@Getter
public class FormAuthenticationDetails extends WebAuthenticationDetails {
private final String secretKey;
//IP 주소와 세션 ID + SecretKey 정보
public FormAuthenticationDetails(HttpServletRequest request) {
super(request);
this.secretKey = request.getParameter("secret_key");
}
}
@Component
public class FormWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {
@Override
public WebAuthenticationDetails buildDetails(HttpServletRequest request) {
return new FormAuthenticationDetails(request);
}
}
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final AuthenticationProvider authenticationProvider;
private final AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/css/**", "/js/**", "/images/**", "/webjars/**", "/favicon.*", "/*/icon-*").permitAll() //정적 자원 관리
.requestMatchers("/", "/signup").permitAll()
.anyRequest().authenticated())
.formLogin(form -> form
.loginPage("/login").permitAll()
.authenticationDetailsSource(authenticationDetailsSource) //추가
)
.authenticationProvider(authenticationProvider)
;
return http.build();
}
}
@Component("authenticationProvider")
@RequiredArgsConstructor
public class FormAuthenticationProvider implements AuthenticationProvider {
private final UserDetailsService userDetailsService;
private final PasswordEncoder passwordEncoder;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String loginId = authentication.getName();
String password = (String) authentication.getCredentials();
AccountContext accountContext = (AccountContext) userDetailsService.loadUserByUsername(loginId);
if (!passwordEncoder.matches(password, accountContext.getPassword())) {
throw new BadCredentialsException("Invalid password");
}
//추가
String secretKey = ((FormAuthenticationDetails) authentication.getDetails()).getSecretKey();
if (secretKey == null || !secretKey.equals("secret")) {
throw new SecretException("Invalid secret");
}
return new UsernamePasswordAuthenticationToken(
accountContext.getAccountDto(), null, accountContext.getAuthorities()
);
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.isAssignableFrom(UsernamePasswordAuthenticationToken.class);
}
}
import org.springframework.security.core.AuthenticationException;
public class SecretException extends AuthenticationException {
public SecretException(String message) {
super(message);
}
}