@Data
public class RequestLogin {
@Email
@NotNull(message = "이메일은 빈칸이 안됩니다.")
@Size(min = 2, message = "이메일은 두글자 이상 입력해주세요")
private String email;
@NotNull(message = "비밀번호는 빈칸이 안됩니다.")
@Size(min = 8, message = "비밀번호는 8글자 이상 입력해주세요")
private String password;
}
@Slf4j
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private UserService userService;
private Environment env;
public AuthenticationFilter(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
public AuthenticationFilter(AuthenticationManager authenticationManager, UserService userService, Environment env) {
super.setAuthenticationManager(authenticationManager);
this.userService = userService;
this.env = env;
}
//로그인 요청을 보냈을 때 로직
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
try {
RequestLogin creds = new ObjectMapper().readValue(request.getInputStream(), RequestLogin.class);
//인증정보 생성
return getAuthenticationManager()
.authenticate(
new UsernamePasswordAuthenticationToken(
creds.getEmail(), //id
creds.getPassword(), //pw
new ArrayList<>() //권한 정보
)
);
} catch(IOException e){
throw new RuntimeException(e);
}
}
//로그인 성공했을 때 로직
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
log.debug(((User)authResult.getPrincipal()).getUsername());
}
security의 UsernamePasswordAuthenticationFilter를 구현하여 로그인 요청을 보냈을 때와 로그인을 성공 했을 때 로직을 정의한다.
5.7.X 부터 WebSecurityConfigurerAdapter Deprecate가 Deprecate 되었다.
@Configuration //다른 bean들 보다 우선순위를 앞으로
@RequiredArgsConstructor
@EnableWebSecurity //security 어노테이션
public class WebSecurity {
private final UserService userService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final Environment env; //패스워드를 암호화할떄 jwt토큰 유효시간 다양한 yml파일 정보를 가져올때 쓰기 위해 등록
@Bean // resource 에 대해 Spring Security FilterChain 제외
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().antMatchers("/h2-console/**", "/favicon.ico");
}
//권한
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager = getAuthenticationFilter(http);
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/error/**").permitAll()
.and()
.authenticationManager(authenticationManager)
.addFilter(getAuthenticationFilter(authenticationManager));
// //h2 console error 해결을 위해
http.headers().frameOptions().disable();
return http.build();
private AuthenticationManager getAuthenticationFilter(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder);
return authenticationManagerBuilder.build();
}
private AuthenticationFilter getAuthenticationFilter(AuthenticationManager authenticationManager) {
return new AuthenticationFilter(authenticationManager, userService, env);
}
기존의 모두 permit()해주던 코드에서 filter를 통해 거르도록 설정을 변경해 주었다. 여기서 중요한 것은 마지막 인증 코드인데. UserDetailsService를 상속받은 userSerivce가 필요하다.
public interface UserService extends UserDetailsService {
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity userEntity = userRepository.findByEmail(username);
if (userEntity == null) {
throw new UsernameNotFoundException(username);
}
return new User(username, userEntity.getEncryptedPwd(),
true, true, true, true,
new ArrayList<>());
}
우리가 지정한 email 로그인 방식에 따라 email로 회원을 검색 후 User 객체를 반환하도록 코드를 작성했다.
gateway설정
yaml
- id: user-service
uri: lb://USER-SERVICE
predicates:
- Path=/user-service/login
- Method=POST
filters:
- RemoveRequestHeader=Cookie
- RewritePath=/user-service/(?<segment>.*), /$\{segment}
- id: user-service
uri: lb://USER-SERVICE
predicates:
- Path=/user-service/users
- Method=POST
filters:
- RemoveRequestHeader=Cookie
- RewritePath=/user-service/(?<segment>.*), /$\{segment}
- id: user-service
uri: lb://USER-SERVICE
predicates:
- Path=/user-service/**
- Method=GET
filters:
- RemoveRequestHeader=Cookie
- RewritePath=/user-service/(?<segment>.*), /$\{segment}
이러고 나면 굳이 user-service를 붙일 필요 없어진다
controller에서 @RequestMapping("/") 로 변경