작성
·
6.2K
·
수정됨
13
Spring Security 가 3점대 버전으로 오면서 상당한 변화가 있습니다. 강의 내용을 따라 하다보니 순환참조나, 현재는 지원하지 않는 기능이 상당수 존재하였습니다. 현재 작업한 코드가 문제 해결에 많은 도움이 되면 좋겠어서 글을 첨부합니다.
SecurityConfig.class 입니다.
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig{
private final CustomAuthenticationManager customAuthenticationManager;
private final UserFindPort userFindPort;
private final Environment environment;
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().
requestMatchers(new AntPathRequestMatcher("/h2-console/**"))
.requestMatchers(new AntPathRequestMatcher( "/favicon.ico"))
.requestMatchers(new AntPathRequestMatcher( "/css/**"))
.requestMatchers(new AntPathRequestMatcher( "/js/**"))
.requestMatchers(new AntPathRequestMatcher( "/img/**"))
.requestMatchers(new AntPathRequestMatcher( "/lib/**"));
}
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
http.csrf(AbstractHttpConfigurer::disable);
http.authorizeHttpRequests(authorize ->
authorize.requestMatchers(new MvcRequestMatcher(introspector, "/**")).permitAll()
// requestMatchers(new MvcRequestMatcher.Builder(introspector).pattern(HttpMethod.GET, "/users/**")).permitAll()
// .requestMatchers(new MvcRequestMatcher(introspector, "/greeting")).permitAll()
// .requestMatchers(new MvcRequestMatcher(introspector, "/welcome")).permitAll()
// .requestMatchers(new MvcRequestMatcher(introspector, "/health-check")).permitAll()
// .requestMatchers(new MvcRequestMatcher.Builder(introspector).pattern(HttpMethod.POST, "/users")).permitAll()
.anyRequest()
.authenticated())
.addFilter(getAuthenticationFilter())
.httpBasic(Customizer.withDefaults());
return http.build();
}
private AuthenticationFilter getAuthenticationFilter() {
return new AuthenticationFilter(customAuthenticationManager, userFindPort, environment);
}
}
requestMatcher에서 AntPathRequestMatcher, MvcRequestMatcher에 관한 설명은
부족하지만 https://velog.io/@dktlsk6/Spring-Security-RequestMatcher
에서 확인 가능하십니다.
CustomUserDetailService.class 입니다. 순환참조 문제가 발생하여 강의와 달리 새로 CustomService를 생성하여 implements 하였습니다.
@Component
@RequiredArgsConstructor
public class CustomUserDetailService implements UserDetailsService {
private final UserFindPort userFindPort;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDto userByEmail = userFindPort.findUserByEmail(username);
if (userByEmail == null) {
throw new UsernameNotFoundException("User Not Found");
}
return new User(userByEmail.getEmail(), userByEmail.getEncPasswd(), true, true, true, true, new ArrayList<>());
}
}
CustomAuthenticationManager.class 입니다. AuthenticationFilter의 AuthenticationManager로 사용할 것입니다.
@Component
@RequiredArgsConstructor
@Slf4j
public class CustomAuthenticationManager implements AuthenticationManager {
private final CustomUserDetailService customUserDetailService;
@Bean
protected PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UserDetails userDetails = customUserDetailService.loadUserByUsername(authentication.getName());
if (!passwordEncoder().matches(authentication.getCredentials().toString(), userDetails.getPassword())) {
throw new BadCredentialsException("Wrong password");
}
return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
}
}
AuthenticationFilter.class 입니다. 해당 부분은 강의와 차이점이 없습니다.
@Slf4j
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final UserFindPort userFindPort;
private final Environment environment;
public AuthenticationFilter(AuthenticationManager authenticationManager, UserFindPort userFindPort, Environment environment) {
super.setAuthenticationManager(authenticationManager);
this.userFindPort = userFindPort;
this.environment = environment;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
LoginRequestDto creds = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(creds.getEmail(),
creds.getPassword(), new ArrayList<>());
return getAuthenticationManager().authenticate(token);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
String username = authResult.getName();
UserDto user = userFindPort.findUserByEmail(username);
if (user == null) {
throw new UsernameNotFoundException(username);
}
log.debug("user id {}", user.getUserId());
String token = Jwts.builder()
.setSubject(user.getUserId())
.setExpiration(new Date(System.currentTimeMillis() + Long.parseLong(environment.getProperty("token.expiration.time"))))
.signWith(SignatureAlgorithm.HS512, environment.getProperty("token.secret"))
.compact();
response.addHeader("token", token);
response.addHeader("userId", user.getUserId());
}
}
아래는 실제 결과입니다.
404가 뜨는 이유는 login 성공시 redirect url을 설정해주지 않아서 /(루트) 경로로 이동해서입니다. 해당 경로와 매핑되는 resource나 api가 없기 때문에 해당 오류가 발생한것이므로 정상작동으로 생각하시면 됩니다.
아래는 잘못된 정보를 기입하여 실패 테스트 입니다. 추후 강의를 들으며 업데이트 하도록 하겠습니다.
답변 2
2
-7
안녕하세요, 인프런 AI 인턴이에요. Spring Security 3점대 버전에서의 변화에 관한 문의시 도움을 드리겠습니다. 현재 첨부된 SecurityConfig 클래스의 코드를 보면, 기존의 @EnableWebSecurity 애노테이션과 @Configuration 애노테이션이 사용되었음을 알 수 있습니다.
Spring Security 3점대 버전에서는 WebSecurityConfigurerAdapter
클래스를 상속받는 방식으로 설정하는 것이 보다 권장됩니다. 따라서, SecurityConfig
클래스를 WebSecurityConfigurerAdapter
클래스를 상속받도록 수정하고, @Configuration
애노테이션은 삭제하면 됩니다.
또한, SecurityFilterChain
을 설정해주기 위해서는 configure(HttpSecurity http)
메소드를 오버라이드해야 합니다. http
객체를 이용하여 필요한 설정들을 추가하면 됩니다.
예시 코드를 들어보면 아래와 같습니다:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomAuthenticationManager customAuthenticationManager;
private final UserFindPort userFindPort;
private final Environment environment;
public SecurityConfig(CustomAuthenticationManager customAuthenticationManager, UserFindPort userFindPort, Environment environment) {
this.customAuthenticationManager = customAuthenticationManager;
this.userFindPort = userFindPort;
this.environment = environment;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/favicon.ico").permitAll()
.antMatchers("/css/**").permitAll()
.antMatchers("/js/**").permitAll()
.antMatchers("/img/**").permitAll()
.antMatchers("/lib/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
// 로그인 페이지 설정 등 추가 설정 가능
.and()
.logout()
// 로그아웃 관련 설정 추가 가능
.and()
.csrf().disable();
}
// 다른 설정들 (UserDetailsService, PasswordEncoder 등)도 추가 가능
}
위 코드에서는 configure(HttpSecurity http)
메소드를 오버라이드하여, 필요한 URL 별 인가 처리를 설정하고 있습니다. 그 외에도 로그인 페이지 설정, 로그아웃 관련 설정 등을 추가할 수 있습니다.
참고로, WebSecurityCustomizer
는 Spring Security 5점대에서 추가된 기능입니다. 3점대에서는 사용되지 않으며, configure(WebSecurity web)
메소드를 오버라이드하여 정적 리소스에 대한 설정을 할 수 있습니다.
안내드린 방식으로 코드를 수정하면 될 것 같습니다. 추가로 궁금한 점이 있으면 언제든지 물어보세요!
이거 ai 인가요?