출처: 코드로 배우는 스프링 웹 프로젝트
스프링 시큐리티에서는 기본적인 로그인 페이지를 제공한다.
하지만 로그인 페이지를 예쁘게 꾸미고 싶다면 로그인 페이지를 직접 만들고 시큐리티 설정을 바꿔야 한다.
이전에 작성했던 security-context.xml 를 다음과 같이 바꾸자.
<security:http>
...생략
<!-- <security:form-login /> -->
<!-- customLogin페이지를 로그인 페이지로 지정한다.
추후에 customLogin을 만들 것이다.-->
<!--login-page 의 uri는 get방식으로 접근하는 uri여야 한다.-->
<security:form-login login-page="/customLogin" />
</security:http>
이전에 만들었던 CommonController에 /customLogin 에 해당하는 메서드를 추가해준다.
@GetMapping("/customLogin")
public void loginInput(String error, String logout, Model model){
if(error != null){
model.addAttribute("error", "로그인 에러: 계정을 확인하십쇼.");
}
if(logout != null){
model.addAttribute("logout", "로그아웃됨");
}
}
이제 이 컨트롤러에서 매핑될 customLogout.jsp 를 만든다. jstl taglib 을 사용하니 없다면 상단에 추가하자.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
다음은 customLogin.jsp 의 body 다
<h1>커스텀 로그인 페이지</h1>
<h2><c:out value="${error}"/></h2>
<h2><c:out value="${logout}"/></h2>
<!-- 시큐리티의 로그인 작업은 /login에서 이루어진다.
/login 에 POST 방식으로 데이터를 보낸다. -->
<form action="/login" method="POST">
<!-- input 태그의 name 속성은 username, password 로 지정해야 한다.
사용자의 id가 이메일이라고 해도 username 으로 지정해야한다.
그래야 스프링 시큐리티에서 처리할 수 있다. -->
<input type="text" name="username" placeholder="username을 입력하세요" />
<input type="password" name="password" />
<input type="submit" />
<!-- csrf 토큰을 생성해 같이 보낸다 -->
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
csrf 토큰이 뭔지 모른다면 이 블로그로 가보자.
이해하기 쉽게 설명돼있다.
이제 애플리케이션을 실행해 로그인이 되는지 확인해보자.
만약 패스워드 등을 잘못 입력한다면 다시 로그인 페이지로 돌아가게 되는 것을 볼 수 있다.
스프링 시큐리티에서는 사용자가 인증에 성공하면 인증 전에 요청했던 페이지로 데려다준다. 하지만 상황에 따라 다양한 작업이 필요 할 수도 있다. 이때 시큐리티에서 제공하는 AuthenticationSuccessHandler 인터페이스를 구현하면 된다. CustomLoginSuccessHandler 클래스를 생성해 구현해보자.
public class CustomLoginSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
List<String> roleNames = new ArrayList<String>();
//Authentication 객체는 인증된 대상의 정보를 담고있다.
//그 객체에서 authority(권한)을 추출해 roleNames 리스트에 담는다.
authentication.getAuthorities().forEach(authority -> {
roleNames.add(authority.getAuthority());
});
//ROLE_ADMIN 이 포함돼있으면 /sample/admin으로 리다이렉트
if(roleNames.contains("ROLE_ADMIN")) {
response.sendRedirect("/sample/admin");
return;
}
//ROLE_MEMBER 이 포함돼있으면 /sample/member으로 리다이렉트
if(roleNames.contains("ROLE_MEMBER")) {
response.sendRedirect("/sample/member");
return;
}
//둘다 없으면 메인 페이지로 리다이렉트
response.sendRedirect("/");
}
}
이제 security-context.xml 에서 이 클래스를 스프링 빈에 등록하자.
<bean id="customAccessDeniedHandler" class="com.green.security.CustomAccessDeniedHandler"></bean>
<!--스프링 빈으로 등록-->
<bean id="customLoginSuccess" class="com.green.security.CustomLoginSuccessHandler"></bean>
<security:http>
<security:intercept-url pattern="/sample/all" access="permitAll"/>
<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')"/>
<security:intercept-url pattern="/sample/admin" access="hasRole('ROLE_ADMIN')"/>
<!-- <security:access-denied-handler error-page="/sample/accessError"/> -->
<security:access-denied-handler ref="customAccessDeniedHandler"/>
<!-- <security:form-login/> -->
<!--위에 등록한 빈을 여기에 주입-->
<security:form-login login-page="/sample/customLogin" authentication-success-handler-ref="customLoginSuccess"/>
</security:http>
이제 애플리케이션을 실행해 커스텀 로그인 페이지로 가서
로그인해보자. member 사용자면 /sample/member, admin 사용자면 /sample/admin 으로 자동으로 리다이렉트될 것이다.
먼저 로그아웃을 했을때 /customLogout으로 이동하도록 설정하자.
<!--invalidate-session 을 true로 지정하면
말그대로 로그아웃 했을때 세션을 무효화 시킨다.-->
<security:logout logout-url="/customLogout" invalidate-session="true"/>
이제 위의 uri에 해당하는 메서드를 컨트롤러에 만들자.
@GetMapping("/customLogout")
public void customLogout() {};
이에 해당하는 customLogout.jsp파일을 만들자.
<h1>Logout Page</h1>
<form action="/customLogout" method="POST">
<!-- csrf 토큰은 POST, PUT, DELETE등의 요청에 주로 사용된다 -->
<input type="hidden" name="${_csrf.parameterNamne}" value="${_csrf.token}">
<button>로그아웃</button>
</form>
로그아웃 시 추가 작업을 해야하면 logoutSuccessHandler를 정의해서 처리하면 된다.
마지막으로 /sample/admin 에 /customLogout 으로 가는 링크를 추가해주자.
<a href="/customLogout">로그아웃</a>
애플리케이션을 실행하고 admin 으로 로그인해보자.
그리고 로그아웃 페이지로 가서 로그아웃 버튼을 눌러보자.
성공적으로 로그아웃됐고 자동으로 /customLogin 페이지로 가는 것을 볼 수 있다(스프링 시큐리티 내부에서 자동으로 해줌). 로그인 페이지에서는 logout 메시지를 보여준다.
만약 로그아웃 시에 로그인페이지가 아닌 메인페이지나 다른 페이지를 보여주고 싶다면 logout-success-utl 속성을 이용하면 된다.
다음에는 드디어 데이터베이스와 연동해 로그인을 구현해본다.