전 포스팅에서 Oauth2의 기본적인 뼈대는 구성을 했습니다. 이제는 권한이 없는 유저가 접근했을 때 403 에러가 아닌 오류가 뜬 페이지를 보여는 것과 Oauth2 인증이 성공했을 때 Redirection 하는 곳을 직접 지정해보겠습니다.

 

1. html 추가

  • denied.html (권한이 없거나 로그인을 하지 않은 유저가 접근했을 때 403에러가 아닌 해당 페이지를 보여줍니다.)
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Denied Page</title>
</head>
<h1> Denied Page </h1>
<div class="container">
    <div th:if="${user}!=null">
        <ul>
            <li>Username = <span th:text="${user.name}"></span></li>
            <li>UserEmail = <span th:text="${user.email}"></span></li>
        </ul>
    </div>

</div>

</body>
</html>

 

  •  redirect.html (Oauth2 인증이 성공 했을 때 "/"가 아닌 Redirect를 새로 지정하는 페이지입니다.)
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <title>redirect Page</title>
</head>
<h1> Redirect Page </h1>


<div class="container">
    <div th:if="${user}!=null">
        <ul>
            <li>Username = <span th:text="${user.name}"></span></li>
            <li>UserEmail = <span th:text="${user.email}"></span></li>
        </ul>
    </div>

</div>

</body>
</html>

 

2. CustomAccessDeniedHandler

@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.sendRedirect("/denied");
    }
}

 

  • 만약 권한이 없을 경우 response.sendRedirect("/denied")로 보내는 것입니다.
  • 여기서 사용자의 편리성을 더 생각한다면 request.getRequestURI()를 받은 뒤 @RequestParam형태로 붙여줍니다. 아래와 같이 작성해줍니다. (현재 만들 Controller는 따로 @RequestParam을 안 받을 예정이므로 위에 형태로 진행합니다.)
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        String requestURI = request.getRequestURI();
        response.sendRedirect("/denied"+"?requestURI="+requestURI);
    }
}

3. SecurityConfig 수정

@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final CustomOauth2UserService customOauth2UserService;
    private final CustomAccessDeniedHandler customAccessDeniedHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/","/denied").permitAll()
                .antMatchers("/user").hasRole(Role.USER.name())
                .antMatchers("/guest","/redirect").authenticated()
                .and()
                .logout()
                .logoutSuccessUrl("/")
                .and()
                .exceptionHandling()
                .accessDeniedHandler(customAccessDeniedHandler) // 권한이 없을 경우 저희가 Custom으로 만든 Handler를 추가합니다.
                .and()
                .oauth2Login()
                .defaultSuccessUrl("/redirect") //Oauth2 인증에 성공했을 경우 저희가 지정한 곳으로 redirect합니다. 
                .userInfoEndpoint()
                .userService(customOauth2UserService);
    }
}

 

4. Postman Test ( OatuhAttributes의 toEntity부분에서 Role 정하는 부분을 테스트를 위해서 Role.GUEST로 변경합니다.)

  • 기존에는 Oauth2 로그인을 했을 때 localhost:8080/으로 redirect 됐지만 현재는 Security 설정으로 인해 localhost:8080/redirect로 된 것을 확인할 수 있습니다.

  • 현재 로그인한 User의 권한은 GUEST이므로 localhost:8080/user에 접근이 불가능합니다. 전에는 springboot 자체의 error 페이지를 받았지만 Securiy 설정을 해줬으므로 localhost:8080/denied로 이동한 것을 볼 수 있습니다.

 

5. SuccessHandler, FailureHandler

예제에서는 추가적인 사항이 없어 다루진 않지만 SuccessHanlder와 FailureHandler는 다 끝난 후 별도의 후 처리가 가능합니다. 예를 들어서 로그인에 성공한 후 별도의 Session이나 토큰을 또 지급한다면 SuccessHanlder에 구현하면 됩니다.
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final CustomOauth2UserService customOauth2UserService;
    private final CustomAccessDeniedHandler customAccessDeniedHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/","/denied").permitAll()
                .antMatchers("/user").hasRole(Role.USER.name())
                .antMatchers("/guest","/redirect").authenticated()
                .and()
                .logout()
                .logoutSuccessUrl("/")
                .and()
                .exceptionHandling()
                .accessDeniedHandler(customAccessDeniedHandler)
                .and()
                .oauth2Login()
                .defaultSuccessUrl("/redirect")
                .userInfoEndpoint()
                .userService(customOauth2UserService)
                .and()
                .successHandler() // AuthenticationSuccessHandler를 상속받아 구현합니다.
                .failureHandler(); //AuthenticationFailureHandler를 상속받아 구현합니다.
    }                              // 둘다 객체를 넣지않아 오류 뜨는게 맞습니다. 사용하지는 않으므로 코드는 주석처리 하겠습니다. 
}

 

Oauth2의 Redirect URL을 직접 지정하는 방법과 접근 권한이 거부될 때 springboot의 자체 오류 페이지가 아닌 저희가 만든 오류 페이지로 이동하는 것을 알아봤습니다. 지금까지 전반적인 Oauth2의 기술을 적용해봤습니다. 다음은 Spring Security의 내부적인 로직들을 사용하여 로그인을 구현해보겠습니다. 감사합니다.

 

모든 코드는 아래 링크에서 확인 가능합니다.

https://github.com/rlaehdals/Oauth2Example

 

GitHub - rlaehdals/Oauth2Example

Contribute to rlaehdals/Oauth2Example development by creating an account on GitHub.

github.com