본문 바로가기
프로그래밍/스프링프레임워크

스프링프레임웍 - Spring Security(3) : 사용자/권한 정보 DB사용하기

by pentode 2018. 4. 9.
반응형

앞서 "스프링프레임웍 - Spring Security(2) : 커스텀 로그인 화면 및 권한에 따른 접근 제어"에서 로그인 화면을 원하는 형태로 만드는 방법에 대해서 알아 보았습니다.

 

지금까지의 기본설정과 화면 커스터마이징에서는 사용자 정보와 권한 정보가 모두 security-context.xml 파일 안에 있었습니다. 이번에는 이 정보들을 DB 저장하고 이용할 수 있도록 해 보겠습니다. 데이터베이스는 Oracle을 사용합니다.

 

먼저 사용자 정보와 권한정보를 저장할 테이블 구조 입니다. 이 테이블들은 스프링 시큐리티의 DB 지원 기본 구조를 키구조만 조금 바꾼것 입니다.

 

스프링시큐리티 테이블 구조

 

 

1. 사용자/권한 테이블

 

사용자 권한 처리를 위해서 총 5개의 테이블로 구성됩니다. 테이블을 생성하고 기본 데이터를 입력하는 쿼리파일은 글 하단 전체소스내의 doc폴더에 sample.sql 파일에 있습니다. 각각의 테이블에 대해 알아 보도록 하겠습니다.

 

i. users - 회원 정보 테이블

 

- username이 아이디입니다. 여기에서는 비밀번호가 암호화 되지 않았습니다.

- enabled는 boolean 값으로 계정 사용여부를 나타냅니다.

 

ii. authorities - 회원, 권한 관계 테이블

 

- 회원(username)이 가지는 권한정보가 있는 테이블 입니다.

- authority"ROLE_USER", "ROLE_ADMIN" 이 될 것입니다.

 

iii. gropus - 그룹 테이블 입니다.

 

- 그룹에 권한을 할당하고, 사용자에게 그룹을 할당하는 방식으로 권한을 부여할 수 있습니다.

 

iv. group_authorities - 그룹이 가지는 권한 정보 테이블

 

- groupu_idgroups테이블의 id와 관계되는 외래키 입니다.

- authority"ROLE_USER", "ROLE_ADMIN" 이 될 것입니다.

 

v. group_member - 그룹과 회원의 관계 테이블

 

- group_id groups 테이블의 id 입니다.

- username 은 회원 아이디 입니다.

 

 

2. 권한 부여방식

 

위의 테이블들을 가지고 회원에게 권한을 부여하는 방법은 두 가지가 있습니다.

 

첫 번째는 usersauthorities 테이블을 사용하여 권한을 부여 하는 것입니다. users테이블의 정보로 로그인하고, authorities 의 권한정보를 접근 제어를 합니다.

 

두 번째 방법은 users(group_members, groups, group_authorities) 로 처리하는 방법입니다. 역시 users 정보로 로그인하고, 권한은 회원이 속한 그룹에 할당된 권한으로  접근제어를 하는 것입니다.

 

스프링 시큐리티는 먼저 authorities 테이블에서 권한을 확인하고, 다음에 group_members 테이블에서 권한을 확인합니다. 그러므로 두 가지 방법중 하나만 사용하면 됩니다. 즉,  authorities 테이블에 정보가 없어도 group_members 테이블에 정보가 있으면 권한이 부여됩니다. 그 반대로 마찬가지 입니다.

 

 

3. security-context.xml 설정파일을 보겠습니다.

 

회원 정보와 권한 정보를 데이터베이스에서 가져오도록 설정하는 부분입니다.

 

<!--
<beans:bean id="userDetailsService"
            class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
	<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
-->

<!--  provider  -->
<authentication-manager>
    <authentication-provider>
        <jdbc-user-service
            data-source-ref="dataSource"
            role-prefix=""
            users-by-username-query="select username, password, enabled from users where username = ?"
            authorities-by-username-query="select username, authority from authorities where username = ?"
            group-authorities-by-username-query="select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id"
        />
    </authentication-provider>
</authentication-manager>

 

