본문으로 바로가기

지금까지 만들어 놓은 것은 로그인만 가능하다. 그래서 다른 아이디로 로그인하려면 뒤로가기를 눌러서 로그인 페이지로 돌아가서 새로운 로그인을 해야했다. (나만 그런거면 눈물) 그래서 일단 로그아웃을 간단하게 만들고 나서 인증 절차를 커스터마이징하자. 그리고 로그아웃 버튼과 함께 화면에 인증된 사용자의 정보를 보여줄 것이다. 예를 들면 '김연아님, 환영합니다.' 이런 문구 정도? 그럼 로그아웃부터 설정해보자.


1. Security 설정 (logout)

context-security.xml

1
2
3
4
5
6
<http>
     <logout
        logout-url="/logout"
        logout-success-url="/"
    />
</http>
cs

- 03행: 기본을 사용하려면 생략해도 된다.

- 04행: 기본을 사용하면 로그아웃 성공시 로그인 페이지로 간다. 나는 메인페이지로 보내기 위해 설정한다.


 표현식

설명 

 logout-url

 로그아웃 처리에 대한 URL. form태그의 action 속성에 지정한 값. (default: POST /logout)

 logout-success-url

 로그아웃 성공시, 이동할 URL. (default: /login?logout)

 invalidate-session

 로그아웃 시, session을 무효화할 지 선택. (default: true)

 delete-cookies

 로그아웃 성공시, 삭제할 쿠키 이름 지정

 success-handler-ref

 로그아웃 성공시, logout-success-url 이 아닌 핸들러로 리다이렉트


참고로 JSESSIONID 쿠키를 명시적으로 삭제하지 않아도 된다. JSESSIONID 쿠키는 Spring Security가 관리하는 것이 아니라, 서블릿 컨테이너에 의해 관리된다고 한다. 따라서 로그아웃을 하면 시큐리티에서 기본적으로 http 세션을 무효화하게 되면, 서블릿 컨테이너가 JSESSIONID 쿠키를 제거하게 된다. 따라서 쿠키에 의해 기억할 것이 있으냐 없느냐에 따라 설정하면 된다. 지금은 설정하지 않았지만 나중에 remember-me 기능을 사용할 때는 쿠키를 삭제해야 할 것이다.



2. 로그아웃 버튼

index.jsp

1
2
3
4
5
6
<sec:authorize access="isAuthenticated()">
    <form action="/logout" method="POST">
        <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
        <button type="submit">LOGOUT</button>
    </form>
</sec:authorize>
cs

- 01행: 인증된 이용자일때 해당 버튼(로그아웃)을 보여주려고 한다.

- 02행: security 설정에서 설정한 logout-url을 form 태그의 action 속성에 설정해야 한다.


+) 01.25

css 때문에 form 태그가 아닌 a 태그를 사용해야 하는 경우가 있다. 하지만 logout은 POST 형식으로 넘어가야 하기 때문에 무조건 form 태그의 형식이여야 한다. 근데 다른 프로젝트에 security를 설정하면서 꼭 a 태그만을 사용해야 하는 경우가 생겼다. (ㅠㅠ) 그래서 이리 저리 찾아보다가 좋은 방법을 발견했다.


1
2
3
4
<a href="#" onclick="document.getElementById('logout-form').submit();">Sign out</a>
<form id="logout-form" action='<c:url value='/accounts/logout'/>' method="POST">
   <input name="${_csrf.parameterName}" type="hidden" value="${_csrf.token}"/>
</form>
cs


짠! 이렇게 사용하면 된다. a 태그를 클릭하면 form 태그의 submit 을 해주는 방법이다. 유레카!



3. 실행


로그인을 하게 되면 위와 같이 로그아웃 버튼이 보일 것이다. 로그아웃 버튼을 누르면 로그아웃이 되어 설정한 url로 이동할 것이다. 나는 메인페이지로 가게 했기 때문에 메인 페이지가 보일 것이다. 기본 설정으로 해두었다면 로그인 페이지가 보일 것이다. 




사용자 정보를 화면에 가져오는 방법에는 여러가지가 있다. bean이나 controller에서 가져오거나 annotation을 이용하는 등등 찾아보면 다양한 방법들이 있다. 그 중에서 나는 SpringContextHolder를 이용해서 spring security 자체적으로 제공하는 방법을 사용할 것이다. 아직 이 부분에 대해선 나도 완벽하게 아는 게 아니라서 사랑이 고픈 프로그래머 블로그의 글을 참고한다.


