FormLogin 인증 과정에서 유저가 넘겨주는 부가적인 파라미터 정보를 저장하는 객체가 WebAuthenticationDetails,
WebAuthenticationDetails 를 생성하는 객체가 AuthenticationDetailsSource 이다.
- 사용자의 인증요청
- AuthenticationFilter 작동
- 사용자의 username, password 외 추가적 정보를 보내는 경우 추가적 정보를 저장하고 참조하여 사용할 수 있게 하는 클래스가 WebAuthenticationDetails
- AuntheticationDetailsSource가 WebAuthenticationDetails 클래스를 생성한다.
동작과정
- AuthenticationFilter가 Authentication객체 생성
- Authentication 객체는 내부적으로 Object 타입의 Details 속성을 가짐
- WebAuthenticationDetails 는 사용자가 전달한 request객체를 받아 파라미터 값을 꺼내 저장함
- WebAuthenticationDetails 는 AuthenticationDetailsSource가 생성함
인증시 추가적 정보를 저장하기위해 AuthenticationDetailsSource 와WebAuthenticationDetails 를 구현하여 사용해보자.
- WebAuthenticationDetails 를 상속한 클래스를 만든다.
- 필요한 값을 필드로 선언
- 생성자에서 request를 받아 파라미터값으로 받아와 저장한다.
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import javax.servlet.http.HttpServletRequest;
public class FormWebAuthenticationDetails extends WebAuthenticationDetails {
private String secretKey;
public FormWebAuthenticationDetails(HttpServletRequest request) {
super(request);
this.secretKey = request.getParameter("secret_key");
}
public String getSecretKey() {
return secretKey;
}
}
- AuthenticationDetailsSource 를 구현한 클래스를 정의
- 제네릭 타입으로 <HttpServletRequest, WebAuthenticationDetails> 를 정의
- 재정의할 메서드인 buildDetails() 에서 CustomWebAuthenticationDetails 를 리턴시킨다.
AuthenticationDetailsSource 는 스프링에서 관리되야 하므로 Spring Bean 이여야한다.
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class FormAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {
@Override
public WebAuthenticationDetails buildDetails(HttpServletRequest context) {
return new FormWebAuthenticationDetails(context);
}
}
등록
- SpringSecurityConfig 클래스의 configure(HttpSecurity) 메서드로 진입
- formLogin() 의 하위 API로 authenticationDetailsSource() 를 제공하고 있기에 해당 메서드의 인자값으로 주입받은 CustomAuthenticationDetailsSource를 준다.
@Autowired
private AuthenticationDetailsSource authenticationDetailsSource;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/","/users").permitAll()
.antMatchers("/mypage").hasRole("USER")
.antMatchers("/messages").hasRole("MANAGER")
.antMatchers("/config").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.loginProcessingUrl("/login_proc")
.authenticationDetailsSource(authenticationDetailsSource)
.permitAll();
}
사용
- AuthenticationProvider의 인증처리 과정에서 authentication 객체의 getDetails() 메서드로 추출
- 상속한 WebAuthenticationDetails 에 맞게 캐스팅
- 값을 비교하며 검증을 하는 도중 알맞지않다면 InsufficientAuthenticationException을 throw
@Autowired
private UserDetailsService userDetailsService;//유저 정보를 끌어오는 클래스
@Autowired
PasswordEncoder passwordEncoder; // 패스워드 검증위한 인코더
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {//검증의 로직
//authentication 객체는 입력한 username, password 를 담고 있다.
String username = authentication.getName(); // username 추출
String password = (String)authentication.getCredentials(); // password 는 credentical 에 저장되어 있음.
AccountContext accountContext = (AccountContext)userDetailsService.loadUserByUsername(username);// 원하는 UserDetails 로 캐스팅
if(!passwordEncoder.matches(password, accountContext.getPassword())){// 사용자 암호와 저장된 암호화된 정보를 비교
throw new BadCredentialsException("BadCredentialsException");
}
FormWebAuthenticationDetails formWebAuthenticationDetails =(FormWebAuthenticationDetails)authentication.getDetails();
String secretKey = formWebAuthenticationDetails.getSecretKey();//<<<<<<<커스텀 WebAuthenticationDetails
if(secretKey == null && "secret".equals(secretKey)){
throw new InsufficientAuthenticationException("InsufficientAuthenticationException");
}
//principal : 아이디 credentials : 암호 athorities : 권한정보 . 즉 최종 인증 토큰 생성 과정
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(accountContext.getAccount(), null,accountContext.getAuthorities());
return usernamePasswordAuthenticationToken;//AuthenticationManager 에게 리턴
}
'springframework > 시작하자SpringSecurity' 카테고리의 다른 글
32.CustomAuthenticationFailureHanlder (0) | 2020.09.29 |
---|---|
31.CustomAuthenticationSuccessHandler (0) | 2020.09.29 |
29.Logout 화면과 보안처리 (0) | 2020.09.28 |
28.CustonLoginPage (0) | 2020.09.28 |
27.인증구현, CustomAuthenticationProvider (0) | 2020.09.27 |