인증 정보를 가져오는 기능을 하는 인터페이스가 org.springframework.security.core.userdetails.UserDetailsService 입니다. 데이터베이스에서 정보를 가져오도록 이 인터페이스를 구현해둔 클래스가 org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl 입니다. 위 코드의 id"userDetailsService"인 빈이 이것 입니다. 이 빈에 대한 정의는 넣지 않아도 됩니다.

 

이 빈은 <jdbc-user-service> 요소로 사용되어 집니다. 각 속성들을 알아보겠습니다.

 

- data-source-ref="dataSource" : 데이터베이스 연결을 나타내는 dataSource 입니다. root-contxt.xml 파일에 정의 되어 있습니다.

- role-prefix : "ROLE_" 와 같은 롤 앞에 붙는 prefix 를 지정합니다. 권한 체크시 여기에 지정된 값을 붙여서 확인합니다. 데이터베이스에 ROLE_USER 형식으로 데이터를 넣어 둿으므로 여기서는 값을 주지 않았습니다.

- users-by-sername-query="" : 아이디로 사용자 정보를 가져오는 쿼리 입니다. users 테이블에서 정보를 가져옵니다.

- authorities-by-username-query="" : authorities 테이블로부터 권한정보를 가져옵니다.

- group-authorities-by-username-query="" : 그룹/회원 관계로부터 권한정보를 가져옵니다.

 

 

이것으로 해서 회원/권한 정보를 데이터베이스로부터 가져오는 처리를 해보았습니다. 하지만 아직 한가지가 처리되지 않을 것이 있습니 다. URL별로 권한을 지정하는 부분이 아직도 xml 파일에 남아 있습니다. 다음 코드 입니다.

 

<intercept-url pattern="/login/loginForm.do" access="permitAll" />
<intercept-url pattern="/home.do" access="permitAll" />
<intercept-url pattern="/admin/**" access="hasRole('ADMIN')" />
<intercept-url pattern="/**" access="hasAnyRole('USER, ADMIN')" />

 

다음글에서는 이 정보도 데이터베이스로 부터 가져오도록 하는 방법에 대해서 알아보도록 하겠습니다.

 

 

4. 실행결과

- 최초 실행화면으로 홈 화면 입니다. 로그인 되어있지 않으므로 로그인 링크가 있습니다.

 

홈화면

 

- 로그인 화면입니다. 일반계정인 user/1 로 로그인 합니다.

 

로그인 화면

 

- 로그인후 홈화면으로 이동합니다. 로그인 되어 있으므로 로그아웃 버튼이 있습니다.

 

로그인된 홈 화면

 

- 소개페이지 링크를 눌러 들어가 보았습니다. 로그인되어 있으므로 페이지가 보입니다. 로그인 되어 있지 않다면 로그인 페이지로 갈 것입니다.

 

일반 사용자 권한 소개 페이지

 

- 일반계정으로 로그인 한 상태에서 관리자 홈 링크를 클릭하면 Access Denied 메세지가 보입니다.

 

일반 권한으로 관리자 페이지 접근

 

- 관리자 아이디 (admin/1) 로 로그인 후 관리자 홈 링크를 클릭하면 관리자페이지로 들어가 입니다.

 

관리자 페이지

 

 

※ 전체소스

spring_security(3).zip
다운로드

 

반응형

