반응형
JWT(Json Web Token)이란?
사용자 인증을 위해 인증에 필요한 정보를 토큰에 담아서 암호화시켜 사용하는 인터넷 표준 인증 방식
1. JWT란?
JWT는 Header, Payload, Signature 3 부분으로 구성되어 있다.
- Header : Header에는 JWT의 유형과 해시 알고리즘 등의 메타 데이터를 포함한다.
- 보통 "typ" , "alg" 가 들어가고, JSON형식으로 표현되고, Base64로 인코딩 됩니다.
- Payload : Payload는 Claim 정보를 포함합니다.
- Claim은 토큰에 대한 추가적인 데이터를 나타냅니다. JSON 형식으로 표현되며, Base64로 인코딩 됩니다.
- Signature : Signature은 헤더와 페이로드의 내용을 바탕으로 생성되며, 토큰이 유효하고 변경되지 않았음을 검증하는 역할을 합니다.
2. 코드
1. Build.gradle
implementation 'io.jsonwebtoken:jjwt-api:0.11.1'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.1', 'io.jsonwebtoken:jjwt-jackson:0.11.1'
Spring boot에서 JWT(Json Web Token)을 이용하기 위해 build.gradle에 위의 코드를 추가시켰다.
2. CreateToken(JwtTokenProvider)
public String createAccessToken(String snsId) {
Claims claims = Jwts.claims().setSubject("accessToken");
claims.put("snsId", snsId); // 사용자를 식별하기 위한 값을 넣어주시면 됩니다.
Date currentTime = new Date();
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(currentTime)
.setExpiration(new Date(currentTime.getTime() + accessTokenValidTime))
.signWith(SignatureAlgorithm.HS256, Base64Utils.encodeToString(JWT_SECRET_KEY.getBytes()))
.compact();
}
JwtTokenProvider에서 createAccessToken 메소드를 통해 토큰을 만들었다.
밑의 값이 들어간다. snsId의 Value에는 사용자의 snsId 값이 들어간다.
{
"header": {
"alg": "HS256",
"typ": "JWT"
},
"payload": {
"sub": "accessToken",
"snsId": "<value>",
...
},
"signature": "<signature>"
}
3. ValidateToken(JwtTokenProvider)
public Boolean validateAccessToken(String token) {
try {
Jwts.parserBuilder()
.setSigningKey(Base64Utils.encodeToString(JWT_SECRET_KEY.getBytes()))
.build()
.parseClaimsJws(token).getBody();
return true;
} catch (ExpiredJwtException e) {
throw new CustomException(HttpStatus.UNAUTHORIZED, "토큰이 만료 됐습니다.");
} catch (UnsupportedJwtException e) {
throw new CustomException(HttpStatus.BAD_REQUEST, "토큰을 지원 안합니다.");
} catch (Exception e) {
// 여기에서 예외 메시지를 설정해야 합니다.
throw new CustomException(HttpStatus.INTERNAL_SERVER_ERROR, "토큰 검증 중에 오류가 발생했습니다.");
}
}
미리 정해놓은 SecretKey로 복호화를 한 뒤, ParseClaimsJws에서 토큰 유효성 검사를 한 뒤, 토큰에 문제가 있으면 에러를 반환합니다. 에러가 없다면 True를 반환합니다. (Filter과 연관이 있습니다)
Jws<Claims> parseClaimsJws(String claimsJws)
throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
4. ResolveToken(JwtTokenProvider)
private String retrieveToken(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
Client가 Server에게 보내는 HttpServletRequest에서 Token값을 추출하는 과정입니다.
request의 header가 Authorization이거나 Bearer이면 Token을 추출합니다.
5. Get~~(JwtTokenProvider)
public UsernamePasswordAuthenticationToken getAuthentication(String token) {
//@AuthenticationPrincipal에서 필요한 정보 여기에 담기
String snsId = getsnsIdFromToken(token);
Member member = memberRepository.findBySnsId(snsId)
.orElseThrow(() -> new RuntimeException("Member 를 찾지 못했습니다."));
MemberPrincipal memberPrincipal = new MemberPrincipal(member);
return new UsernamePasswordAuthenticationToken(memberPrincipal, token,
member.getAuthorities());
}
//Token으로부터 snsId 추출
public String getsnsIdFromToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(Base64Utils.encodeToString(JWT_SECRET_KEY.getBytes()))
.build().parseClaimsJws(token)
.getBody()
.get("snsId",
String.class);
}
Token에 저장되어 있는 각종 정보들을 get 하는 함수들입니다.
전체 코드
https://github.com/Chat-ITC/WITH_Server/tree/main/src/main/java/codingFriends_Server/global/auth/jwt
반응형