HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🤩
개발
/
🔐
Spring Security
/
🌘
Custom AuthenticationProvider 적용
🌘

Custom AuthenticationProvider 적용

UsernamePasswordAuthenticationFilter를 통한 Authentication 메커니즘 살펴보기

  • AuthenticationProvider가 처리 가능한 Authentication에 대해 알려주는 support 메소드를 지원하고, authenticate() 에서 인증 로직을 처리해줌
코드 구현
  1. 통행증을 위한 Authentication 클래스(StudentAuthenticationToken) 정의, principal(Student)에 들어갈 class 정의
  1. 그것을 다룰 AuthenticationProvider 클래스 정의
  1. WebSecurityConfigurerAdapter 를 상속받은 클래스에서 authenticationProvider로 등록해주기
 
진행 순서
  1. http.formLogin()을 통해서 로그인 시, UsernamePasswordAuthenticationFilter 의 attemptAuthentication()으로 넘어오게 됨
      • this.getAuthenticationManager() → authRequest의 타입인 UsernamePasswordAuthenticationToken을 처리할 수 있는 AuthenticationProvider를 반환하게됨
  1. UsernamePasswordAuthenticationToken을 처리할 수 있는(supports메소드에서 정의) AuthenticationProvider → StudentManager
  1. StudentManager의 authenticate() 에서 UsernamePasswordAuthenticationToken을 StudentAuthenticationToken으로 변환하여 반환
@Data @AllArgsConstructor @NoArgsConstructor @Builder public class StudentAuthenticationToken implements Authentication { private Student principal; private String credentials; private String details; private boolean authenticated; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return principal == null ? new HashSet<>() : principal.getRole(); } @Override public String getName() { return principal == null ? "" : principal.getUserName(); } } @Data @AllArgsConstructor @NoArgsConstructor @Builder public class Student { private String id; private String userName; private Set<GrantedAuthority> role; }
@Component public class StudentManager implements AuthenticationProvider, InitializingBean { private HashMap<String, Student> studentDB = new HashMap<>(); @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication; if(studentDB.containsKey(token.getName())){ Student student = studentDB.get(token.getName()); return StudentAuthenticationToken.builder() .principal(student) .details(student.getUserName()) .authenticated(true) .build(); } return null; // authentication token을 false로 해서 넘기게 되면 // authentication을 핸들링 했다는 것이 되기 때문에 문제가됨. /// 처리할 수 없는 authentication은 null로 넘겨야 함 // 그래야 그다음 filter에서 문제없이 처리가 가능함 } @Override public boolean supports(Class<?> authentication) { return authentication == UsernamePasswordAuthenticationToken.class; } @Override public void afterPropertiesSet() throws Exception { Set.of( new Student("hong", "홍길동", Set.of(new SimpleGrantedAuthority("ROLE_USER"))), new Student("kang", "강아지", Set.of(new SimpleGrantedAuthority("ROLE_USER"))), new Student("rang", "호랑이", Set.of(new SimpleGrantedAuthority("ROLE_USER"))) ).forEach(s-> studentDB.put(s.getId(), s)); } }
@EnableWebSecurity(debug = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { private final StudentManager studentManager; public SecurityConfig(StudentManager studentManager) { this.studentManager = studentManager; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(studentManager); } }
@Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (this.postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } String username = obtainUsername(request); username = (username != null) ? username : ""; username = username.trim(); String password = obtainPassword(request); password = (password != null) ? password : ""; UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); }