1. SpringContextHolder

index.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<%@ page import="org.springframework.security.core.context.SecurityContextHolder" %>
<%@ page import="org.springframework.security.core.Authentication" %>
<%
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    Object principal = auth.getPrincipal();
 
    String name = "";
    if(principal != null) {
        name = auth.getName();
    }
%>
...
<sec:authorize access="isAuthenticated()">
    <h5><%=name %>님, 반갑습니다.</h5>
    <form action="/logout" method="POST">
        ...
    </form>
</sec:authorize>
cs


spring security 에서 자체적으로 제공하는 방법에 05, 06행의 형식이 주어진다고 한다. 그리고 이들을 사용하기 위해서는 02행, 03행 태그를 선언해야 한다. auth.getPrincipal() 함수를 통해 사용자의 정보를 가져오는데, 해당 함수에서 return 되는 객체는 2가지이다. 


- 인증하지 않은 상태 : anonymousUser란 문자열이 있는 String 객체 return

- 인증에 성공한 상태 : 로그인한 사용자의 정보가 담긴 Object 객체 return


auth.getPrinicipal() 함수는 Object 객체가 return 되기 때문에 String 이나 Object 객체 모두 받아진다. 지금은 security 설정에 있는 user에 사용자의 정보를 담아서 사용한다. 만약 커스터마이징을 하여 사용자 정보를 담겨있는 클래스를 만들게 된다면, 그 클래스의 객체가 return 될 것이다


객체를 가져왔다면 사용자의 정보가 담긴 principal 이 null 이 아닌 지 확인 한 후, null이 아니면 principal 객체를 캐스팅해서 필요한 정보만 가져오면 된다. 화면에 이름만 보여주면 되기 때문에 10행에서 보는 것과 같이 name이라는 String 변수에 객체에 담긴 이름(getName())을 가져왔다.


이렇게 이름을 가져왔다면 화면에는 어떤식으로 보여줘야할까? 15행을 보면, <%= %> 태그를 이용한 것이 보인다. name 변수에 사용자의 정보(이름)을 넣어주었기에 name을 그대로 사용하면 된다. 나는 인증에 성공(로그인 성공)했을 때만 이름(이용자의 정보)이 보이도록 해주었다.



2. 실행


로그인을 하게 되면 로그인한(인증을 한) 이용자의 정보가 화면에 보일 것이다. 여기까지 따라왔다면 어느 정도 구색은 갖춰졌다. 보통의 사이트들처럼 로그인, 로그아웃, 그리고 사용자의 정보보기까지 된다!



+) 01.22

간단하고 좋은 방법을 발견했다. 유레카! security 태그를 이용한 방법이다. security 태그를 권한을 확인할 때(<sec:authorize>) 사용했었다. 로그아웃, 로그인 버튼 만들때 인증을 한 사용자는 로그아웃 버튼이 보이게, 인증하지 않은 사용자는 로그인 버튼이 보이게 만든적이 있다. 이렇게 권한을 확인하는 태그 외에도 사용자 정보를 가져오는 태그도 존재한다. 그래서 위의 방법 대신에 security 태그를 이용해서 사용자 정보를 가져와보도록 하자.


1
2
3
4
5
6
7
<sec:authorize access="isAnonymous()">
   <a href="#">로그인</a>
</sec:authorize>
<sec:authorize access="isAuthenticated()">
   <a href="#">로그아웃</a>
   <p><sec:authentication property="principal.username"/>님, 반갑습니다.</p>
</sec:authorize>
cs


06행을 보면 <sec:authentication> 태그를 사용한 것이 보인다. 해당 태그를 이용해 사용자의 정보를 가져올 수 있다. 여기서 주의할 점은 반드시 인증이 되었을 때만 해당 태그를 사용해야 한다. 따라서 04행의 태그가 꼭 필요하다. UserDetails 인터페이스를 구현한 클래스에 저장된 정보들을 다 가져올 수 있다. 만약 이메일을 가져오고 싶다면 "principal.email" 이렇게 사용하면 된다.



GitHub