사용자 관리하기
회원가입 구현
회원가입 설계
- @Enumerated(value = EnumType.STRING)
- EnumType을 DB 컬럼에 저장할 때 사용하는 애너테이션
- EnumType.STRING 옵션을 사용하면 Enum의 이름을 DB에 그대로 저장
패스워드 암호화 이해
- 패스워드를 저장할때, '단방향' 암호 알고리즘 사용이 필요
- 패스워드 확인절차 : 가입시 등록한 패스워드의 암호문 vs 로그인시 입력한 패스워드의 암호문
if(!passwordEncoder.matches("사용자가 입력한 비밀번호", "저장된 비밀번호")) {
throw new IllegalAccessError("비밀번호가 일치하지 않습니다.");
}
Filter
Filter란?
- Client로 부터 오는 요청과 응답에 대해 최초/최종 단계
- 요청과 응답의 정보를 변경, 부가적인 기능을 추가 가능
- 주로 범용적으로 처리해야 하는 작업에 활용(로깅, 보안 처리, 인증, 인가)
- Filter를 사용하면 인증, 인가와 관련된 로직을 비즈니스 로직과 분리하여 관리할 수 있다는 장점
Filter Chain
- 여러개의 필터가 체인형식으로 묶여서 처리될 수 있음
적용
- Request URL Logging
@Slf4j(topic = "LoggingFilter")
@Component
@Order(1)
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String url = httpServletRequest.getRequestURI();
log.info(url);
chain.doFilter(request, response);
log.info("비즈니스 로직 완료");
}
}
- 인증 및 인가 처리 필터
@Slf4j(topic = "AuthFilter")
@Component
@Order(2)
public class AuthFilter implements Filter {
private final UserRepository userRepository;
private final JwtUtil jwtUtil;
public AuthFilter(UserRepository userRepository, JwtUtil jwtUtil) {
this.userRepository = userRepository;
this.jwtUtil = jwtUtil;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String url = httpServletRequest.getRequestURI();
if (StringUtils.hasText(url) &&
(url.startsWith("/api/user") || url.startsWith("/css") || url.startsWith("/js"))
) {
chain.doFilter(request, response);
} else {
String tokenValue = jwtUtil.getTokenFromRequest(httpServletRequest);
if (StringUtils.hasText(tokenValue)) {
String token = jwtUtil.substringToken(tokenValue);
if (!jwtUtil.validateToken(token)) {
throw new IllegalArgumentException("Token Error");
}
Claims info = jwtUtil.getUserInfoFromToken(token);
User user = userRepository.findByUsername(info.getSubject()).orElseThrow(() ->
new NullPointerException("Not Found User")
);
request.setAttribute("user", user);
chain.doFilter(request, response);
} else {
throw new IllegalArgumentException("Not Found Token");
}
}
}
}
public String getTokenFromRequest(HttpServletRequest req) {
Cookie[] cookies = req.getCookies();
if(cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(AUTHORIZATION_HEADER)) {
try {
return URLDecoder.decode(cookie.getValue(), "UTF-8");
} catch (UnsupportedEncodingException e) {
return null;
}
}
}
}
return null;
}
RestTemplate
RestTemplate이란 무엇일까?
Server To Server
- RestTemplate : 서버에서 다른 서버로 간편하게 요청할 수 있도록 하는 기능
RestTemplate의 Get 요청
Get 요청 방법(getForEntity)
- RestTemplate 주입
private final RestTemplate restTemplate;
public RestTemplateService(RestTemplateBuilder builder) {
this.restTemplate = builder.build();
}
- 요청 받은 검색어를 Query String 방식으로 Server 입장의 서버로 RestTemplate를 사용하여 요청
public ItemDto getCallObject(String query) {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:7070")
.path("/api/server/get-call-obj")
.queryParam("query", query)
.encode()
.build()
.toUri();
log.info("uri = " + uri);
ResponseEntity<ItemDto> responseEntity = restTemplate.getForEntity(uri, ItemDto.class);
log.info("statusCode = " + responseEntity.getStatusCode());
return responseEntity.getBody();
}
요청한 item이 여러 개라면?(다건)
public List<ItemDto> getCallList() {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:7070")
.path("/api/server/get-call-list")
.encode()
.build()
.toUri();
log.info("uri = " + uri);
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
log.info("statusCode = " + responseEntity.getStatusCode());
log.info("Body = " + responseEntity.getBody());
return fromJSONtoItems(responseEntity.getBody());
}
public List<ItemDto> fromJSONtoItems(String responseEntity) {
JSONObject jsonObject = new JSONObject(responseEntity);
JSONArray items = jsonObject.getJSONArray("items");
List<ItemDto> itemDtoList = new ArrayList<>();
for (Object item : items) {
ItemDto itemDto = new ItemDto((JSONObject) item);
itemDtoList.add(itemDto);
}
return itemDtoList;
}
RestTemplate의 Post 요청
Post 요청 방법(postForEntity)
public ItemDto postCall(String query) {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:7070")
.path("/api/server/post-call/{query}")
.encode()
.build()
.expand(query)
.toUri();
log.info("uri = " + uri);
User user = new User("Robbie", "1234");
ResponseEntity<ItemDto> responseEntity = restTemplate.postForEntity(uri, user, ItemDto.class);
log.info("statusCode = " + responseEntity.getStatusCode());
return responseEntity.getBody();
}
RestTemplate의 exchange
- RestTemplate으로 요청을 보낼 때 Header에 특정 정보를 같이 전달 하고 싶을 때 사용
- Client 입장
public List<ItemDto> exchangeCall(String token) {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:7070")
.path("/api/server/exchange-call")
.encode()
.build()
.toUri();
log.info("uri = " + uri);
User user = new User("Robbie", "1234");
RequestEntity<User> requestEntity = RequestEntity
.post(uri)
.header("X-Authorization", token)
.body(user);
ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
return fromJSONtoItems(responseEntity.getBody());
}