JJWT는 JVM 및 Android에서 JSON 웹 토큰(JWT) 및 JSON 웹 키(JWK)를 생성하고 확인하기 위한 가장 쉽게 사용하고 이해하는 라이브러리를 목표로 합니다.
JJWT는 JOSE Working Group RFC 사양만을 기반으로 하는 순수 Java 구현입니다.
RFC 7519: JSON 웹 토큰(JWT)
RFC 7515: JSON 웹 서명(JWS)
RFC 7516: JSON 웹 암호화(JWE)
RFC 7517: JSON 웹 키(JWK)
RFC 7518: JSON 웹 알고리즘(JWA)
RFC 7638: JSON 웹 키 지문
RFC 9278: JSON 웹 키 지문 URI
RFC 7797: JWS 인코딩되지 않은 페이로드 옵션
RFC 8037: Edwards Curve 알고리즘 및 JWK
Les Hazlewood가 만들었으며 기여자 커뮤니티에서 지원하고 유지 관리합니다.
JJWT는 Apache 2.0 라이센스 조건에 따른 오픈 소스입니다.
PublicKey
toString()
안전모든 Java 7+ JDK 및 Android에서 완벽하게 작동합니다.
자동 보안 모범 사례 및 어설션
배우고 읽기 쉬운 API
편리하고 읽기 쉬운 유창한 인터페이스, 코드를 빠르게 작성하기 위한 IDE 자동 완성에 적합
구현된 모든 기능에 대해 완전히 RFC 사양을 준수하고 RFC 지정 테스트 벡터에 대해 테스트되었습니다.
약 1,700개에 달하는 테스트와 100% 테스트 코드 적용 범위를 적용하여 안정적으로 구현합니다. 전체 코드베이스의 모든 단일 메서드, 명령문 및 조건부 분기 변형이 테스트되고 모든 빌드에 전달되어야 합니다.
모든 표준 JWS 알고리즘을 사용하여 디지털 서명된 컴팩트 JWT(일명 JWS) 생성, 구문 분석 및 확인:
식별자 | 서명 알고리즘 |
---|---|
| SHA-256을 사용하는 HMAC |
| SHA-384를 사용하는 HMAC |
| SHA-512를 사용하는 HMAC |
| P-256 및 SHA-256을 사용하는 ECDSA |
| P-384 및 SHA-384를 사용하는 ECDSA |
| P-521 및 SHA-512를 사용하는 ECDSA |
| SHA-256을 사용하는 RSASSA-PKCS-v1_5 |
| SHA-384를 사용하는 RSASSA-PKCS-v1_5 |
| SHA-512를 사용하는 RSASSA-PKCS-v1_5 |
| SHA-256 및 MGF1과 SHA-256을 사용하는 RSASSA-PSS 1 |
| SHA-384 및 MGF1과 SHA-384를 사용하는 RSASSA-PSS 1 |
| SHA-512 및 MGF1과 SHA-512를 사용하는 RSASSA-PSS 1 |
| Edwards 곡선 디지털 서명 알고리즘 2 |
1. 런타임 클래스 경로에 Java 11 또는 호환 가능한 JCA 공급자(예: BouncyCastle)가 필요합니다.
2 . 런타임 클래스 경로에 Java 15 또는 호환 가능한 JCA 공급자(예: BouncyCastle)가 필요합니다.
모든 표준 JWE 암호화 알고리즘을 사용하여 암호화된 컴팩트 JWT(일명 JWE) 생성, 구문 분석 및 해독:
식별자 | 암호화 알고리즘 |
---|---|
| AES_128_CBC_HMAC_SHA_256 인증 암호화 알고리즘 |
| AES_192_CBC_HMAC_SHA_384 인증 암호화 알고리즘 |
| AES_256_CBC_HMAC_SHA_512 인증 암호화 알고리즘 |
| 128비트 키 1을 사용하는 AES GCM |
| 192비트 키 1을 사용하는 AES GCM |
| 256비트 키 1을 사용하는 AES GCM |
1 . 런타임 클래스 경로에 Java 8 또는 호환 가능한 JCA 제공자(예: BouncyCastle)가 필요합니다.
JWE 암호화 및 암호 해독 키를 얻기 위한 모든 키 관리 알고리즘:
식별자 | 키 관리 알고리즘 |
---|---|
| RSAES-PKCS1-v1_5 |
| 기본 매개변수를 사용하는 RSAES OAEP |
| SHA-256 및 SHA-256과 함께 MGF1을 사용하는 RSAES OAEP |
| 128비트 키를 사용하여 기본 초기 값으로 AES 키 래핑 |
| 192비트 키를 사용하여 기본 초기 값으로 AES 키 래핑 |
| 256비트 키를 사용하여 기본 초기 값으로 AES 키 래핑 |
| 공유 대칭 키를 CEK로 직접 사용 |
| Concat KDF를 사용한 타원 곡선 Diffie-Hellman 임시 정적 키 계약 |
| "A128KW"로 래핑된 Concat KDF 및 CEK를 사용하는 ECDH-ES |
| "A192KW"로 래핑된 Concat KDF 및 CEK를 사용하는 ECDH-ES |
| "A256KW"로 래핑된 Concat KDF 및 CEK를 사용하는 ECDH-ES |
| 128비트 키를 사용하는 AES GCM으로 키 래핑 1 |
| 192비트 키를 사용하는 AES GCM으로 키 래핑 1 |
| 256비트 키를 사용하는 AES GCM으로 키 래핑 1 |
| HMAC SHA-256 및 "A128KW" 래핑이 포함된 PBES2 1 |
| HMAC SHA-384 및 "A192KW" 래핑이 포함된 PBES2 1 |
| HMAC SHA-512 및 "A256KW" 래핑이 포함된 PBES2 1 |
1 . 런타임 클래스 경로에 Java 8 또는 호환 가능한 JCA 제공자(예: BouncyCastle)가 필요합니다.
기본 Java Key
유형을 사용하여 모든 표준 JWA 키 형식으로 JWK(JSON 웹 키) 생성, 구문 분석 및 확인:
JWK 키 형식 | 자바 Key 유형 | JJWT Jwk 유형 |
---|---|---|
대칭키 | | |
타원 곡선 공개 키 | | |
타원 곡선 개인 키 | | |
RSA 공개 키 | | |
RSA 개인 키 | | |
XDH 개인 키 | | |
XDH 개인 키 | | |
EdDSA 공개 키 | | |
EdDSA 개인 키 | | |
1 . 런타임 클래스 경로에 Java 15 또는 호환 가능한 JCA 공급자(예: BouncyCastle)가 필요합니다.
2 . 런타임 클래스 경로에 Java 15 또는 호환 가능한 JCA 공급자(예: BouncyCastle)가 필요합니다.
등 사양을 뛰어넘는 편의성 강화
JWE뿐만 아니라 모든 대규모 JWT에 대한 페이로드 압축
클레임 어설션(특정 값 필요)
호환되는 JSON 구문 분석기(예: Jackson)를 사용할 때 POJO 마샬링 및 역마샬링 요청
원하는 JWA 알고리즘을 기반으로 보안 키 생성
그리고 더…
비컴팩트 직렬화 및 구문 분석.
이 기능은 향후 릴리스에서 구현될 수 있습니다. 커뮤니티 기여를 환영합니다!
JJWT 사용에 문제가 있는 경우 질문하기 전에 먼저 이 페이지의 설명서를 읽어보세요. 우리는 JJWT의 문서가 견고하고, 목차로 분류되고, 각 릴리스에 대해 최신 상태인지 확인하기 위해 매우 열심히 노력합니다.
문서나 API JavaDoc이 충분하지 않고 유용성에 대한 질문이 있거나 어떤 것에 대해 혼란스러운 경우 여기에 질문하십시오. 하지만:
질문을 하기 위해 GitHub 이슈를 생성하지 마세요.
우리는 GitHub 이슈를 사용하여 JJWT의 디자인 및/또는 코드베이스를 변경해야 하는 실행 가능한 작업을 추적합니다. 사용성에 대한 질문이 있는 경우 대신 여기에 질문해 주세요. 필요한 경우 문제로 전환해 드릴 수 있습니다.
JJWT의 코드베이스에 대한 실행 가능한 작업을 나타내지 않는 GitHub 문제가 생성되면 즉시 종료됩니다.
사용성에 대한 질문이 없고 합법적인 버그나 기능 요청이 있다고 생각되는 경우 먼저 여기에서 논의하시기 바랍니다. 먼저 빠른 검색을 통해 귀하와 관련된 기존 토론이 이미 존재하는지 확인하고 필요한 경우 기존 토론에 참여하세요.
버그 수정에 도움을 주거나 새 기능을 직접 구현하고 싶다면 작업을 시작하기 전에 다음 기여 섹션을 읽어보세요.
JJWT 핵심 코드(문서, JavaDoc, 오타, 테스트 사례 등) 이외의 사항을 수정하는 간단한 풀 요청은 항상 높이 평가되며 빠르게 병합될 가능성이 높습니다. 보내주세요!
그러나 JJWT의 기능이나 핵심 코드를 변경하고 싶거나 필요하다고 생각하는 경우 작업을 시작하기 전에 새로운 JJWT 토론을 시작하고 원하는 변경 사항에 대해 먼저 논의하지 않고 풀 요청을 발행하지 마십시오.
귀하의 진지하고 진심으로 감사한 끌어오기 요청이 프로젝트 목표, 디자인 기대치 또는 계획된 기능과 일치하지 않을 수 있다면 거부하는 것은 부끄러운 일입니다. 슬프게도 과거에는 대규모 PR이 프로젝트 또는 디자인 기대치와 일치하지 않았기 때문에 거부해야 했습니다. 이는 모두 PR 작성자가 솔루션 작업을 수행하기 전에 먼저 팀에 확인하지 않았기 때문입니다.
따라서 먼저 새로운 JJWT 토론을 만들어 논의하십시오. 그런 다음 토론을 문제로 쉽게 전환한 다음 PR이 타당한지(또는 어떻게) 확인할 수 있습니다. 감사합니다!
도움을 주고 싶지만 어디서부터 시작해야 할지 모르겠다면, 구인 문제 페이지를 방문하여 원하는 문제를 선택하세요. 문제 댓글에서 질문에 대해 기꺼이 토론하고 답변해 드리겠습니다.
그 중 하나라도 마음에 들지 않는다면 걱정하지 마세요! 풀 리퀘스트 기여에 관한 위의 주의 사항을 바탕으로 귀하가 제공하고 싶은 도움을 주시면 감사하겠습니다. 확실하지 않은 경우 먼저 토론하거나 질문하십시오. :)
JWT(JSON 웹 토큰)는 간결하고 안전한 방식으로 정보를 전송하기 위한 범용 텍스트 기반 메시징 형식입니다. 대중적인 믿음과는 달리 JWT는 웹에서 ID 토큰을 보내고 받는 데에만 유용하지 않습니다. 가장 일반적인 사용 사례라 할지라도 말이죠. JWT는 모든 유형의 데이터에 대한 메시지로 사용될 수 있습니다.
가장 간단한 형태의 JWT는 두 부분으로 구성됩니다.
payload
라고 하는 JWT 내의 기본 데이터
header
라고 하는 payload
및 메시지 자체에 대한 메타데이터를 나타내는 이름/값 쌍이 있는 JSON Object
입니다.
JWT payload
는 문자열, 이미지, 문서 등과 같이 바이트 배열로 표현될 수 있는 모든 것이 될 수 있습니다.
그러나 JWT header
JSON Object
이기 때문에 JWT payload
도 JSON Object
일 수 있다는 것이 합리적입니다. 많은 경우 개발자는 사용자나 컴퓨터 또는 유사한 ID 개념에 대한 데이터를 나타내는 JSON을 payload
로 선호합니다. 이러한 방식으로 사용되면 payload
JSON Claims
개체라고 하며 해당 개체 내의 각 이름/값 쌍을 claim
이라고 합니다. '클레임' 내의 각 정보는 ID에 대한 것입니다.
그리고 정체성에 대해 무언가를 '주장'하는 것이 유용하지만 실제로는 누구나 그렇게 할 수 있습니다. 중요한 것은 해당 주장이 신뢰할 수 있는 사람이나 컴퓨터에서 나온 것인지 확인하여 이를 신뢰한다는 것입니다.
JWT의 좋은 특징은 다양한 방법으로 보안을 유지할 수 있다는 것입니다. JWT는 암호화 방식으로 서명되거나(JWS라고 함) 암호화될 수 있습니다(JWE). 이는 JWT에 강력한 검증 가능성 계층을 추가합니다. JWS 또는 JWE 수신자는 서명을 확인하거나 암호를 해독하여 신뢰하는 사람이 보낸 정보라는 높은 수준의 확신을 가질 수 있습니다. JWT가 신원 주장과 같은 보안 정보를 보내고 받는 데 적합한 선택이 되는 것은 이러한 검증 가능성 기능 때문입니다.
마지막으로 사람이 쉽게 읽을 수 있도록 공백이 있는 JSON은 좋지만 매우 효율적인 메시지 형식은 아닙니다. 따라서 JWT는 최소한의 표현(기본적으로 Base64URL 인코딩 문자열)으로 압축 (심지어 압축)될 수 있으므로 HTTP 헤더나 URL과 같이 웹에서 보다 효율적으로 전송될 수 있습니다.
payload
와 header
있으면 웹 전송을 위해 어떻게 압축되며 최종 JWT는 실제로 어떤 모습일까요? 의사 코드를 사용하여 프로세스의 단순화된 버전을 살펴보겠습니다.
JSON header
와 간단한 텍스트 메시지 페이로드가 있는 JWT가 있다고 가정합니다.
헤더
{ "alg": "없음" }
유효 탑재량
지능의 진정한 표시는 지식이 아니라 상상력이다.
JSON에서 불필요한 공백을 모두 제거합니다.
String header = ' {"alg":"none"} '
String payload = ' The true sign of intelligence is not knowledge but imagination. '
UTF-8 바이트와 Base64URL 인코딩을 각각 가져옵니다.
String encodedHeader = base64URLEncode( header . getBytes( " UTF-8 " ) )
String encodedPayload = base64URLEncode( payload . getBytes( " UTF-8 " ) )
마침표('.') 문자를 사용하여 인코딩된 헤더와 클레임을 결합합니다.
String compact = encodedHeader + ' . ' + encodedPayload + ' . '
연결된 최종 compact
JWT 문자열은 다음과 같습니다.
eyJhbGciOiJub25lIn0.VGhlIHRydWUgc2lnbiBvZiBpbnRlbGxpZ2VuY2UgaXMgbm90IGtub3dsZWRnZSBidXQgaW1hZ2luYXRpb24u.
보안이 관련되지 않았기 때문에 이를 '비보호' JWT라고 합니다. 제3자가 변경할 수 없도록 JWT를 '보호'하는 디지털 서명이나 암호화가 없습니다.
최소한 우리가 감지하지 않고는 누구도 데이터를 변경하지 않는다는 것을 보장할 수 있도록 압축 양식에 디지털 서명을 하려면 다음에 표시된 몇 가지 단계를 더 수행해야 합니다.
일반 텍스트 페이로드 대신 다음 예에서는 아마도 가장 일반적인 유형의 페이로드(특정 ID에 대한 정보가 포함된 JSON 클레임 Object
사용합니다. 또한 JWT에 디지털 서명을 하여 우리가 모르는 사이에 제3자가 이를 변경할 수 없도록 할 것입니다.
JSON header
와 클레임 payload
있다고 가정합니다.
헤더
{
"alg" : " HS256 "
}
유효 탑재량
{
"sub" : " Joe "
}
이 경우 header
HS256
(SHA-256을 사용하는 HMAC) 알고리즘이 JWT에 암호화 서명하는 데 사용됨을 나타냅니다. 또한 payload
JSON 개체에는 값이 Joe
인 sub
단일 클레임이 있습니다.
사양에는 등록된 청구항(Registered Claims)이라는 표준 청구항이 많이 있으며 sub
('주제'에 대한)는 그 중 하나입니다.
두 JSON 객체 모두에서 불필요한 공백을 모두 제거합니다.
String header = ' {"alg":"HS256"} '
String claims = ' {"sub":"Joe"} '
UTF-8 바이트와 Base64URL 인코딩을 각각 가져옵니다.
String encodedHeader = base64URLEncode( header . getBytes( " UTF-8 " ) )
String encodedClaims = base64URLEncode( claims . getBytes( " UTF-8 " ) )
인코딩된 헤더와 클레임을 마침표 '.'로 연결합니다. 구분 기호:
String concatenated = encodedHeader + ' . ' + encodedClaims
선택한 서명 알고리즘(여기에서는 HMAC-SHA-256 사용)과 함께 충분히 강력한 암호화 비밀 또는 개인 키를 사용하고 연결된 문자열에 서명합니다.
SecretKey key = getMySecretKey()
byte [] signature = hmacSha256( concatenated, key )
서명은 항상 바이트 배열이므로 서명을 Base64URL로 인코딩하고 마침표 '.'를 사용하여 concatenated
문자열에 결합합니다. 구분 기호:
String compact = concatenated + ' . ' + base64URLEncode( signature )
그리고 거기에 최종 compact
문자열은 다음과 같습니다.
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.1KP0SsvENi7Uz1oQc07aXTL7kpQG5jBNIybqr60AlD4
이를 'JWS'( 서명된 JWT의 약자)라고 합니다.
물론, 누구도 코드에서 수동으로 이 작업을 수행하고 싶어하지 않을 것이며, 더 나쁜 것은 잘못된 것이 있으면 심각한 보안 문제와 약점이 발생할 수 있다는 것입니다. 결과적으로 JJWT는 이 모든 것을 처리하기 위해 만들어졌습니다. JJWT는 JWS 생성과 JWS 구문 분석 및 확인을 완전히 자동화합니다.
지금까지 우리는 보호되지 않은 JWT와 암호화되어 서명된 JWT('JWS'라고 함)를 살펴보았습니다. 이 두 가지 모두에 내재된 것 중 하나는 그 안에 있는 모든 정보를 누구나 볼 수 있다는 것입니다. 즉, 헤더와 페이로드의 모든 데이터가 공개적으로 표시됩니다. JWS는 데이터가 다른 사람에 의해 변경되지 않았는지 확인만 할 뿐, 다른 사람이 데이터를 보는 것을 막지는 않습니다. 대부분의 경우, 그 안에 있는 데이터는 민감한 정보가 아니기 때문에 괜찮습니다.
하지만 민감한 정보로 간주 되는 정보(누군가의 우편 주소, 주민등록번호, 은행 계좌 번호 등)를 JWT에 표시해야 한다면 어떻게 될까요?
이러한 경우 줄여서 'JWE'라고 하는 완전히 암호화된 JWT가 필요합니다. JWE는 암호화를 사용하여 페이로드가 완전히 암호화 되고 인증된 상태로 유지되므로 승인되지 않은 당사자가 감지되지 않고 데이터를 볼 수 없으며 데이터를 변경할 수 없습니다. 특히 JWE 사양에서는 데이터를 완전히 암호화하고 보호하기 위해 인증된 암호화와 관련 데이터 알고리즘을 사용해야 합니다.
AEAD 알고리즘에 대한 전체 개요는 이 문서의 범위를 벗어납니다. 그러나 다음은 이러한 알고리즘을 활용하는 최종 압축 JWE의 예입니다(줄바꿈은 가독성을 위한 것입니다).
eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0. 6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ. AxY8DCtDaGlsbGljb3RoZQ. KDlTtXchhZTGufMYmOYGS4HffxPSURfmqCHXaI9wOGY. U0m_YmjN04DJvceFICbCVQ
다음으로 프로젝트에 JJWT를 설치하는 방법을 다룬 다음 위험한 문자열 조작 대신 JJWT의 훌륭하고 유창한 API를 사용하여 JWT, JWS 및 JWE를 빠르고 안전하게 구축하는 방법을 살펴보겠습니다.
선호하는 Maven 호환 빌드 도구를 사용하여 Maven Central에서 종속성을 가져옵니다.
JDK 프로젝트 또는 Android 프로젝트로 작업하는 경우 종속성이 약간 다를 수 있습니다.
Android가 아닌 JDK 프로젝트를 빌드하는 경우 다음 종속성을 정의해야 합니다.
< dependency >
< groupId >io.jsonwebtoken</ groupId >
< artifactId >jjwt-api</ artifactId >
< version >0.12.6</ version >
</ dependency >
< dependency >
< groupId >io.jsonwebtoken</ groupId >
< artifactId >jjwt-impl</ artifactId >
< version >0.12.6</ version >
< scope >runtime</ scope >
</ dependency >
< dependency >
< groupId >io.jsonwebtoken</ groupId >
< artifactId >jjwt-jackson</ artifactId > <!-- or jjwt-gson if Gson is preferred -->
< version >0.12.6</ version >
< scope >runtime</ scope >
</ dependency >
<!-- Uncomment this next dependency if you are using:
- JDK 10 or earlier, and you want to use RSASSA-PSS (PS256, PS384, PS512) signature algorithms.
- JDK 10 or earlier, and you want to use EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.
- JDK 14 or earlier, and you want to use EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.
It is unnecessary for these algorithms on JDK 15 or later.
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId> or bcprov-jdk15to18 on JDK 7
<version>1.76</version>
<scope>runtime</scope>
</dependency>
-->
dependencies {
implementation ' io.jsonwebtoken:jjwt-api:0.12.6 '
runtimeOnly ' io.jsonwebtoken:jjwt-impl:0.12.6 '
runtimeOnly ' io.jsonwebtoken:jjwt-jackson:0.12.6 ' // or 'io.jsonwebtoken:jjwt-gson:0.12.6' for gson
/*
Uncomment this next dependency if you are using:
- JDK 10 or earlier, and you want to use RSASSA-PSS (PS256, PS384, PS512) signature algorithms.
- JDK 10 or earlier, and you want to use EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.
- JDK 14 or earlier, and you want to use EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.
It is unnecessary for these algorithms on JDK 15 or later.
*/
// runtimeOnly 'org.bouncycastle:bcprov-jdk18on:1.76' // or bcprov-jdk15to18 on JDK 7
}
Android 프로젝트는 다음 종속성, Proguard 제외 및 선택적 BouncyCastle Provider
정의하려고 합니다.
프로젝트에 종속성을 추가합니다.
dependencies {
api( ' io.jsonwebtoken:jjwt-api:0.12.6 ' )
runtimeOnly( ' io.jsonwebtoken:jjwt-impl:0.12.6 ' )
runtimeOnly( ' io.jsonwebtoken:jjwt-orgjson:0.12.6 ' ) {
exclude( group : ' org.json ' , module : ' json ' ) // provided by Android natively
}
/*
Uncomment this next dependency if you want to use:
- RSASSA-PSS (PS256, PS384, PS512) signature algorithms.
- EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.
- EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.
** AND ALSO ensure you enable the BouncyCastle provider as shown below **
*/
// implementation('org.bouncycastle:bcprov-jdk18on:1.76') // or bcprov-jdk15to18 for JDK 7
}
다음 Android Proguard 제외 규칙을 사용할 수 있습니다.
-Keepattributes InnerClasses -keep 클래스 io.jsonwebtoken.** { *; } -keepnames 클래스 io.jsonwebtoken.* { *; } -keepnames 인터페이스 io.jsonwebtoken.* { *; } -keep 클래스 org.bouncycastle.** { *; } -keepnames 클래스 org.bouncycastle.** { *; } - org.bouncycastle을 경고하지 마세요.**
JWT RSASSA-PSS 알고리즘(예: PS256
, PS384
및 PS512
), EdECDH( X25512
또는 X448
) 타원 곡선 Diffie-Hellman 암호화, EdDSA( Ed25519
또는 Ed448
) 서명 알고리즘을 사용하려는 경우 또는 Android를 보장하려는 경우 애플리케이션이 업데이트된 버전의 BouncyCastle을 실행 중이라면 다음을 수행해야 합니다.
종속성 섹션에서 위에 설명된 대로 BouncyCastle 종속성의 주석 처리를 제거합니다.
기존 Android 맞춤 BC
공급자를 업데이트된 공급자로 교체합니다.
공급자 등록은 애플리케이션 수명 주기 초기 에 수행되어야 하며, 바람직하게는 애플리케이션의 기본 Activity
클래스에서 정적 초기화 블록으로 수행되어야 합니다. 예를 들어:
class MainActivity : AppCompatActivity () {
companion object {
init {
Security .removeProvider( " BC " ) // remove old/legacy Android-provided BC provider
Security .addProvider( BouncyCastleProvider ()) // add 'real'/correct BC provider
}
}
// ... etc ...
}
위의 JJWT 종속성 선언에는 모두 컴파일 시간 종속성이 하나만 있고 나머지는 런타임 종속성으로 선언되었습니다.
이는 JJWT가 애플리케이션에서 사용하도록 명시적으로 설계된 API에만 의존하도록 설계되었으며 경고 없이 변경될 수 있는 기타 모든 내부 구현 세부 사항은 런타임 전용 종속성으로 강등되기 때문입니다. 시간이 지남에 따라 안정적인 JJWT 사용 및 업그레이드를 보장하려는 경우 이는 매우 중요한 사항입니다.
JJWT는 |
이는 귀하에게 이익이 되도록 수행됩니다. jjwt-api
.jar을 관리하고 여기에 필요한 내용이 포함되어 있는지 확인하고 가능한 한 이전 버전과의 호환성을 유지하여 컴파일 범위에서 안전하게 의존할 수 있도록 세심한 주의를 기울입니다. 런타임 jjwt-impl
.jar 전략은 JJWT 개발자에게 필요할 때마다 내부 패키지와 구현을 변경할 수 있는 유연성을 제공합니다. 이를 통해 기능을 구현하고, 버그를 수정하고, 새 릴리스를 보다 빠르고 효율적으로 제공할 수 있습니다.
대부분의 복잡성은 편리하고 읽기 쉬운 빌더 기반 유창한 인터페이스 뒤에 숨겨져 있으며, IDE 자동 완성을 사용하여 코드를 빠르게 작성하는 데 적합합니다. 예는 다음과 같습니다.
import io . jsonwebtoken . Jwts ;
import io . jsonwebtoken . security . Keys ;
import java . security . Key ;
// We need a signing key, so we'll create one just for this example. Usually
// the key would be read from your application configuration instead.
SecretKey key = Jwts . SIG . HS256 . key (). build ();
String jws = Jwts . builder (). subject ( "Joe" ). signWith ( key ). compact ();
얼마나 쉬웠나요!?
이 경우 우리는 다음과 같습니다.
등록된 클레임 sub
(제목)가 Joe
로 설정된 JWT를 구축합니다 . 우리는 그때
HMAC-SHA-256 알고리즘에 적합한 키를 사용하여 JWT 에 서명합니다 . 마지막으로 우리는
최종 String
형식으로 압축합니다 . 서명된 JWT를 'JWS'라고 합니다.
결과 jws
문자열은 다음과 같습니다.
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.1KP0SsvENi7Uz1oQc07aXTL7kpQG5jBNIybqr60AlD4
이제 JWT를 확인해 보겠습니다(예상 서명과 일치하지 않는 JWT는 항상 삭제해야 합니다).
assert Jwts . parser (). verifyWith ( key ). build (). parseSignedClaims ( jws ). getPayload (). getSubject (). equals ( "Joe" );
여기에는 두 가지 일이 진행되고 있습니다. 이전의 key
JWT의 서명을 확인하는 데 사용됩니다. JWT 확인에 실패하면 SignatureException
( JwtException
확장)이 발생합니다. JWT가 확인되었다고 가정하면 클레임을 구문 분석하고 해당 주제가 Joe
로 설정되어 있다고 주장합니다. 강력한 효과를 주는 한 줄짜리 코드를 좋아해야 합니다!
메모 | 유형이 안전한 JWT: 유형이 안전한 |
하지만 구문 분석이나 서명 확인에 실패하면 어떻게 될까요? JwtException
포착하고 그에 따라 대응할 수 있습니다.
try {
Jwts . parser (). verifyWith ( key ). build (). parseSignedClaims ( compactJws );
//OK, we can trust this JWT
} catch ( JwtException e ) {
//don't trust the JWT!
}
이제 JWT를 생성하고 구문 분석하는 방법을 빠르게 살펴보았으므로 JJWT의 API를 심층적으로 다루겠습니다.
다음과 같이 JWT를 생성합니다.
Jwts.builder()
메서드를 사용하여 JwtBuilder
인스턴스를 만듭니다.
선택적으로 원하는 대로 header
매개변수를 설정합니다.
페이로드 콘텐츠 또는 클레임을 설정하려면 빌더 메서드를 호출하세요.
JWT를 디지털 서명하거나 암호화하려면 선택적으로 signWith
또는 encryptWith
메소드를 호출하십시오.
compact()
메서드를 호출하여 결과 압축 JWT 문자열을 생성합니다.
예를 들어:
String jwt = Jwts . builder () // (1)
. header () // (2) optional
. keyId ( "aKeyId" )
. and ()
. subject ( "Bob" ) // (3) JSON Claims, or
//.content(aByteArray, "text/plain") // any byte[] content, with media type
. signWith ( signingKey ) // (4) if signing, or
//.encryptWith(key, keyAlg, encryptionAlg) // if encrypting
. compact (); // (5)
JWT payload
byte[]
콘텐츠( content
통해) 또는 JSON 클레임(예: subject
, claims
등)일 수 있지만 둘 다일 수는 없습니다.
디지털 서명( signWith
) 또는 암호화( encryptWith
)를 사용할 수 있지만 둘 다 사용할 수는 없습니다.
보호되지 않은 JWT : |
JWT 헤더는 JWT payload
와 관련된 콘텐츠, 형식 및 암호화 작업에 대한 메타데이터를 제공하는 JSON Object
입니다. JJWT는 전체 헤더 및/또는 여러 개별 헤더 매개변수(이름/값 쌍)를 설정하는 다양한 방법을 제공합니다.
하나 이상의 JWT 헤더 매개변수(이름/값 쌍)를 설정하는 가장 쉽고 권장되는 방법은 JwtBuilder
의 header()
빌더를 원하는 대로 사용한 다음 해당 and()
메서드를 호출하여 추가 구성을 위해 JwtBuilder
로 다시 돌아가는 것입니다. . 예를 들어:
String jwt = Jwts . builder ()
. header () // <----
. keyId ( "aKeyId" )
. x509Url ( aUri )
. add ( "someName" , anyValue )
. add ( mapValues )