[E-commerce App] Users Microservice - 인증
저번에 만들었던 user-service
에 인증 기능을 추가해보자.
user-service
AuthenticationFilter 추가
아래 두 가지 메서드를 재정의(override) 할 것이다.
attemptAuthentication()
successfulAuthentication()
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws
AuthenticationException {
try {
RequestLogin creds = new ObjectMapper().readValue(request.getInputStream(), RequestLogin.class);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(
creds.getEmail(),
creds.getPassword(),
new ArrayList<>()
);
return getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
}
}
attemptAuthentication
request.getInputStream()
으로 받은 이유는
전달하고자하는 로그인의 값은 POST 형태로 전달되는데, POST 형태로 전달되는 값은 request parameter로 받을 수 없기 때문에
inputStream을 사용하면 수작업으로 어떤 데이터가 들어왔는지 처리할 수 있다.
successfulAuthentication()
사용자가 입력한 아이디와 패스워드 값이 일치했을 때, 어떤 처리를 해줄 것인지, (ex. 토큰 생성)
토큰의 만료시간을 어떻게 설정할건지,
사용자가 로그인 했을 때 반환값으로 어떤걸 줄건지… 등을 정의한다.
WebSecurity 변경
@Configuration
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/**")
.hasIpAddress("192.168.x.x") // 🌟 본인 IP 변경
.and()
.addFilter(getAuthenticationFilter());
http.headers().frameOptions().disable();
}
private AuthenticationFilter getAuthenticationFilter() throws Exception {
AuthenticationFilter authenticationFilter = new AuthenticationFilter();
authenticationFilter.setAuthenticationManager(authenticationManager());
return authenticationFilter;
}
}
loadUserByUsername() 구현
UserService
를 먼저 변경한 뒤, UserServiceImpl
에 loadUserByUsername()
을 구현한다.
UserService
public interface UserService extends UserDetailsService { // 🌟 UserDetailsService 상속
...
}
UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity userEntity = userRepository.findByEmail(username);
if (userEntity == null) {
throw new UsernameNotFoundException(username);
}
return new User(
userEntity.getEmail(),
userEntity.getEncryptedPwd(),
true,
true,
true,
true,
new ArrayList<>()
);
}
...
}
gateway-service
application.yml
server:
port: 8000
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
- 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/** # 🌟 /user-service/** 등록
- Method=GET
filters:
- RemoveRequestHeader=Cookie
- RewritePath=/user-service/(?<segment>.*), /$\{segment}
- id: catalog-service
uri: lb://CATALOG-SERVICE
predicates:
- Path=/catalog-service/**
- id: order-service
uri: lb://ORDER-SERVICE
predicates:
- Path=/order-service/**
테스트
해당 마이크로 서비스에 할당된 포트번호로 직접 요청하려면 아래와 같이 요청하면 된다.
http://localhost:60910/login
이 때, localhost:
뒤에는 할당된 랜덤 프트를 적으면 되고, prefix는 필요없다.
api gateway를 통해 요청하려면 아래와 같이 요청하면 된다.
http://localhost:8000/user-serivce/login
이때는 /user-service
라는 prefix를 붙여야 한다.
🤔 생각해보니
/login
엔드포인트는 컨트롤러에 따로 정의하지 않았는데 어떻게 가능할까?
/login
엔드포인트는 Spring Security를 사용하게되면 기본적으로 제공하는 엔드포인트이다.
하지만/login
엔드포인트를 직접 정의해 추가적인 설정을 할 수도 있다.
💛 개인 공부 기록용 블로그입니다. 👻