본문으로 바로가기


1. 라이브러리 추가

Spring Security는 Spring 버전에 의존도가 있기 때문에, 의존성(dependency) 관련 버전을 반드시 확인하고 사용해야 한다. 무조건 내가 쓴 버전을 사용해야 한다는 것이 아니다. 의존성에 맞는 버전을 사용하면 된다. 버전을 찾고 싶으면 여기를 참고하면 된다. 자신이 쓸 스프링 시큐리티의 버전에 들어간 후, Compile Dependencies 에서 스프링 버전을 확인하여 사용하면 된다.


스프링 4.3.2 버전에 스프링 시큐리티 4.1.3 버전을 사용한다.


pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    <properties>
        <java-version>1.8</java-version>
        <org.springframework-version>4.3.2.RELEASE</org.springframework-version>
        <org.aspectj-version>1.8.4</org.aspectj-version>
        <org.slf4j-version>1.6.6</org.slf4j-version>
        <spring.security.version>4.1.3.RELEASE</spring.security.version>
    </properties>
 
    <!-- Spring Security -->
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-core</artifactId>
        <version>${spring.security.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>${spring.security.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>${spring.security.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-taglibs</artifactId>
        <version>${spring.security.version}</version>
    </dependency>
    <!--  -->
cs



2. Spring Security Filter 추가

spring security를 적용하기 위한 필터를 추가한다. 웬만하면 그대로 붙여넣자. 오타가 나면 곤란하다. 필터 이름을 임의로 변경해서는 안되기 때문이다. 스프링 시큐리티 내에서 클래스를 찾기 위해 지정한 이름이여서 변경하거나 오타가 발생하면 안된다. 그리고 url 에서도 확장자가 붙는 스타일이 아니 때문에 마음대로 변경해서는 안된다.


web.xml

1
2
3
4
5
6
7
8
9
10
11
    <!-- Spring Security Filter -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
 
    <filter-mapping>
          <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--  -->
cs

- 03행: 필터의 이름은 반드시 springSecurityFilterChain 이여야 한다.

- 09행: 해당 필터가 적용될 URL 패턴을 모든 패턴을 의미하는 /*를 반드시 써야한다. 주소 호출할때 쓰던 *.do 등으로 쓰면 안된다.



3. Spring Security 설정 파일

Spring security의 설정을 위한 파일을 생성하자. 기본적으로 namespace를 "beans"로 사용할 것이다. 하지만 나는 "security"를 기본 namespace로 사용할 것이다. 아무거나 사용해도 무방하다. security를 기본 namespace로 사용하는 이유는 security 요소를 사용할 때 접두사 security를 생략하여 읽기 쉽게 하기 위함이다.


context-security.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/security
         http://www.springframework.org/schema/security/spring-security.xsd">
        
        <http auto-config="true" use-expressions="false">
            <intercept-url pattern="/**" access="ROLE_USER" />
        </http>
        
        <authentication-manager>
            <authentication-provider>
                <user-service>
                    <user name="user" password="userPw" authorities="ROLE_USER"/>
                    <user name="guest" password="guest" authorities="ROLE_GUEST"/>
                </user-service>
            </authentication-provider>
        </authentication-manager>
    
</beans:beans>
cs

- 02행: 기본 namespace를 security로 설정했다.

- 10행: auto-config 속성은 자동 설정을 뜻하고 use-expressions 속성은 intercept-url에 SpEL문법의 사용유무를 선택한다.

- 11행: 모든 URL을 접속(/**)하기 위해선 ROLE_USER 권한이 필요하다는 뜻이다. index 페이지 및 모든 페이지에 들어갈 수 있는 사람은 로그인을 한, 즉 권한을 가진(ROLE_USER) 사람만 들어 올 수 있다는 뜻이다. 나중에 되면 이곳에서 페이지의 경로(/admin/**, /user/**, ...)에 원하는 대로 권한 설정을 할 수 있다. 이것과 관련된 내용은 커스텀을 하면서 더 자세히 알게 될 것이다.

- 14행: 인증과 관련된 정보를 설정하는 태그이다.

- 15행: 인증에 대한 정보를 제공하는 제공자를 지정하는 태그이다.

- 16~20행: 사용자 정보를 설정하는 태그이다. 사용자 이름(ID), 권한, 비밀번호를 지정할 수 있다.



4. 설정 파일 등록

context-security.xml을 만들었으니, web.xml에 경로를 등록하자.

두가지 경우가 있다. 나는 프로젝트를 만들기 전에 구조를 변경했었다. 각자 맞는 경로를 등록하면 된다.


예1) web.xml

1
2
3
4
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring/context-*.xml</param-value>
    </context-param>
cs

2


예2) web.xml

1
2
3
4
5
6
7
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/context-root.xml
            /WEB-INF/spring/context-security.xml
        </param-value>
    </context-param>
cs



4. 서버실행

서버를 실행하자. 근데 여기서 로그인 페이지를 안만들고 그냥 실행하는지 의문이 생길 수 있다. spring security에서 기본으로 제공하는 로그인 페이지를 사용할 것이다. 그렇기에 따로 페이지를 만들 지 않았다. 여기는 기초중의 완전 기초 설정만 설명하기 위해서다. 나중에 되면 로그인 페이지를 예쁘게 꾸미고, 거기에 맞춰서 시큐리티 설정을 다 만들어야 한다.


서버를 실행하면 만든 적도 없는 로그인 페이지가 뜰 것이다. 심지어 경로까지 정해져 있다(/login). 이게 바로 spring security에서 제공하는 기본 로그인 페이지이다. 그리고 index 페이지가 뜨지 않고 바로 로그인 페이지가 뜨는 이유는, context-security에서 모든 URL(/**)에 접속하기 위해선 권한이 ROLE_USER이여야 한다고 정했다. 그래서 권한을 알 수 없는(로그인하지 않은) 사용자에겐 로그인 하라는 로그인 페이지가 뜨는 것이다.


그럼 이제 로그인을 해보자. 사용자 등록 또한 context-security에서 했다. 먼저 접근 권한이 없는 ROLE_GUEST 부터 로그인 해보자.


403 에러 페이지가 떴다. 403 에러 페이지가 뜨는 게 정상이다. Access is denied. 접근이 불가하다. 접근 권한이 없다는 뜻이다. 우리는 ROLE_USER 권한을 가진 사용자만 접근할 수 있게 해놨기 때문이다. 그럼 이제 ROLE_USER 권한을 가진 user로 로그인 하자.



index 페이지가 나왔다. 로그인에 성공하였고, 해당 계정은 페이지에 접근할 권한이 있다는 뜻이다. 그럼 만약 비밀번호가 틀리거나, 없는 아이디를 사용하면 어떻게 될까? ROLE_GUEST 처럼 에러 페이지가 뜨는 걸까? 아니면 흔히 볼 수 있는 "비밀번호가 틀렸습니다."와 같은 메세지를 보여주는 걸까? 한번 해보자. 



다른 페이지로 넘어가지 않고 인증 실패를 확인할 수 있는 에러 메시지가 나왔다. 주소창에도 에러를 알려준다.


여기까지가 정말 기본 중의 기본, 완전 기초인 spring security 설정이다. 와, 쉽네! 이거 그대로 쓰면 되겠네! 라고 생각했다면 주먹을 쥐고 자신의 머리를 때려라. 당연히 커스텀해야 한다. 이렇게 볼품없는(?) 페이지와 울렁거리게 만드는 영어 에러 문구, 뭔가 잘 못 한 것만 같은 접근 불가 403 페이지까지... 전부 다 커스텀해야 한다. 이걸 그대로 프로젝트에 쓴다면 차라리 안쓰는 게 낫다. 쓸모없다. 복잡하고 어려워 보여도 스프링 시큐리티의 꽃은 커스텀이라고 생각한다. 


spring security를 차근 차근 잘 정리할 수 있기를 빌며!


GitHub


댓글을 달아 주세요

  1. 짱짱맨 2019.03.09 20:35

    안녕하세요, 쉽고 자세한글 많은 도움이 되고 있어요.
    잘 안되는 부분이 있어서 도움 부탁드립니다.

    관리자 페이지가 있어서요. 그 부분처리를 하고 싶은데요.

    예를 들어서 /admin/config/** 직접 찍고 들어 오면 현재는 관리자 로그인페이지로 이동을 하는데
    저는 403페이지 보여주고 끝내고 싶어요. 어떻게 하면 좋을 까요? (아래는 봐주시는데 도움이 될까해서 (context-security.xml ) 같이 올려요~

    <security:http auto-config="true" use-expressions="true">
    <!-- spring 4.x때 추가된 옵션으로 ssl을 사용하지 않을 경우 csrf는 disalbed true로 해준다. -->
    <security:csrf disabled="true" />
    <security:intercept-url pattern="/admin/coins/**" access="hasAnyRole('ROLE_MEMBER', 'ROLE_ADMIN')" />
    <security:intercept-url pattern="/admin/config/**" access="hasAnyRole('ROLE_MEMBER', 'ROLE_ADMIN')" />
    <security:intercept-url pattern="/admin/masternodes/**" access="hasAnyRole('ROLE_MEMBER', 'ROLE_ADMIN')" />
    <security:intercept-url pattern="/admin/nodeservers/**" access="hasAnyRole('ROLE_MEMBER', 'ROLE_ADMIN')" />
    <!-- admin root는 접근 가능하다.(admin loginpage지 밎 403(access denied page)를 보여 줘야 함으로.) -->
    <!-- <security:intercept-url pattern="/**" access="permitAll"/> -->

    <!-- 권한 설정 -->

    <security:form-login
    username-parameter="login_id"
    password-parameter="login_pwd"
    login-processing-url="/login"
    login-page="/admin/login_page"
    default-target-url="/admin/config/list"
    ></security:form-login>


    <security:access-denied-handler error-page="/access_denied_page"></security:access-denied-handler>
    <security:logout
    logout-url="/logout"
    logout-success-url="/admin/login_page"
    />

    </security:http>

    • BlogIcon #에게 2019.03.09 21:09 신고

      음.. 403페이지는 인증된 사용자가 권한이 없는 페이지에 접근할때 가는 건데, 원하시는 건 인증하지 않은 사용자가 권한이 없는 페이지에 접근하면 403 페이지로 가고 싶으신거죠?

      그건 조금 고민을 해봐야 할 거 같아요.. 제가 공부한거로는 security 설정으로는 못할거 같구요.. 음.. 인터셉터를 이용하거나, 로그인 페이지로 가는 컨트롤러에서 이전 페이지 정보를 가지고 로그인 페이지로 보내거나 403 페이지로 보내게 설정해도 되지 않을까요??

      음음.. 전혀 생각해보지않은 부분이라...음... 제가 생각한 방법이 조금이나마 도움이 되었으면 좋겠네요ㅠㅠ

    • 짱짱맨 2019.03.10 02:50

      답변 감사합니다~

      도움 많이 됬습니다. 인터셉트도 한번 생각을 해볼게요~^v^

  2. 코머 2019.04.26 09:34

    안녕하세요 좋은글 덕에 많은도움되었습니다.
    위 과정대로 따라해보던중
    No bean named 'springSecurityFilterChain' is defined
    라는 에러가 나오는데 무엇이 문제인지 잘 모르겠습니다 ㅜㅜ

  3. 아메리카노 2019.12.05 15:21

    안녕하세요. spring security 공부하려고 찾아보다가 너무 꼼꼼히 잘 설명해주셔서 덕분에 많이 알아갑니다! github fork도 했어요~! 프로젝트 참고할게요! 감사합니다!

  4. ㄷㄷ 2019.12.17 18:19

    혹시 소스는 못보나요?

  5. 익명 2020.02.07 09:58

    비밀댓글입니다

  6. 뿌뿌 2020.12.14 09:28

    깔끔하게 정리된 글 잘 보고 갑니다!
    감사합니다