-
springboot2.7 + JWT + RSA256(openssl)WEB/BACK 2024. 7. 3. 10:36반응형
후,, 인터넷에 deprecated 된 코드들 너무 많아서 직접 올리는 게시물
DEPRECATED 예시 // JWT 토큰 생성 public String createToken(String userPk, List<String> roles, PrivateKey key) { Claims claims = Jwts.claims().setSubject(userPk); // JWT payload 에 저장되는 정보단위 claims.put("roles", roles); // 정보는 key / value 쌍으로 저장된다. Map<String, Object> header = new HashMap<>(); header.put("alg", "RS256"); header.put("typ", "JWT"); Date now = new Date(); return Jwts.builder() .setHeader(header) // 알고리즘과 토큰 타입을 헤더에 넣어줌 .setClaims(claims) // 유저의 이름(userPk)등이 담겨있음 .setIssuedAt(now) // 토큰 발행 시간 정보 iat .setExpiration(new Date(now.getTime() + tokenValidTime)) // set Expire Time 언제까지 유효한지. .signWith(SignatureAlgorithm.RS256, key) // 사용할 암호화 알고리즘과 .compact(); }
signwith 안쓰임, builder 하고 set이런 형식 안쓰임.
참고로 jwt 생성시에 alg가 hs256이 탑재 되어있고 rs256은 약간 더 복잡하다
RSA256 알고리즘 사용하려면 pricate key, public key 두 가지가 필요하다.
키는직접 파일로 떨궈서 사용하는 방법과 java단에서 만드는 방법 두가지가 있다.
1. Getting private key, public key (직접 파일 만들기)
openssl genrsa -out private_key.pem 2048 openssl rsa -pubout -in private_key.pem -out public_key.pem openssl pkcs8 -topk8 -in private_key.pem -inform pem -out private_key_pkcs8.pem -outform pem -nocrypt
^ 위에 명령어를 수행하면 3가지 파일이 만들어진다.
그중에서 private key, public key 를 사용한다. 첫 줄에 2048로 하게되면 256인거고 저 숫자를 변경하면 rsa512 등으로 변경할 수 있다.
비대칭키는 소수와 같아서 6= 2x3 처럼 양쪽이 모두 있어야 복호화가 가능하다.
key pair 를 java에서 만드는법 포스팅 >> https://bluemint.tistory.com/114
2. 파일을 읽어와서 객체로 만든다.
String privateKeyContent = new String(Files.readAllBytes(Paths.get(new FileSystemResource("folder/private_key_pkcs8.pem").getURI()))); String publicKeyContent = new String(Files.readAllBytes(Paths.get(new FileSystemResource("folder/public_key.pem").getURI()))); //System.out.println(privateKeyContent); System.out.println(publicKeyContent); privateKeyContent = privateKeyContent.replaceAll("\\n", "").replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", ""); publicKeyContent = publicKeyContent.replaceAll("\\n", "").replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "");; KeyFactory kf = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyContent)); privateKey = kf.generatePrivate(keySpecPKCS8); X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyContent)); publicKey = (RSAPublicKey) kf.generatePublic(keySpecX509);
만약 키 파일을 resources에 위치시킨다면 이렇게 작성가능
String privateKeyContent = new String(Files.readAllBytes(Paths.get(ClassLoader.getSystemResource("private_key_pkcs8.pem").toURI())));
3. jwt 생성
public String createToken( PrivateKey privateKey) { // 현재 시간 가져오기 LocalDateTime now = LocalDateTime.now(); // 30분 뒤 시간 계산 LocalDateTime thirtyMinutesLater = now.plusMinutes(30); //LocalDateTime thirtyMinutesLater = now.minusMinutes(30); // 30분 뒤 시간을 초로 변환 long secondsSinceEpoch = thirtyMinutesLater.atZone(ZoneId.systemDefault()).toEpochSecond(); // 초를 Date 객체로 변환 Date dateThirtyMinutesLater = new Date(secondsSinceEpoch * 1000); // 결과 출력 System.out.println("현재 시간: " + new Date()); System.out.println("30분 뒤 시간: " + dateThirtyMinutesLater); Map<String, Object> user = new HashMap<>(); user.put("id", "redmon"); user.put("email", "redmon@world.io"); return Jwts.builder().claim("user", user).expiration(dateThirtyMinutesLater) .signWith(privateKey).compact(); }
주의할 점은 expiration 이 '초'라는 것이다. claim의 exp는 optional이며 쓰지 않을시 만료시간이 없다. (=무제한)
4. token validation
rsa 에서는 publickey, token 을 가지고 복호화를 한다.
public boolean validateToken( PublicKey publicKey, String token) { try { Jws<Claims> claims = Jwts.parser().verifyWith(publicKey).build().parseSignedClaims(token); return true; } catch (Exception e) { return false; } }
만약에 토큰 시간이 만료됐거나 알고리즘이 잘못된 경우 Jws<Claims> claims = Jwts.parser().verifyWith(publicKey).build().parseSignedClaims(token); 에서 바로 에러가 발생하게 되지만 따로 exception 처리를 해주고 싶은 경우에는 아래처럼 추가해줄 수 있다.
long exp = (long) claims.getPayload().get("exp"); long currentSeconds = Instant.now().getEpochSecond(); //alg이름이 RS256아닌경우 에러 if(!claims.getHeader().get("alg").toString().equals("RS256")) { return false; } if(exp > currentSeconds) { return true; }else { return false; }
5. claim 정보 출력
public Claims extractAllClaims( PublicKey publicKey,String token) { return Jwts.parser().verifyWith(publicKey).build().parseSignedClaims(token).getPayload(); }
반응형'WEB > BACK' 카테고리의 다른 글
spring cloud config (server,client,watcher,java) 구현하기 1 (0) 2024.07.24 RSA in JAVA , rsa256 key 생성 (0) 2024.07.03 springboot2.7 ver 최상단 디렉토리 변경 (0) 2024.06.25 spring security error - io.jsonwebtoken.io.JacksonSerializer (0) 2024.06.18 Dockerfile이름 변경시 build 방법 (0) 2024.05.31