실무에서 JWT 토큰 인증 구현이 가장 일반적이지만, 웹으로 만든 사이트를 모바일에서 하이브리드 형식으로 빠른 제공을 하고 싶다면 BasicToken을 사용하고 session을 이용하면 된다.
*모바일에서 MultiChainProxy 구성하기
MobileSecurityConfig에서 BasicAuthenticationFilter 방식을 사용하는데, 이는 UsernamePasswordAuthentication 으로 검사하여 해당 토큰을 인증제공자(AuthenticationProvider)에게 준다.
SecurityConfig에서 CustomLoginFilter를 사용하는데 CustomLoginFilter는 Student와 Teacher의 토큰을 인증하기 위해 각각 StudentAuthentication 토큰과 TeacherAuthentication 토큰을 만든다. 만들어진 토큰을 StudentManger와 TeacherManager로 보낸다. supports() 메서드로 인증 가능한 토큰을 검사해서 가능하다면 authenticate()에서 인증을 완료한다. 단, 자신이 제어하지 않는 토큰은 return null을 하여야 다른 필터에서 검증이 가능하므로 주의한다.
*모바일용 시큐리티 설정 추가하기
@Order(1)
@Configuration
public class MobileSecurityConfig extends WebSecurityConfigurerAdapter {
private final StudentManager studentManager;
private final TeacherManager teacherManager;
public MobileSecurityConfig(StudentManager studentManager, TeacherManager teacherManager) {
this.studentManager = studentManager;
this.teacherManager = teacherManager;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(studentManager);
auth.authenticationProvider(teacherManager);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.csrf().disable()
.authorizeRequests(request ->
request.anyRequest().authenticated()
)
.httpBasic();
}
}
.antMatcher("/api/**") 방식으로 api통신의 경우 해당 시큐리티 필터를 지나가도록 설정한다.
.httpBasic() 방식을 사용해 form 로그인이 없는 모바일 환경에서 basicAuthentication 방식으로 로그인 인증을 사용한다.
@Order(2)
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final StudentManager studentManager;
private final TeacherManager teacherManager;
현재 모바일과 웹을 위한 총 2개의 필터가 작동하고 있다. 다른 인증 체계 필터가 작동한다.
첫번째 순서로 MobileSecurityConfig가 검증을 하는데 BasicAuthentication방식의 httpBasic만 검사한다. api로 대표하는 모바일 서비스를 위해 인증 검사 경로를 /api/**로 하였다. 모바일은 form 로그인을 사용할 수 없기 때문에 httpBasic 로그인 인증을 사용한다.
두번째 순서로 SecurityConfig는 UsernamePasswordAuthenticationToken으로 모든 인증을 담당한다. 로그인 인증 요청을 form으로 하기 때문에 csrf 토큰 사용을 한다. (csrf 토큰 인증방식은 ajax에서도 사용한다.)
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if(authentication instanceof UsernamePasswordAuthenticationToken) {
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
if(studentDB.containsKey(token.getName())) {
Student student = studentDB.get(token.getName());
return studentAuthenticationToken(student);
}
return null;
}
if(authentication instanceof StudentAuthenticationToken) {
StudentAuthenticationToken token = (StudentAuthenticationToken) authentication;
if(studentDB.containsKey(token.getCredentials())) {
Student student = studentDB.get(token.getCredentials());
return studentAuthenticationToken(student);
}
return null;
}
return null;
}
private StudentAuthenticationToken studentAuthenticationToken(Student student) {
return StudentAuthenticationToken.builder()
.principal(student)
.credentials(null)
.details(student.getUsername())
.authenticated(true)
.build();
}
@Override
public boolean supports(Class<?> authentication) {
return authentication == StudentAuthenticationToken.class ||
authentication == UsernamePasswordAuthenticationToken.class;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if(authentication instanceof UsernamePasswordAuthenticationToken) {
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
if(teacherDB.containsKey(token.getName())) {
Teacher teacher = teacherDB.get(token.getName());
return getAuthenticationToken(teacher);
}
return null;
}
if(authentication instanceof TeacherAuthenticationToken) {
TeacherAuthenticationToken token = (TeacherAuthenticationToken) authentication;
if(teacherDB.containsKey(token.getCredentials())) {
Teacher teacher = teacherDB.get(token.getCredentials());
return getAuthenticationToken(teacher);
}
return null;
}
return null;
}
private TeacherAuthenticationToken getAuthenticationToken(Teacher teacher) {
return TeacherAuthenticationToken.builder()
.principal(teacher)
.credentials(null)
.details(teacher.getUsername())
.authenticated(true)
.build();
}
@Override
public boolean supports(Class<?> authentication) {
return authentication == TeacherAuthenticationToken.class ||
authentication == UsernamePasswordAuthenticationToken.class;
}
인증방식은
1. 토큰 인증 필터에서 각 필터들의 고유한 방식으로 정보들을 추출하고 토큰 만들기
2. AuthenticationManager에서 토큰 종류에 따라서 자신의 방법으로 검사 후 결과 리턴
'Spring > Spring Security' 카테고리의 다른 글
RememberMe (0) | 2021.10.12 |
---|---|
UserDetailsService (0) | 2021.10.11 |
BasicAuthentication 인증 (0) | 2021.10.11 |
authentication 메커니즘 (0) | 2021.10.08 |
basic login 과정 (0) | 2021.10.08 |