보안 용어 정리
Principal (접근주체) : 보호된 리로스에 접근하는 대상
인증(Authentication) : 누구인지 , / 보호된 리소스에 접근한 대상에 대해 이 유저가 누구인지 / 주체확인 /
인가(Authorize) : 어떤것을 할 수 있는지 / 해당 리소스에 대한 접근 가능한 권한을 확인하는 과정 (인증 이후)
● JWT인증 처리
● JwtAuthenticationFilter
로그인 진행 및 JWT생성
package com.sparta.springauth.jwt;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sparta.springauth.dto.LoginRequestDto;
import com.sparta.springauth.entity.UserRoleEnum;
import com.sparta.springauth.security.UserDetailsImpl;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.io.IOException;
@Slf4j(topic = "로그인 및 JWT 생성")
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final JwtUtil jwtUtil;
public JwtAuthenticationFilter(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
setFilterProcessesUrl("/api/user/login");
}
@Override
//HttpServletRequest request = 클라이언트의 요청 정보 가지고 있는 객체
// HttpServletResponse response = 서버의 응답 정보를 가지고 있는 객체
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
log.info("로그인 시도");
try {
//request.getInputStream() 사용자 아이디 비번
// ObjectMapper().readValue = 아래 따로 설명정리
LoginRequestDto requestDto = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class);
//인증처리하는 메서드
return getAuthenticationManager().authenticate(
//인증처리하는 메서드 안에 넣을 토큰객체
// UsernamePasswordAuthenticationToken() = 사용자의 비밀번호와 아이디를 저장하는 토큰 객체
new UsernamePasswordAuthenticationToken(
requestDto.getUsername(),
requestDto.getPassword(),
null
)
);
} catch (IOException e) {
log.error(e.getMessage());
throw new RuntimeException(e.getMessage());
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
log.info("로그인 성공 및 JWT 생성");
// UserDetailsImpl로 형변환하는 이유? 는 아래에 정리
String username = ((UserDetailsImpl) authResult.getPrincipal()).getUsername();
UserRoleEnum role = ((UserDetailsImpl) authResult.getPrincipal()).getUser().getRole();
String token = jwtUtil.createToken(username, role);
jwtUtil.addJwtToCookie(token, response);
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
log.info("로그인 실패");
response.setStatus(401);
}
}
● ObjectMapper()( Jackson 라이브러리의 일부 )
:: JSON데이터와 객체간의 변환을 처리하는 역할
● readValue()
:: JSON형식의 데이터를 JAVA객체로 변환하는 기능
※ 정리하면
ObjectMapper().readValue()는 JSON 형식의 데이터를 Java 객체로 변환하는 역할을 수행. 이 코드에서는
HttpServletRequest를 사용하여 클라이언트의 요청에서 사용자 아이디와 비밀번호를 읽어와
LoginRequestDto객체로 변환해서 변환된 객체를 사용자 인증 처리함
● UserDetailsImpl
:: authResult.getPricipal() 은 반환타입이 객체이다.
:: UserDetailsImpl 에 getUsername() 메서드와 getUser() 메서드가 정의 되어 있음.
:: 해당 클래스의 정의된 기능을 사용하기위해서는 해당 타입에 맞춰 형변환해야한다.
● JWT인가처리
● JwtAuthorizationFilter
API에 전달되는 JWT유효성 검증 및 인가 처리
생각하자
로그인 진행 및 jwt생성을 했으면 그 해당 jwt 검증 및 인가처리를 해야한다.
package com.sparta.springauth.jwt;
import com.sparta.springauth.security.UserDetailsServiceImpl;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Slf4j(topic = "JWT 검증 및 인가")
public class JwtAuthorizationFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
private final UserDetailsServiceImpl userDetailsService;
public JwtAuthorizationFilter(JwtUtil jwtUtil, UserDetailsServiceImpl userDetailsService) {
this.jwtUtil = jwtUtil;
this.userDetailsService = userDetailsService;
}
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) throws ServletException, IOException {
//jwtUtil객체 사용해서 JWT토큰 추출
//HttpServletRequest객체를 매개변수로 전달하면 요청한 헤더, 그리고 쿠키에서 토큰 가져올수잇음
String tokenValue = jwtUtil.getTokenFromRequest(req);
if (StringUtils.hasText(tokenValue)) {
// JWT 토큰 substring
tokenValue = jwtUtil.substringToken(tokenValue);
log.info(tokenValue);
if (!jwtUtil.validateToken(tokenValue)) {
log.error("Token Error");
return;
}
//jwtUtil객체를 사용하여 토큰에서 사용자 정보 추출(Claims)
//Claims는 JWT토큰에 포함된 사용자 추가정보를 제공하는 객체
Claims info = jwtUtil.getUserInfoFromToken(tokenValue);
try {
//사용자 정보에서 이름만 추출
// setAuthentication() = SecurityContextHolder에 인증정보 설정하고 저장
setAuthentication(info.getSubject());
} catch (Exception e) {
log.error(e.getMessage());
return;
}
}
filterChain.doFilter(req, res);
}
// 인증 처리
public void setAuthentication(String username) {
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = createAuthentication(username);
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
}
// 인증 객체 생성
private Authentication createAuthentication(String username) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
}
}
● doFilterInternal()
jwt토큰을 추출하고 -> 유효성 검사하고 -> 인증 정보 설정하고 컨텍스트에 저장하는 역할하는 메서드
★ 필터 등록
http.addFilterBefore()
:: 해당 메서드는 security의 HttpSecurity객체에 필터를 등록하는 역할
그리고 필터는 체인형태로 동작한다.
앞에 등록된 순서대로 실행!
UsernamePasswordAuthenticationFilter
=> HTTP POST요청에서 아이디와 비밀번호 추출 / 일반적으로 요청의 body에서 아이디와 비밀번호를 추출하는 방식
=> 추출한 정보를 인증처리를 하고 성공하면 Authentication 객체를 생성
'TIL' 카테고리의 다른 글
+27 Spring Security 로그인 (0) | 2023.07.12 |
---|---|
+26 RestTemplate이란 무엇일까? (0) | 2023.07.11 |
+24 Spring Security 프레임워크 (1) | 2023.07.08 |
+23 스프링부트 필터 Filter (0) | 2023.07.07 |
+22 JWT 토큰기반 무엇일까? (0) | 2023.07.06 |