SpringBoot환경에서 Spring Security기반에 JWT 인증 방식을 구현하도록 하겠다.
Spring Security와 JWT에 대한 개념은 아래 포스팅을 참고하기 바란다.
Spring Security 개념 및 Architecture
Spring Security 설정은 아래 포스팅을 참고하기 바란다.
Spring Security + JWT 인증 (2/2) - Spring Security 설정
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
jwt:
header: Authorization
type: Bearer
secret: EStHVT61mNgGaJUWO/+90UAyLbhLfvbVEvkE1r1hhCQ=
#1800000: 30분
access-expiration-time: 1800000
refresh-expiration-time: 3600000
JWT Secret key는 아래 홈페이지에서 생성할 수 있다. JWT에서 사용할 Algorithm에 맞게 secret key를 간편하게 발급할 수 있다. (HS256 사용)
import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.devlog.common.jwt.JwtCode;
import com.devlog.common.jwt.JwtProvider;
import com.devlog.security.PrincipalDetails;
import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequestMapping("/auth")
@RequiredArgsConstructor
@Transactional
@RestController
public class AuthController {
private final AuthenticationManagerBuilder authenticationManagerBuilder;
private final JwtProvider jwtProvider;
@PostMapping("/login")
public ResponseEntity<HashMap<String, String>> login(@RequestBody HashMap<String, String> requestBody) {
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(requestBody.get("email"), requestBody.get("password"));
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
String sAccessToken = jwtProvider.generateAccessToken(authentication);
String sRefreshToken = jwtProvider.generateRefreshToken(principalDetails.getUserId());
HashMap<String, String> responseBody = new HashMap<String, String>();
responseBody.put("userId", String.valueOf(principalDetails.getUserId()));
responseBody.put("userName", principalDetails.getUsername());
responseBody.put("refreshToken", sRefreshToken);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(jwtProvider.getJwtHeader(), jwtProvider.addTokenType(sAccessToken));
return new ResponseEntity<>(responseBody, httpHeaders, HttpStatus.OK);
}
@PostMapping("/refresh")
public ResponseEntity<HashMap<String, String>> refresh(HttpServletRequest httpServletRequest, @RequestBody HashMap<String, String> requestBody) {
HashMap<String, String> responseBody = new HashMap<String, String>();
HttpHeaders httpHeaders = new HttpHeaders();
String inputRefreshToken = requestBody.get("refreshToken");
String sAccessToken = jwtProvider.resolveToken(httpServletRequest);
JwtCode jwtCode = jwtProvider.validateToken(sAccessToken);
switch (jwtCode) {
case ACCESS:
log.info("JWT Token Not Expired");
responseBody.put("error", "JWT Token Not Expired");
break;
case EXPIRED:
Claims claims = jwtProvider.parseClaims(sAccessToken);
if (claims.get("userId") == null) {
log.info("Invalid JWT Token");
return null;
}
Long userId = Long.parseLong(claims.get("userId").toString());
boolean bRefreshTokenValid = jwtProvider.validateRefreshToken(userId, inputRefreshToken);
if(bRefreshTokenValid) {
Authentication authentication = jwtProvider.getAuthentication(sAccessToken);
String sNewAccessToken = jwtProvider.generateAccessToken(authentication);
String sNewRefreshToken = jwtProvider.generateRefreshToken(userId);
SecurityContextHolder.getContext().setAuthentication(authentication);
httpHeaders.add(jwtProvider.getJwtHeader(), jwtProvider.addTokenType(sNewAccessToken));
responseBody.put("msg", "Expried Token Re Issue");
responseBody.put("refreshToken", sNewRefreshToken);
}
else {
log.info("Invalid JWT Token");
responseBody.put("error", "Invalid JWT Token");
}
break;
default:
log.info("Invalid JWT Token");
responseBody.put("error", "Invalid JWT Token");
break;
}
return new ResponseEntity<>(responseBody, httpHeaders, HttpStatus.OK);
}
}
1) /auth/login
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(requestBody.get("email"), requestBody.get("password"));
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
String sAccessToken = jwtProvider.generateAccessToken(authentication);
String sRefreshToken = jwtProvider.generateRefreshToken(principalDetails.getUserId());
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(jwtProvider.getJwtHeader(), jwtProvider.addTokenType(sAccessToken));
return new ResponseEntity<>(responseBody, httpHeaders, HttpStatus.OK);
2) /auth/refresh
Access Token이 만료되고 로그인 시 발행한 Refresh Token을 사용하여 Access Token 재발급한다.
String sAccessToken = jwtProvider.resolveToken(httpServletRequest);
JwtCode jwtCode = jwtProvider.validateToken(sAccessToken);
case EXPIRED:
Claims claims = jwtProvider.parseClaims(sAccessToken);
if (claims.get("userId") == null) {
log.info("Invalid JWT Token");
return null;
}
Long userId = Long.parseLong(claims.get("userId").toString());
boolean bRefreshTokenValid = jwtProvider.validateRefreshToken(userId, inputRefreshToken);
if(bRefreshTokenValid) {
Authentication authentication = jwtProvider.getAuthentication(sAccessToken);
String sNewAccessToken = jwtProvider.generateAccessToken(authentication);
String sNewRefreshToken = jwtProvider.generateRefreshToken(userId);
SecurityContextHolder.getContext().setAuthentication(authentication);
httpHeaders.add(jwtProvider.getJwtHeader(), jwtProvider.addTokenType(sNewAccessToken));
responseBody.put("msg", "Expried Token Re Issue");
responseBody.put("refreshToken", sNewRefreshToken);
}
import java.security.Key;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.devlog.common.entity.RefreshToken;
import com.devlog.common.entity.User;
import com.devlog.security.PrincipalDetails;
import com.devlog.security.RefreshTokenRepository;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class JwtProvider {
private static final String AUTHORITIES_KEY = "auth";
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.access-expiration-time}")
private long accessExpirationTime;
@Value("${jwt.refresh-expiration-time}")
private long refreshExpirationTime;
@Value("${jwt.header}")
private String jwtHeader;
@Value("${jwt.type}")
private String jwtType;
private Key key;
@Autowired
private RefreshTokenRepository refreshTokenRepository;
@PostConstruct
public void init() {
byte[] keyBytes = Decoders.BASE64.decode(secret);
this.key = Keys.hmacShaKeyFor(keyBytes);
}
/**
* Access Token 생성
*/
public String generateAccessToken(Authentication authentication) {
// 인증된 사용자의 권한 목록 조회
String authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
// 토큰의 expire 시간을 설정
long now = (new Date()).getTime();
Date expiration = new Date(now + accessExpirationTime);
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
return Jwts.builder()
.setSubject(authentication.getName())
.claim("userId", principalDetails.getUserId())
.claim(AUTHORITIES_KEY, authorities)
.setExpiration(expiration)
.signWith(key, SignatureAlgorithm.HS256)
.compact();
}
/**
* Refresh Token 생성
*/
@Transactional
public String generateRefreshToken(Long userId) {
long issue = (new Date()).getTime();
long expired = (new Date(issue + refreshExpirationTime)).getTime();
String uuid = UUID.randomUUID().toString();
RefreshToken refreshToken = new RefreshToken();
refreshToken.setUserId(userId);
refreshToken.setToken(uuid);
refreshToken.setIssue(String.valueOf(issue));
refreshToken.setExpired(String.valueOf(expired));
refreshTokenRepository.save(refreshToken);
return uuid;
}
/**
* 토큰에서 인증 정보 조회 후 Authentication 객체 리턴
*
* 토큰 -> 클레임 추출 -> 유저 객체 제작 -> Authentication 객체 리턴
*/
public Authentication getAuthentication(String token) {
Claims claims = this.parseClaims(token);
if (claims.get(AUTHORITIES_KEY) == null) {
throw new RuntimeException("권한 정보가 없는 토큰입니다.");
}
List<? extends GrantedAuthority> authorities = Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
User user = new User();
user.setUsername(claims.getSubject());
user.setUserId(Long.parseLong(claims.get("userId").toString()));
user.setAuthority(claims.get(AUTHORITIES_KEY).toString());
PrincipalDetails principal = new PrincipalDetails(user);
return new UsernamePasswordAuthenticationToken(principal, token, authorities);
}
/**
* JWT Claims 복호화
*/
public Claims parseClaims(String token) {
try {
return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
}catch (ExpiredJwtException e) {
return e.getClaims();
}
}
/**
* 토큰 검증
*/
public JwtCode validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
return JwtCode.ACCESS;
} catch (ExpiredJwtException e) {
log.info("Expired JWT Token");
return JwtCode.EXPIRED;
} catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
log.info("Invalid JWT Token");
return JwtCode.DENIED;
} catch (UnsupportedJwtException e) {
log.info("Unsupported JWT Token");
return JwtCode.DENIED;
} catch (IllegalArgumentException e) {
log.info("JWT claims string is empty");
return JwtCode.DENIED;
} catch (Exception e) {
log.info("Exception");
return JwtCode.DENIED;
}
}
/**
* Refresh Token 검증
*/
public boolean validateRefreshToken(Long userId, String validRefreshToken) {
RefreshToken refreshToken = refreshTokenRepository.findByUserId(userId);
if(!refreshToken.getToken().equals(validRefreshToken)) {
return false;
}
long now = (new Date()).getTime();
long expired = Long.parseLong(refreshToken.getExpired());
if(now > expired) {
return false;
}
return true;
}
public String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(jwtHeader);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(jwtType)) {
return bearerToken.substring(7);
}
return null;
}
/**
* prefix Token Type Add
*/
public String addTokenType(String token) {
return String.format("%s %s", jwtType, token);
}
public String getJwtHeader() {
return jwtHeader;
}
public String getJwtType() {
return jwtType;
}
}
JWT 토큰 생성, 추출 그리고 검증에 관한 내용이 정의되어 있다.
@PostConstruct
public void init() {
byte[] keyBytes = Decoders.BASE64.decode(secret);
this.key = Keys.hmacShaKeyFor(keyBytes);
}
/**
* Access Token 생성
*/
public String generateAccessToken(Authentication authentication) {
// 인증된 사용자의 권한 목록 조회
String authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
// 토큰의 expire 시간을 설정
long now = (new Date()).getTime();
Date expiration = new Date(now + accessExpirationTime);
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
return Jwts.builder()
.setSubject(authentication.getName())
.claim("userId", principalDetails.getUserId())
.claim(AUTHORITIES_KEY, authorities)
.setExpiration(expiration)
.signWith(key, SignatureAlgorithm.HS256)
.compact();
}
@Transactional
public String generateRefreshToken(Long userId) {
long issue = (new Date()).getTime();
long expired = (new Date(issue + refreshExpirationTime)).getTime();
String uuid = UUID.randomUUID().toString();
RefreshToken refreshToken = new RefreshToken();
refreshToken.setUserId(userId);
refreshToken.setToken(uuid);
refreshToken.setIssue(String.valueOf(issue));
refreshToken.setExpired(String.valueOf(expired));
refreshTokenRepository.save(refreshToken);
return uuid;
}
/**
* 토큰에서 인증 정보 조회 후 Authentication 객체 리턴
*
* 토큰 -> 클레임 추출 -> 유저 객체 제작 -> Authentication 객체 리턴
*/
public Authentication getAuthentication(String token) {
Claims claims = this.parseClaims(token);
if (claims.get(AUTHORITIES_KEY) == null) {
throw new RuntimeException("권한 정보가 없는 토큰입니다.");
}
List<? extends GrantedAuthority> authorities = Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
User user = new User();
user.setUsername(claims.getSubject());
user.setUserId(Long.parseLong(claims.get("userId").toString()));
user.setAuthority(claims.get(AUTHORITIES_KEY).toString());
PrincipalDetails principal = new PrincipalDetails(user);
return new UsernamePasswordAuthenticationToken(principal, token, authorities);
}
/**
* Refresh Token 검증
*/
public boolean validateRefreshToken(Long userId, String validRefreshToken) {
RefreshToken refreshToken = refreshTokenRepository.findByUserId(userId);
if(!refreshToken.getToken().equals(validRefreshToken)) {
return false;
}
long now = (new Date()).getTime();
long expired = Long.parseLong(refreshToken.getExpired());
if(now > expired) {
return false;
}
return true;
}
public String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(jwtHeader);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(jwtType)) {
return bearerToken.substring(7);
}
return null;
}
@Setter
@Getter
@Entity
@Table(name = "DEV_USER")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long userId;
@Column(unique = true, nullable = false)
private String email;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String username;
@Column(nullable = false)
private String authority;
}
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.devlog.common.entity.User;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class PrincipalDetails implements UserDetails{
private User user;
public PrincipalDetails (User user) {
this.user = user;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collectors = new ArrayList<>();
for (String role : user.getAuthority().split(",")) {
collectors.add(new SimpleGrantedAuthority(role));
}
return collectors;
}
/**
* 계정 만료 여부 반환
*
* true -> 만료되지 않았음
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 계정 잠금 여부 반환
*
* true -> 잠금되지 않았음
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* 패스워드의 만료 여부 반환
*
* true -> 만료되지 않았음
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 계정 사용 가능 여부 반환
*
* true -> 사용 가능
*/
@Override
public boolean isEnabled() {
return true;
}
public String getAuthority() {
return user.getAuthority();
}
public String getEmail() {
return user.getEmail();
}
public long getUserId() {
return user.getUserId();
}
}
@Setter
@Getter
@Entity
@Table(name = "DEV_RE_TOKEN")
public class RefreshToken {
@Id
private Long userId;
@Column(unique = true, nullable = false)
private String token;
@Column(nullable = false)
private String issue;
@Column(nullable = false)
private String expired;
}
public enum JwtCode {
ACCESS("ACCESS"),
EXPIRED("EXPIRED"),
DENIED("DENIED"),
;
private final String code;
JwtCode(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request
, HttpServletResponse response
, AuthenticationException authException) throws IOException, ServletException {
log.error("URI : {} , MESSAGE : {} , Error : {}" ,request.getRequestURI()
, authException.getMessage()
, HttpServletResponse.SC_UNAUTHORIZED);
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler{
@Override
public void handle(HttpServletRequest request
, HttpServletResponse response
, AccessDeniedException accessDeniedException) throws IOException, ServletException {
log.error("JWT : {}, URI : {}, MESSAGE : {}, Error : {}" , request.getHeader("Authorization")
, request.getRequestURI()
, accessDeniedException.getMessage()
, HttpServletResponse.SC_FORBIDDEN);
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
}
import java.io.IOException;
import java.util.Arrays;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import com.devlog.common.jwt.JwtCode;
import com.devlog.common.jwt.JwtProvider;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter{
private final JwtProvider jwtProvider;
private String[] PERMIT_ALL_RESOURCES;
public JwtAuthenticationFilter (JwtProvider jwtProvider, String ... permitAllResources) {
this.jwtProvider = jwtProvider;
this.PERMIT_ALL_RESOURCES = permitAllResources;
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest
, HttpServletResponse httpServletResponse
, FilterChain filterChain) throws ServletException, IOException {
// Request에서 Access Token 추출
String sAccessToken = jwtProvider.resolveToken(httpServletRequest);
if (sAccessToken == null || !StringUtils.hasText(sAccessToken)){
log.info("Invalid JWT Token : " + httpServletRequest.getServletPath());
httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
}
// Access Token 검증
JwtCode jwtCode = jwtProvider.validateToken(sAccessToken);
switch (jwtCode) {
case ACCESS:
// Access Token에서 인증(Authentication)객체 생성
Authentication authentication = jwtProvider.getAuthentication(sAccessToken);
// security context에 인증 정보 저장
SecurityContextHolder.getContext().setAuthentication(authentication);
break;
case EXPIRED:
log.info("Access token expired");
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); //401
break;
case DENIED:
log.info("Invalid JWT Token");
httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
break;
default:
log.info("Invalid JWT Token");
httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
break;
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
/**
* 필터링에서 제외시키고 싶은 request
*/
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return Arrays.stream(PERMIT_ALL_RESOURCES)
.anyMatch(permit -> new AntPathMatcher().match(permit, request.getRequestURI()));
}
}
private final JwtProvider jwtProvider;
private String[] PERMIT_ALL_RESOURCES;
public JwtAuthenticationFilter (JwtProvider jwtProvider, String ... permitAllResources) {
this.jwtProvider = jwtProvider;
this.PERMIT_ALL_RESOURCES = permitAllResources;
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return Arrays.stream(PERMIT_ALL_RESOURCES)
.anyMatch(permit -> new AntPathMatcher().match(permit, request.getRequestURI()));
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest
, HttpServletResponse httpServletResponse
, FilterChain filterChain) throws ServletException, IOException {
// Request에서 Access Token 추출
String sAccessToken = jwtProvider.resolveToken(httpServletRequest);
if (sAccessToken == null || !StringUtils.hasText(sAccessToken)){
log.info("Invalid JWT Token : " + httpServletRequest.getServletPath());
httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
}
// Access Token 검증
JwtCode jwtCode = jwtProvider.validateToken(sAccessToken);
switch (jwtCode) {
case ACCESS:
// Access Token에서 인증(Authentication)객체 생성
Authentication authentication = jwtProvider.getAuthentication(sAccessToken);
// security context에 인증 정보 저장
SecurityContextHolder.getContext().setAuthentication(authentication);
break;
case EXPIRED:
log.info("Access token expired");
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); //401
break;
case DENIED:
log.info("Invalid JWT Token");
httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
break;
default:
log.info("Invalid JWT Token");
httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
break;
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
Spring Security를 구현하지 않아 위에 설명된 인스턴스들을 구현해도 실행되지는 않을 것이다.
이쯤에서 부분적으로 결과를 보고 가는 게 좋을 것 같아 테스트 결과를 일부 작성한다.
Spring Security 설정 은 다음 포스팅을 확인하기 바란다.
Spring Security - FilterSecurityInterceptor 이해 및 Example (2) | 2024.11.11 |
---|---|
Spring Security + JWT 인증 (2/2) - Spring Security 설정 (29) | 2024.08.21 |
Spring Security 개념 및 Architecture (28) | 2024.08.19 |
[Spring] JWT(Json Web Token) 정리 (35) | 2024.08.15 |
[Spring] Filter Example (36) | 2024.08.14 |
댓글 영역