프로젝트에서 Spring Security + JWT + Redis 방식으로 인증/인가 로직을 구현하였고, 전체 과정을 기록으로 남겨두려 한다.
⇒ 즉, 먼저 사용자가 맞는지 인증한 후, 인증된 사용자에 한해 인가 절차를 수행한다.
Ex) 로그인을 통해 인증되면 url 별로 설정된 접근 권한에 따라 인가 여부가 결정된다.


hasRole() 과 같은 메서드로 설정할 수 있는데, 해당 정보가 SecurityMetadataSource에 의해 반환된다.
MODE_THREADLOCAL, MODE_INHERITABLETHREADLOCAL, MODE_GLOBAL 방식을 제공한다.MODE_??MODE_THREADLOCALMODE_INHERITABLETHREADLOCALMODE_GLOBAL try {
Authentication authentication = Objects.requireNonNull(SecurityContextHolder
.getContext()
.getAuthentication());
if (authentication instanceof AnonymousAuthenticationToken) {
authentication = null;
}
return authentication.getName();
} catch (NullPointerException e) {
throw new RuntimeException();
}AbstractAuthenticationToken 추상 클래스를 상속받아 구현된다.AbstractAuthenticationTokenauthenticated 변수를 갖고 있으며, setAuthenticated() 메서드를 통해 인증되면 true, 아니면 false가 저장된다.authenticate() 메서드가 있는 Interface이다.authenticate()Authentication authenticate(Authentication var1) throws AuthenticationException;public class ProviderManager implements AuthenticationManager, MessageSourceAware,
InitializingBean {
public List<AuthenticationProvider> getProviders() {
return providers;
}
...public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
...
for (AuthenticationProvider provider : getProviders()) {
....
try {
result = provider.authenticate(authentication);
if (result != null) {
copyDetails(authentication, result);
break;
}
}
catch (AccountStatusException e) {
prepareException(e, authentication);
// SEC-546: Avoid polling additional providers if auth failure is due to
// invalid account status
throw e;
}
....
}
...
}authenticate() 이다. // 1. id, pw 기반 Authentication 객체 생성, 해당 객체는 인증 여부를 확인하는 authenticated 값이 false.
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(id, password);
// 2. 검증 진행 - 내부적으로 CustomUserDetailsService.loadUserByUsername 메서드가 실행됨
Authentication authentication = authenticationManagerBuilder.getObject()
.authenticate(authenticationToken);authenticate() 메서드를 통해 인증 로직이 수행될 때, 성공한 Authentication 객체를 생성하는 과정 중 UserDetails를 구현한 클래스의 객체가 필요하다.loadUserByUsername() 메서드를 통해 반환된다.loadUserByUsername() 만을 갖고 있는 Interface이다.public interface UserDetailsService {
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}authenticate()) 중 해당 메서드가 호출되며, 접근 주체의 정보에 해당하는 사용자 정보를 담은 UserDetails 객체를 반환하는 역할을 수행한다.getAuthority() 를 갖고 있는 Interface이다.public interface GrantedAuthority extends Serializable {
String getAuthority();
}ROLE_? 형태로 활용된다.ROLE_USERROLE_ADMINgetAuthorities() 메서드를 갖고 있으며, 해당 사용자가 갖고 있는 권한들을 GrantedAuthority 객체의 List로 반환해야 한다.public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
...
authenticate())이 수행된다. authenticate())authenticate() 과정 중 UserDetailsService의 loadUserByUsername() 메서드가 호출된다.loadUserByUsername() 메서드를 통해 UserDetails 객체가 생성된다.
hasRole(), hasAuthority() 등으로 설정하는 권한 정보가 해당 과정에서 반환된다.hasRole(), hasAnyRole(), hasAuthority(), permitAll(), denyAll(), …