스프링 시큐리티 커스텀 로그인 페이지 만들기

charco·2021년 6월 9일
0

출처: 코드로 배우는 스프링 웹 프로젝트


커스텀 로그인 페이지

스프링 시큐리티에서는 기본적인 로그인 페이지를 제공한다.
하지만 로그인 페이지를 예쁘게 꾸미고 싶다면 로그인 페이지를 직접 만들고 시큐리티 설정을 바꿔야 한다.
이전에 작성했던 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 속성을 이용하면 된다.

다음에는 드디어 데이터베이스와 연동해 로그인을 구현해본다.

profile
아직 배우는 중입니다

0개의 댓글