댓글13

  • 궁금 2018.05.31 15:29

    안녕하세요 글을 읽으면서 따라가고 있는 사람입니다.

    좋은글 아주 잘 읽고 있습니다. 감사합니다.

    글을 읽다가 좀 궁금한게 생겨서 이렇게 댓글을 남깁니다.

    제가 프로젝트를 내려받아서 작업을 하고 있는데... 로그인 처리를 따로 해준적이 없는거 같은데 로그인이 되는게 맞는건가요??

    테이블도 만들었고 아이디 : user 비밀번호 : 1을 입력하면

    아이디와 비밀번호가 잘못됐다고 나오고 있는 상황입니다. 어떻게 해야할지 몰라서 이렇게 댓글을 남깁니다.

    확인 하시고 방안에 대해서 알려주시면 감사하겠습니다.
    답글

    • pentode 2018.05.31 20:27 신고

      안녕하세요. 첨부된 소스를 다운로드 받아서 실행해본 결과 정상적으로 동작하는 것을 확인했습니다.

      실행했을 경우 화면은 본문 아래에 추가 했습니다. 참고하시기 바랍니다.

  • 익명 2018.07.11 11:06

    비밀댓글입니다
    답글

    • pentode 2018.07.12 00:24 신고

      방문해 주셔서 감사합니다. intercept-url을 DB에서 가져오도록 수정하는 것은 언제 진행할지 미정 입니다. 지금 좀 바쁘기도 하거니와 자료를 좀 찾아보니 너무 복잡하게 될 것 같아서 망설이고 있습니다.
      전자정부표준프레임워크에서 intercept-url을 DB화 해서 사용하고 있습니다. 오픈소스 프로젝트이므로 그쪽 소스를 참고해 봐도 좋을 것입니다.

  • hp1830 2018.08.28 16:02

    정성글 너무 감사합니다.ㅜㅜ

    바보도 쉽게 이해할 수 있는 글 너무 좋아요!

    저도 스프링 시큐리티를 배울려고 했지만

    어려운거 같아 포기를 한적이 있었거든요.ㅜㅜ

    하지만 이 블로그 글을 다시 읽어보니 생각보다 쉽네요!


    답글

    • pentode 2018.08.28 20:43 신고

      스프링 시큐리티 좀 복잡한 감이 있는것 같습니다. 그래서인지 이론적인 문서는 많이 있는데, 쉽게 응용용할 수 있는 코드들은 잘 없는 것 같습니다. 도움이 되셨다면 다행입니다.^^

  • jyw 2019.04.07 15:01

    안녕하세요. 덕분에 시큐리티에 대한 기초적인 개념을 쉽게 접할 수 있었습니다!
    이 코드들을 제가 만든 DB정보와 연동 시키려면 root-context와 security-context의 정보들만 바꿔주면 되는건가요?
    만약 그렇다면 어느 부분들을 건드려야되는지 알려주시면 정말 감사하겠습니다!
    답글

    • pentode 2019.04.07 21:52 신고

      사용자 테이블이 members이고 id, pwd 가 있다면 security-context.xml 파일내의 쿼리를 select id as username, pwd as password, 1 as enabled from members where id=? 처럼 사용하면 될것 같습니다.

  • 나그네 2019.10.19 14:53

    글 잘 보았습니다.

    security-context.xml은 전자정부 프레임워크의 dispatch-servelet이 존재하는 디렉토리에 넣으면 되는지요?

    실제로 테스트해보니 이쪽에서 에러가 나네요~
    ALTER TABLE group_authorities ADD CONSTRAINT IDX_group_authorities_FK0 FOREIGN KEY (group_id) REFERENCES groups (id);
    에러
    ALTER TABLE group_members ADD CONSTRAINT IDX_group_members_FK0 FOREIGN KEY (username) REFERENCES users (username);
    ALTER TABLE group_members ADD CONSTRAINT IDX_group_members_FK1 FOREIGN KEY (group_id) REFERENCES groups (id);

    에러 내용은 이렇습니다...

    ORA-02270: no matching unique or primary key for this column-list
    02270. 00000 - "no matching unique or primary key for this column-list"
    *Cause: A REFERENCES clause in a CREATE/ALTER TABLE statement
    gives a column-list for which there is no matching unique or primary
    key constraint in the referenced table.
    *Action: Find the correct column names using the ALL_CONS_COLUMNS
    catalog view

    답글

    • pentode 2019.10.19 16:18 신고

      이 예제에서는 security-context.xml 파일은 /WEB-INF/spring/ 폴더에 있습니다. 예제 소스를 다운로드 해서 확인해 보세요. 스프링 프레임워크의 설정 파일의 위치는 web.xml 파일에서 지정합니다. 필요하면 원하는 다른 위치로 변경할 수 도 있습니다.

      에러가 발생한 것은 테이블 생성시 Foreign key 생성에서 발생한 것이군요. group, members, authorities 테이블이 생성되고 primary key가 제대로 설정되었는지를 먼저 확인하면 될 것 같습니다.

  • 열공이 2020.07.15 09:29

    정마류ㅠㅠㅠ 너무 설명이 잘되어있어요 너무 좋아요 어떻게 이렇게 정리를 잘하시는 건가요.ㅠㅠㅠ
    공감 오천번 누르고싶은 마음을 담아 공감을 누르고 갑니다.
    답글

  • 우리형 2022.06.30 15:03

    관리자의 승인을 기다리고 있는 댓글입니다
    답글