SSO 처리를 위해 AbstractAuthenticationProcessingFilter를 사용하여 사전에 사용자 정보를 가져와 로그인 처리를 하려 하는데 분명 로그인을 했는데 자꾸 AnonymousUser라고 로그인 안 된거 처럼 되는 현상으로 하루 죙일 구글링 시작...
찾은 결과
SecurityContext는 인증 성공후에 기본적으로 저장하지 않는다.
UsernamePasswordAuthenticationFilter는 form-login 기반으로 SSO 처리시에는 호출 되지 않기 때문에
SessionManagementFilter에 인증정보를 감지할 수 없다.
그렇기 때문에 인증 성공후에 인정된 객체를 SecurityContext에 저장해야 한다.
SecurityContext에 저장하기 위하여는 AbstractAuthenticationProcessingFilter의 successfulAuthentication를 재정의하여야 한다.
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authResult);
//SecurityContextHolder.setContext(context);
HttpSessionSecurityContextRepository secRepo = new HttpSessionSecurityContextRepository();
secRepo.saveContext(context, request, response);
super.successfulAuthentication(request, response, chain, authResult);
}
이걸 찾는데 너무 오랜 시간을 사용했다...ㅜㅜ
SecurityConfig에서 해당 부분만 발췌한 내용은 아래와 같다.
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig {
...
@Autowired
private UrlBasedAuthorizationManager urlBasedAuthorizationManager;
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf((csrf) ->
csrf.disable()
)
.authorizeHttpRequests(
(requests) ->
requests
.requestMatchers("/", "/loginionvalid.html").permitAll()
.anyRequest().authenticated()
)
.formLogin((form) ->
form
.loginPage("/login.html")
.usernameParameter("userId")
.passwordParameter("pass")
.loginProcessingUrl("/login/proc.html")
.defaultSuccessUrl("/")
.successHandler(customAuthenticationSuccessHandler)
.failureHandler(customAuthenticationFailureHandler)
.permitAll()
)
.logout((logout) ->
logout
.logoutUrl("/logout.html")
//.logoutSuccessHandler(null)
.logoutSuccessUrl("/")
.permitAll()
)
.addFilterBefore(requestProcessingFilter(http), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(urlBaseAuthorizationFilter(), AuthorizationFilter.class)
;
return http.build();
}
/**
* SSO 처리를 위한 처리
* @param http
* @return
* @throws Exception
*/
@Bean
public RequestProcessingFilter requestProcessingFilter(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManagerBuilder.class).build();
RequestProcessingFilter rpf = new RequestProcessingFilter("/ssoLogin.html");
rpf.setAuthenticationManager(authenticationManager);
rpf.setAuthenticationFailureHandler(ssoAuthenticationFailureHandler);
rpf.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
return rpf;
}
...
}
RequestProcessingFilter.java
public class RequestProcessingFilter extends AbstractAuthenticationProcessingFilter {
private String usernameParameter = "userInfo";
public RequestProcessingFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
String requestInfo = obtainUsername(request);
if( !StringUtils.hasText(requestInfo) ) {
logger.error("사용자 정보 연계시 사용자 정보 미전송");
throw new BadCredentialsException("사용자 정보가 올바르게 전송되지 않았습니다. 관리자에게 문의하여 주시기 바랍니다.");
}
...
String userNo = ...;
UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(userNo,
"user1");
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
public String obtainUsername(HttpServletRequest request){
return request.getParameter(usernameParameter);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authResult);
//SecurityContextHolder.setContext(context);
HttpSessionSecurityContextRepository secRepo = new HttpSessionSecurityContextRepository();
secRepo.saveContext(context, request, response);
super.successfulAuthentication(request, response, chain, authResult);
}
}
'JAVA > Spring Security' 카테고리의 다른 글
[Spring Security] JSP 파일에서 Custom Tag를 이용한 권한 체크 (0) | 2018.04.25 |
---|