<!-- 기존에 있는 것 -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 기존의 것을 정확하게 지정 -->
<param-value>/WEB-INF/config/egovframework/springmvc/egov-com-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!--
RESTful 용 :
rest란 이름의 DispatcherServlet 추가 생성
-->
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- servlet.xml을 분리한 후 정확하게 지정 -->
<param-value>/WEB-INF/config/egovframework/springmvc/egov-api-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Aspect Oriented Programming (AOP)는 써야하지만 우아하지 않은 코드, 비지니스 로직들을 줄여주고 가독성을 유지시켜주는데 도움이 된다. 어떤 메소드를 실행하기 전 또는 후에 특정 task를 실행하고 싶다면 AOP를 사용하면 된다. 내부적으로 Spring은 proxy를 사용해서 실제 메소드 실행 클래스를 둘러싼 wrapper를 호출한다
JointPoint : 대상 메소드
PointCut : joint point를 매칭하기 위해 사용하는 predicate
Advice : PointCut call 전/후에 실행할 Code/Task
Aspect : pointcut과 advice의 묶음
Weaving : aspect가 실행되는 시점
About Demo
이번 demo에서는 restful webservice에서 Aspect를 사용하는 방법을 보여준다. 전체 package, 특정 class/method처럼 PointCut을 정의하는 방법에는 여러가지가 있다. 여기서는 AOP기반의 @annotation을 사용한다. 2개의 AOP를 만들어서 , 하나는 메소드의 전/후에 로그를 출력하고 다른 하나는 method의 성능을 계산하고 출력한다. DB 대신 List를 사용한다
Apach Maven은 널리 사용되는 프로젝트 의존성 관리 tool이자 project building tool이다. 지난 몇 년간 Spring Boot는 application 개발을 위한 아주 인기가 많은 프레임워크가 되었다. Spring boot Maven Plugin이 있는데 Maven에서 Spring Boot supoort를 제공한다
application을 JAR or WAR artifact 형태로 Maven 을 이용해서 패키징하고 싶은 때가 있다. 이 때 mvn package를 사용하면 된다. 하지만 Spring Boot Maven Plugin은 repackage goal로 출고되는데 mvn command라고 한다.
가끔 두개의 명령어가 혼란스럽다. 이번 toturial에서는 mvn pckage와 spring-boot:repackage의 차이점에 대해서 설명한다
2. A Spring Boot Application Example
맨 처음 바로 Spring Boot application 을 만든다
@SpringBootApplication
public class SpringBootArtifacts2Application {
public static void main(String[] args) {
SpringApplication.run(SpringBootArtifacts2Application.class, args);
}
}
그리고 application이 빌드되고 기동된다는 것을 검증하기 위해 간단한 REST endpoint를 생성한다
@RestController
public class DemoRestController {
@GetMapping(value = "/welcome")
public ResponseEntity welcomeEndpoint() {
return ResponseEntity.ok("Welcome to Baeldung Spring Boot Demo!");
}
}
3. Maven package Goal
Spring Boot application을 빌드하려면 spring-boot-starter-web 의존성만 있으면된다.
Maven's package goal은 코드를 컴파일하고 패키징한다. 이 예제에서는 JAR format이다
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< com.example:spring-boot-artifacts-2 >-----------------
[INFO] Building spring-boot-artifacts-2 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ spring-boot-artifacts-2 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ spring-boot-artifacts-2 ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ spring-boot-artifacts-2 ---
[INFO] Not copying test resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ spring-boot-artifacts-2 ---
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ spring-boot-artifacts-2 ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ spring-boot-artifacts-2 ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.016 s
[INFO] Finished at: 2021-02-03T01:14:27+09:00
[INFO] ------------------------------------------------------------------------
mvn package 명령어를 실행하고 나면 jar 파일이 생성된 것을 확인할 수 있고 JAR 파일 내부를 살펴보자
위 사진에서 볼 수 있듯이 mvn package 명령어의 결과로 JAR 파일이 만들어졌고 내부에는 resources와 컴파일된 Java class만이 포함되어 있다
실행에 필요한 libs도 없다.
이 JAR 파일을 이용해서 다른 프로젝트에 의존성으로 사용할 수도 있다. 하지만 Spring Boot application이면 이 JAR파일을 "java -jar JAR_FILE" 명령어를 이용해서 기동시키지 못한다. runtime 의존성이 포함되어 있지 않기 때문이다. 예를 들자면 web context를 기동시킬 수 있는 servlet container가 없다.
"java -jar" 명령어를 이용해서 간단하게 실행시킬려면 fat JAR이 필요하다. 이것을 만들기 위해 Spring Boot Maven Plugin이 필요하다
4. The Spring Boot Maven Plugin's repackage Goal
spring-boot:repackage가 무엇을 하는지 알아보자
4.1 Spring Boot Maven Plugin 추가하기
이미 위에서 설명했듯이 기본적으로 적용되어 있다.
4.2 spring-boot:repackage Goal 실행
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< com.example:spring-boot-artifacts-2 >-----------------
[INFO] Building spring-boot-artifacts-2 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ spring-boot-artifacts-2 ---
[INFO] Deleting D:\workspaces\git\spring-boot-artifacts-2\target
[INFO]
[INFO] --- spring-boot-maven-plugin:2.4.2:repackage (default-cli) @ spring-boot-artifacts-2 ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.193 s
[INFO] Finished at: 2021-02-03T01:35:19+09:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.4.2:repackage (default-cli) on project spring-boot-artifacts-2: Execution default-cli of goal org.springframework.boot:spring-boot-maven-plugin:2.4.2:repackage failed: Source file must not be null -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
실패했다. 왜냐하면 spring-boot:repackage goal은 존재하는 JAR or WAR archive를 입력소스로 취하고 project runtime 의존성을 전부 final artifact내에 재패키징한다. 이런 방법으로 재패키징 된 artifact는 "java -jar JAR_FILE.jar" 명령어로 실행이 가능하다
따라서 먼저 JAR 파일을 만들고 그 후에 spring-boot:repackage goal을 실행해야 한다
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< com.example:spring-boot-artifacts-2 >-----------------
[INFO] Building spring-boot-artifacts-2 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ spring-boot-artifacts-2 ---
[INFO] Deleting D:\workspaces\git\spring-boot-artifacts-2\target
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ spring-boot-artifacts-2 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ spring-boot-artifacts-2 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to D:\workspaces\git\spring-boot-artifacts-2\target\classes
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ spring-boot-artifacts-2 ---
[INFO] Not copying test resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ spring-boot-artifacts-2 ---
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ spring-boot-artifacts-2 ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ spring-boot-artifacts-2 ---
[INFO] Building jar: D:\workspaces\git\spring-boot-artifacts-2\target\spring-boot-artifacts-2-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.4.2:repackage (repackage) @ spring-boot-artifacts-2 ---
[INFO] Replacing main artifact with repackaged archive
[INFO]
[INFO] --- spring-boot-maven-plugin:2.4.2:repackage (default-cli) @ spring-boot-artifacts-2 ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.056 s
[INFO] Finished at: 2021-02-03T01:41:21+09:00
[INFO] ------------------------------------------------------------------------
아래 그림에서 볼 수 있듯이 original JAR file과 repackaged JAR file을 볼 수 있다.
JAR 파일 내부를 살펴보자
repackaged JAR 파일을 보면 컴파일된 Java classes와 Spring Boot application을 실행하는데 필요한 모든runtime libraries 가 모두 포함되어 있다. 예를 들어, embedded tomcat library는 BOOT-INF/lib directory에 패키징되어 있다
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<!-- Uncomment this next dependency if you are using JDK 10 or earlier and you also want to use
RSASSA-PSS (PS256, PS384, PS512) algorithms. JDK 11 or later does not require it for those algorithms:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
<scope>runtime</scope>
</dependency>
-->
JDK 10이하의 환경에서 RSASSA-PSS(PS256, PS384, PS512) 알고리즘을 사용하고자 하는 경우 주석부분을 해제하면 된다. JDK 11이상의 경우 자동으로 지원하기 때문에 명시할 필요는 없다.
2020.07.31 현재 https://mvnrepository에는 0.9.1 버전이 명시되어 있다.
Gradle
dependencies {
compile 'io.jsonwebtoken:jjwt-api:0.11.2'
runtime 'io.jsonwebtoken:jjwt-impl:0.11.2',
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
//'org.bouncycastle:bcprov-jdk15on:1.60',
'io.jsonwebtoken:jjwt-jackson:0.11.2' // or 'io.jsonwebtoken:jjwt-gson:0.11.2' for gson
}
Android Projects
안드로이드 프로젝트의 경우 다음의 의존성을 추가하고 코드에서는 Proguard에 따라야 한다
dependencies {
api 'io.jsonwebtoken:jjwt-api:0.11.2'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2'
runtimeOnly('io.jsonwebtoken:jjwt-orgjson:0.11.2') {
exclude group: 'org.json', module: 'json' //provided by Android natively
}
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
//runtimeOnly 'org.bouncycastle:bcprov-jdk15on:1.60'
}
Proguard
-keepattributes InnerClasses
-keep class io.jsonwebtoken.** { *; }
-keepnames class io.jsonwebtoken.* { *; }
-keepnames interface io.jsonwebtoken.* { *; }
-keep class org.bouncycastle.** { *; }
-keepnames class org.bouncycastle.** { *; }
-dontwarn org.bouncycastle.**
JJWT 의존성의 이해
위에서 언급한 의존성은 complie-time 의존이며 그 외 나머지는 runtime 의존이다라는 사실을 명심할 것!
This is because JJWT is designed so you only depend on the APIs that are explicitly designed for you to use in your applications and all other internal implementation details - that can change without warning - are relegated to runtime-only dependencies. This is an extremely important point if you want to ensure stable JJWT usage and upgrades over time:
JJWT는 의미론적으로 jjwt-impl.jar 를 제외하고 나머지 artifact들에 대해 버전 호환성을 제공한다. 즉 jjwt-impl.jar에 대해서는 보장하지 않으며 내부 구현은 어느 순간에 변경된다. jjwt-impl.jar를 compile scope에 넣지 말고 runtime scope로 선언하라
This is done to benefit you: great care goes into curating the jjwt-api .jar and ensuring it contains what you need and remains backwards compatible as much as is possible so you can depend on that safely with compile scope. The runtime jjwt-impl .jar strategy affords the JJWT developers the flexibility to change the internal packages and implementations whenever and however necessary. This helps us implement features, fix bugs, and ship new releases to you more quickly and efficiently.
QuickStart
가장 복잡한 것들은 편리하고 읽기쉬운 builder 기반의 fluent interface 뒤에 존재하며 IDE를 사용하면 자동완성을 지원한다.
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
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.
Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
String jws = Jwts.builder().setSubject("Joe").signWith(key).compact();
registered claim인 sub(subject)에 'Joe'를 가지는 JWT를 build
주의사항 : parseClaimsJws 메소드를 반드시 호출해야 한다. 비슷한 메소드들이 무수히 많은데 잘못 호출하면 UnsupportedJwtException을 던진다.
알아야 할 2가지 항목이 있다. 이전에 사용했던 key는 JWT의 서명을 검증하는데도 사용된다. 검증에 실패하면 SignatureException(JwtException을 확장한)이 던져진다. JWT가 올바르다면 claims를 분석하고 subject에 'Joe'가 설정되어 있는 것을 주장한다.
강렬한 효과를 가진 1줄짜리 코딩을 애용해야만 한다.
만약에 분석이나 서명 검증에 실패하면 어떻게 될까? JwtException을 catch하고 처리해야 한다
try {
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compactJws);
//OK, we can trust this JWT
} catch (JwtException e) {
//don't trust the JWT!
}
Signed JWTs
JWT 명세는 JWT를 서명하는 방법을 제공한다
JWT가 우리가 잘 알고 있는 누군가에 의해 생성되었음을 보장한다
JWT를 서명하고 나서는 JWT를 바꾸거나 변경하지 않았음을 보장한다.
2가지 속성 - authenticity(진본임) and integrity(완전성)-은 JWT에 우리가 신뢰할 수 있는 정보를 포함하고 있다는 것을 보장해 준다. 만약에 authenticity나 integrity 검사에 실패하게 되면, 신뢰할 수 없기 때문에 반려해야 한다
JWT 서명은 어떻게 하는가? 간단하게 읽기 쉬운 pseudocode를 가지고 진행한다
1. JSON 형태의 header와 body('Claim'이라 불리우는)를 가지는 JWT가 있다고 가정한다
Of course, no one would want to do this manually in code, and worse, if you get anything wrong, you could cause security problems or weaknesses. As a result, JJWT was created to handle all of this for you: JJWT completely automates both the creation of JWSs as well as the parsing and verification of JWSs for you.
JJWT를 이용해서 JWS를 어떻게 생성하는지에 대해 보여줬지만 잠시 서명 알고리즘과 Key 그리고 JWT 명세와 관련된 부분에 대해 논의해 보자. 이것들에 대해 이해하는 것은 매우 중요하다.
Signature Algorithms Keys
JWT 명세에는 12가지의 표준 서명 알고리즘을 정의하고 3개의 secret key 알고리즘과 9개의 비대칭키 알고리즘에 대해 명시하고 있다.
HS256: HMAC using SHA-256
HS384: HMAC using SHA-384
HS512: HMAC using SHA-512
ES256: ECDSA using P-256 and SHA-256
ES384: ECDSA using P-384 and SHA-384
ES512: ECDSA using P-521 and SHA-512
RS256: RSASSA-PKCS-v1_5 using SHA-256
RS384: RSASSA-PKCS-v1_5 using SHA-384
RS512: RSASSA-PKCS-v1_5 using SHA-512
PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256
PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384
PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512
이것들은 전부 io.jsonwebtoken.SignatureAlgorithm enum에 정의되어 있다.
이 중에서 가장 중요한 것은 선택한 알고리즘에 대해 충분히 강력한 Key를 사용해야 한다는 것이다.
JJWT가 선택한 서명 알고리즘에 대해 충분히 강력한 key를 사용하게끔 JJWT가 강제한다는 것을 의미한다.
만약, 선택한 알고리즘에 대해 약한 key를 제공하면 JJWT를 거부하고 예외를 던진다
이것은 개발자의 삶을 피곤하게 하기 위함이 아니다. 잔말 말고 반드시 특정 길이 이상의 key를 사용해라
HMAC-SHA
각각의 알고리즘에 대해 필수요구사항은 다음과 같다
HS256(HMAC-SHA-256)의 서명값은 256bits(32 bytes)이며, 32 bytes 이상의 key length를 요구한다
HS384(HMAC-SHA-384)의 서명값은 384bits(48 bytes)이며, 48 bytes 이상의 key length를 요구한다
HS512(HMAC-SHA-512)의 서명값은 512bits(64 bytes)이며, 64 bytes 이상의 key length를 요구한다
RSA
모든 알고리즘에는 최소한 2048 bits 이상이어야만 한다. 이보다 작으면 InvalidKeyException을 던진다
RS256, PS256 : 2048 bits 이상
RS384, PS384 : 3072 bits 이상
RS512, PS512 : 4096 bits 이상
이것들은 JJWT의 제안사항이지 요구사항은 아니다. 모든 RSA 알고리즘에 대해 2048 bits 이상의 key를 적용하면 동작한다.
Elliptic Curve
ES256 : 256 bits 이상
ES384 : 384 bits 이상
ES512 : 512 bits 이상
안전한 Key 생성하기
key 길이에 대해 고민하고 싶지 않은 경우 JJWT는 io.jsonwebtoken.security.Keys utility class를 제공하는 , 선택한 알고리즘에 대해 충분히 안전한 key를 생성해 준다.
Secret Keys
JWT HMAC-SHA 알고리즘에서 충분히 안전한 key를 생성하고자 한다면 Keys.secretKeyFor(SignatureAlgorithm) helper 메소드를 사용하자
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); //or HS384 or HS512
JJWT는 JCA provider's KeyGenerator를 사용해서 주어진 알고리즘에 대해 정확한 최소 길이이 secure-random key를 생성한다.
String jws = Jwts.builder()
.setIssuer("me")
.setSubject("Bob")
.setAudience("you")
.setExpiration(expiration) //a java.util.Date
.setNotBefore(notBefore) //a java.util.Date
.setIssuedAt(new Date()) // for example, now
.setId(UUID.randomUUID()) //just an example id
/// ... etc ...
Custom Claims
표준 claim말고 1개 이상의 custom claims를 설정하려면 JwtBuilder의 claim 메소드를 사용한다
Jws<Claims> jws;
try {
jws = Jwts.parserBuilder() // (1)
.setSigningKey(key) // (2)
.build() // (3)
.parseClaimsJws(jwsString); // (4)
// we can safely trust the JWT
catch (JwtException ex) { // (5)
// we *cannot* use the JWT as intended by its creator
}
결국 이 과정은 서명이 올바르게 된 것인지를 검증하고 claim에 저장된 값을 추출하는 과정이다.
public class MySigningKeyResolver extends SigningKeyResolverAdapter {
@Override
public Key resolveSigningKey(JwsHeader jwsHeader, Claims claims) {
// implement me
}
}
The JwtParser will invoke the resolveSigningKey method after parsing the JWS JSON, but before verifying the jws signature. This allows you to inspect the JwsHeader and Claims arguments for any information that can help you look up the Key to use for verifying that specific jws. This is very powerful for applications with more complex security models that might use different keys at different times or for different users or customers.
어떤 데이터를 검사할 것인가?
JWT 명세는 kid (Key Id) 필드를 이용해서 지원한다.
Key signingKey = getSigningKey();
String keyId = getKeyId(signingKey); //any mechanism you have to associate a key with an ID is fine
String jws = Jwts.builder()
.setHeaderParam(JwsHeader.KEY_ID, keyId) // 1
.signWith(signingKey) // 2
.compact();
파싱하는 과정에서 SigningKeyResolver는 JwsHeader에서 kid 값을 추출한 다음 이를 이용해서 key를 생성한다
public class MySigningKeyResolver extends SigningKeyResolverAdapter {
@Override
public Key resolveSigningKey(JwsHeader jwsHeader, Claims claims) {
//inspect the header or claims, lookup and return the signing key
String keyId = jwsHeader.getKeyId(); //or any other field that you need to inspect
Key key = lookupVerificationKey(keyId); //implement me
return key;
}
}
jwsHeader.getKeyId()를 검사하는 것은 가장 일반적인 방법이다. 임의의 heder 필드를 사용해도 괜찮다.
Claim Assertions
분석하는 과정에서 특정 값을 가지고 있는지 확인하게끔 할 수 있다.
예를 들어, sub(subject)가 존재하는지 검사하고 싶다면 require* 메소드를 사용하면 된다
try {
Jwts.parserBuilder().requireSubject("jsmith").setSigningKey(key).build().parseClaimsJws(s);
} catch(InvalidClaimException ice) {
// the sub field was missing or did not have a 'jsmith' value
}
확인과정에서 해당 key가 존재하지 않는다면 MissingClaimException을, key가 존재하지만 값이 일치하지 않는다면 IncorrectClaimException을 던진다
try {
Jwts.parserBuilder().requireSubject("jsmith").setSigningKey(key).build().parseClaimsJws(s);
} catch(MissingClaimException mce) {
// the parsed JWT did not have the sub field
} catch(IncorrectClaimException ice) {
// the parsed JWT had a sub field, but its value was not equal to 'jsmith'
}
custom claim에 대해서는 require(fieldName, requiredFieldValue) 메소드를 사용하면 된다
try {
Jwts.parserBuilder().require("myfield", "myRequiredValue").setSigningKey(key).build().parseClaimsJws(s);
} catch(InvalidClaimException ice) {
// the 'myfield' field was missing or did not have a 'myRequiredValue' value
}
여기서도 해당 key가 존재하지 않는다면 MissingClaimException을, key가 존재하지만 값이 일치하지 않는다면 IncorrectClaimException을 던진다