mirror of https://github.com/jwtk/jjwt.git
Merge pull request #4 from jwtk/jwt-builder-claims-convenience-methods
Jwt builder claims convenience methods
This commit is contained in:
commit
1be528b58b
28
README.md
28
README.md
|
@ -33,9 +33,7 @@ Random random = new SecureRandom();
|
||||||
byte[] key = new byte[64];
|
byte[] key = new byte[64];
|
||||||
random.nextBytes(key);
|
random.nextBytes(key);
|
||||||
|
|
||||||
Claims claims = Jwts.claims().setIssuer("Me").setSubject("Joe");
|
String compactJwt = Jwts.builder().setIssuer("Me").setSubject("Joe").signWith(HS256, key).compact();
|
||||||
|
|
||||||
String compactJwt = Jwts.builder().setClaims(claims).signWith(HS256, key).compact();
|
|
||||||
```
|
```
|
||||||
|
|
||||||
How easy was that!?
|
How easy was that!?
|
||||||
|
@ -45,7 +43,7 @@ Now let's verify the JWT (you should always discard JWTs that don't match an exp
|
||||||
```java
|
```java
|
||||||
Jwt jwt = Jwts.parser().setSigningKey(key).parse(compactJwt);
|
Jwt jwt = Jwts.parser().setSigningKey(key).parse(compactJwt);
|
||||||
|
|
||||||
assert jwt.getClaims().getSubject().equals("Joe");
|
assert ((Claims)jwt.getBody()).getSubject().equals("Joe");
|
||||||
```
|
```
|
||||||
|
|
||||||
You have to love one-line code snippets in Java!
|
You have to love one-line code snippets in Java!
|
||||||
|
@ -88,6 +86,28 @@ try {
|
||||||
|
|
||||||
These feature sets will be implemented in a future release when possible. Community contributions are welcome!
|
These feature sets will be implemented in a future release when possible. Community contributions are welcome!
|
||||||
|
|
||||||
|
## Release Notes
|
||||||
|
|
||||||
|
### 0.2
|
||||||
|
|
||||||
|
#### More convenient Claims building
|
||||||
|
|
||||||
|
This release adds convenience methods to the `JwtBuilder` interface so you can set claims directly on the builder without having to create a separate Claims instance/builder, reducing the amount of code you have to write. For example, this:
|
||||||
|
|
||||||
|
```java
|
||||||
|
Claims claims = Jwts.claims().setIssuer("Me").setSubject("Joe");
|
||||||
|
|
||||||
|
String compactJwt = Jwts.builder().setClaims(claims).signWith(HS256, key).compact();
|
||||||
|
```
|
||||||
|
|
||||||
|
can now be written as:
|
||||||
|
|
||||||
|
```java
|
||||||
|
String compactJwt = Jwts.builder().setIssuer("Me").setSubject("Joe").signWith(HS256, key).compact();
|
||||||
|
```
|
||||||
|
|
||||||
|
A Claims instance based on the specified claims will be created and set as the JWT's payload automatically.
|
||||||
|
|
||||||
<a name="olderJackson"></a>
|
<a name="olderJackson"></a>
|
||||||
#### Already using an older Jackson dependency?
|
#### Already using an older Jackson dependency?
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ import java.util.Map;
|
||||||
*
|
*
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public interface Claims extends Map<String, Object> {
|
public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
|
||||||
|
|
||||||
/** JWT {@code Issuer} claims parameter name: <code>"iss"</code> */
|
/** JWT {@code Issuer} claims parameter name: <code>"iss"</code> */
|
||||||
public static final String ISSUER = "iss";
|
public static final String ISSUER = "iss";
|
||||||
|
@ -70,12 +70,9 @@ public interface Claims extends Map<String, Object> {
|
||||||
String getIssuer();
|
String getIssuer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.1">
|
* {@inheritDoc}
|
||||||
* <code>iss</code></a> (issuer) value. A {@code null} value will remove the property from the JSON map.
|
|
||||||
*
|
|
||||||
* @param iss the JWT {@code iss} value or {@code null} to remove the property from the JSON map.
|
|
||||||
* @return the {@code Claims} instance for method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
Claims setIssuer(String iss);
|
Claims setIssuer(String iss);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -87,12 +84,9 @@ public interface Claims extends Map<String, Object> {
|
||||||
String getSubject();
|
String getSubject();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.2">
|
* {@inheritDoc}
|
||||||
* <code>sub</code></a> (subject) value. A {@code null} value will remove the property from the JSON map.
|
|
||||||
*
|
|
||||||
* @param sub the JWT {@code sub} value or {@code null} to remove the property from the JSON map.
|
|
||||||
* @return the {@code Claims} instance for method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
Claims setSubject(String sub);
|
Claims setSubject(String sub);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,12 +98,9 @@ public interface Claims extends Map<String, Object> {
|
||||||
String getAudience();
|
String getAudience();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.3">
|
* {@inheritDoc}
|
||||||
* <code>aud</code></a> (audience) value. A {@code null} value will remove the property from the JSON map.
|
|
||||||
*
|
|
||||||
* @param aud the JWT {@code aud} value or {@code null} to remove the property from the JSON map.
|
|
||||||
* @return the {@code Claims} instance for method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
Claims setAudience(String aud);
|
Claims setAudience(String aud);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,14 +114,9 @@ public interface Claims extends Map<String, Object> {
|
||||||
Date getExpiration();
|
Date getExpiration();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.4">
|
* {@inheritDoc}
|
||||||
* <code>exp</code></a> (expiration) timestamp. A {@code null} value will remove the property from the JSON map.
|
|
||||||
*
|
|
||||||
* <p>A JWT obtained after this timestamp should not be used.</p>
|
|
||||||
*
|
|
||||||
* @param exp the JWT {@code exp} value or {@code null} to remove the property from the JSON map.
|
|
||||||
* @return the {@code Claims} instance for method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
Claims setExpiration(Date exp);
|
Claims setExpiration(Date exp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,14 +130,9 @@ public interface Claims extends Map<String, Object> {
|
||||||
Date getNotBefore();
|
Date getNotBefore();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.5">
|
* {@inheritDoc}
|
||||||
* <code>nbf</code></a> (not before) timestamp. A {@code null} value will remove the property from the JSON map.
|
|
||||||
*
|
|
||||||
* <p>A JWT obtained before this timestamp should not be used.</p>
|
|
||||||
*
|
|
||||||
* @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the JSON map.
|
|
||||||
* @return the {@code Claims} instance for method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
Claims setNotBefore(Date nbf);
|
Claims setNotBefore(Date nbf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,14 +146,9 @@ public interface Claims extends Map<String, Object> {
|
||||||
Date getIssuedAt();
|
Date getIssuedAt();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.6">
|
* {@inheritDoc}
|
||||||
* <code>iat</code></a> (issued at) timestamp. A {@code null} value will remove the property from the JSON map.
|
|
||||||
*
|
|
||||||
* <p>The value is the timestamp when the JWT was created.</p>
|
|
||||||
*
|
|
||||||
* @param iat the JWT {@code iat} value or {@code null} to remove the property from the JSON map.
|
|
||||||
* @return the {@code Claims} instance for method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
Claims setIssuedAt(Date iat);
|
Claims setIssuedAt(Date iat);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -189,16 +165,9 @@ public interface Claims extends Map<String, Object> {
|
||||||
String getId();
|
String getId();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.7">
|
* {@inheritDoc}
|
||||||
* <code>jti</code></a> (JWT ID) value. A {@code null} value will remove the property from the JSON map.
|
|
||||||
*
|
|
||||||
* <p>This value is a CaSe-SenSiTiVe unique identifier for the JWT. If specified, this value MUST be assigned in a
|
|
||||||
* manner that ensures that there is a negligible probability that the same value will be accidentally
|
|
||||||
* assigned to a different data object. The ID can be used to prevent the JWT from being replayed.</p>
|
|
||||||
*
|
|
||||||
* @param jti the JWT {@code jti} value or {@code null} to remove the property from the JSON map.
|
|
||||||
* @return the {@code Claims} instance for method chaining.
|
|
||||||
*/
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
Claims setId(String jti);
|
Claims setId(String jti);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 jsonwebtoken.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.jsonwebtoken;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutation (modifications) to a {@link io.jsonwebtoken.Claims Claims} instance.
|
||||||
|
*
|
||||||
|
* @param <T> the type of mutator
|
||||||
|
* @see io.jsonwebtoken.JwtBuilder
|
||||||
|
* @see io.jsonwebtoken.Claims
|
||||||
|
* @since 0.2
|
||||||
|
*/
|
||||||
|
public interface ClaimsMutator<T extends ClaimsMutator> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.1">
|
||||||
|
* <code>iss</code></a> (issuer) value. A {@code null} value will remove the property from the JSON map.
|
||||||
|
*
|
||||||
|
* @param iss the JWT {@code iss} value or {@code null} to remove the property from the JSON map.
|
||||||
|
* @return the {@code Claims} instance for method chaining.
|
||||||
|
*/
|
||||||
|
T setIssuer(String iss);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.2">
|
||||||
|
* <code>sub</code></a> (subject) value. A {@code null} value will remove the property from the JSON map.
|
||||||
|
*
|
||||||
|
* @param sub the JWT {@code sub} value or {@code null} to remove the property from the JSON map.
|
||||||
|
* @return the {@code Claims} instance for method chaining.
|
||||||
|
*/
|
||||||
|
T setSubject(String sub);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.3">
|
||||||
|
* <code>aud</code></a> (audience) value. A {@code null} value will remove the property from the JSON map.
|
||||||
|
*
|
||||||
|
* @param aud the JWT {@code aud} value or {@code null} to remove the property from the JSON map.
|
||||||
|
* @return the {@code Claims} instance for method chaining.
|
||||||
|
*/
|
||||||
|
T setAudience(String aud);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.4">
|
||||||
|
* <code>exp</code></a> (expiration) timestamp. A {@code null} value will remove the property from the JSON map.
|
||||||
|
*
|
||||||
|
* <p>A JWT obtained after this timestamp should not be used.</p>
|
||||||
|
*
|
||||||
|
* @param exp the JWT {@code exp} value or {@code null} to remove the property from the JSON map.
|
||||||
|
* @return the {@code Claims} instance for method chaining.
|
||||||
|
*/
|
||||||
|
T setExpiration(Date exp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.5">
|
||||||
|
* <code>nbf</code></a> (not before) timestamp. A {@code null} value will remove the property from the JSON map.
|
||||||
|
*
|
||||||
|
* <p>A JWT obtained before this timestamp should not be used.</p>
|
||||||
|
*
|
||||||
|
* @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the JSON map.
|
||||||
|
* @return the {@code Claims} instance for method chaining.
|
||||||
|
*/
|
||||||
|
T setNotBefore(Date nbf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.6">
|
||||||
|
* <code>iat</code></a> (issued at) timestamp. A {@code null} value will remove the property from the JSON map.
|
||||||
|
*
|
||||||
|
* <p>The value is the timestamp when the JWT was created.</p>
|
||||||
|
*
|
||||||
|
* @param iat the JWT {@code iat} value or {@code null} to remove the property from the JSON map.
|
||||||
|
* @return the {@code Claims} instance for method chaining.
|
||||||
|
*/
|
||||||
|
T setIssuedAt(Date iat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.7">
|
||||||
|
* <code>jti</code></a> (JWT ID) value. A {@code null} value will remove the property from the JSON map.
|
||||||
|
*
|
||||||
|
* <p>This value is a CaSe-SenSiTiVe unique identifier for the JWT. If specified, this value MUST be assigned in a
|
||||||
|
* manner that ensures that there is a negligible probability that the same value will be accidentally
|
||||||
|
* assigned to a different data object. The ID can be used to prevent the JWT from being replayed.</p>
|
||||||
|
*
|
||||||
|
* @param jti the JWT {@code jti} value or {@code null} to remove the property from the JSON map.
|
||||||
|
* @return the {@code Claims} instance for method chaining.
|
||||||
|
*/
|
||||||
|
T setId(String jti);
|
||||||
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
package io.jsonwebtoken;
|
package io.jsonwebtoken;
|
||||||
|
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,7 +24,7 @@ import java.util.Map;
|
||||||
*
|
*
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public interface JwtBuilder {
|
public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
||||||
|
|
||||||
//replaces any existing header with the specified header.
|
//replaces any existing header with the specified header.
|
||||||
|
|
||||||
|
@ -100,6 +101,223 @@ public interface JwtBuilder {
|
||||||
*/
|
*/
|
||||||
JwtBuilder setClaims(Map<String, Object> claims);
|
JwtBuilder setClaims(Map<String, Object> claims);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.1">
|
||||||
|
* <code>iss</code></a> (issuer) value. A {@code null} value will remove the property from the Claims.
|
||||||
|
*
|
||||||
|
* <p>This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set
|
||||||
|
* the Claims {@link Claims#setIssuer(String) issuer} field with the specified value. This allows you to write
|
||||||
|
* code like this:</p>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* String jwt = Jwts.builder().setIssuer("Joe").compact();
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>instead of this:</p>
|
||||||
|
* <pre>
|
||||||
|
* Claims claims = Jwts.claims().setIssuer("Joe");
|
||||||
|
* String jwt = Jwts.builder().setClaims(claims).compact();
|
||||||
|
* </pre>
|
||||||
|
* <p>if desired.</p>
|
||||||
|
*
|
||||||
|
* @param iss the JWT {@code iss} value or {@code null} to remove the property from the Claims map.
|
||||||
|
* @return the builder instance for method chaining.
|
||||||
|
* @since 0.2
|
||||||
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
|
JwtBuilder setIssuer(String iss);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.2">
|
||||||
|
* <code>sub</code></a> (subject) value. A {@code null} value will remove the property from the Claims.
|
||||||
|
*
|
||||||
|
* <p>This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set
|
||||||
|
* the Claims {@link Claims#setSubject(String) subject} field with the specified value. This allows you to write
|
||||||
|
* code like this:</p>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* String jwt = Jwts.builder().setSubject("Me").compact();
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>instead of this:</p>
|
||||||
|
* <pre>
|
||||||
|
* Claims claims = Jwts.claims().setSubject("Me");
|
||||||
|
* String jwt = Jwts.builder().setClaims(claims).compact();
|
||||||
|
* </pre>
|
||||||
|
* <p>if desired.</p>
|
||||||
|
*
|
||||||
|
* @param sub the JWT {@code sub} value or {@code null} to remove the property from the Claims map.
|
||||||
|
* @return the builder instance for method chaining.
|
||||||
|
* @since 0.2
|
||||||
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
|
JwtBuilder setSubject(String sub);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.3">
|
||||||
|
* <code>aud</code></a> (audience) value. A {@code null} value will remove the property from the Claims.
|
||||||
|
*
|
||||||
|
* <p>This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set
|
||||||
|
* the Claims {@link Claims#setAudience(String) audience} field with the specified value. This allows you to write
|
||||||
|
* code like this:</p>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* String jwt = Jwts.builder().setAudience("You").compact();
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>instead of this:</p>
|
||||||
|
* <pre>
|
||||||
|
* Claims claims = Jwts.claims().setSubject("You");
|
||||||
|
* String jwt = Jwts.builder().setClaims(claims).compact();
|
||||||
|
* </pre>
|
||||||
|
* <p>if desired.</p>
|
||||||
|
*
|
||||||
|
* @param aud the JWT {@code aud} value or {@code null} to remove the property from the Claims map.
|
||||||
|
* @return the builder instance for method chaining.
|
||||||
|
* @since 0.2
|
||||||
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
|
JwtBuilder setAudience(String aud);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.4">
|
||||||
|
* <code>exp</code></a> (expiration) value. A {@code null} value will remove the property from the Claims.
|
||||||
|
*
|
||||||
|
* <p>A JWT obtained after this timestamp should not be used.</p>
|
||||||
|
*
|
||||||
|
* <p>This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set
|
||||||
|
* the Claims {@link Claims#setExpiration(java.util.Date) expiration} field with the specified value. This allows
|
||||||
|
* you to write code like this:</p>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* String jwt = Jwts.builder().setExpiration(new Date(System.currentTimeMillis() + 3600000)).compact();
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>instead of this:</p>
|
||||||
|
* <pre>
|
||||||
|
* Claims claims = Jwts.claims().setExpiration(new Date(System.currentTimeMillis() + 3600000));
|
||||||
|
* String jwt = Jwts.builder().setClaims(claims).compact();
|
||||||
|
* </pre>
|
||||||
|
* <p>if desired.</p>
|
||||||
|
*
|
||||||
|
* @param exp the JWT {@code exp} value or {@code null} to remove the property from the Claims map.
|
||||||
|
* @return the builder instance for method chaining.
|
||||||
|
* @since 0.2
|
||||||
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
|
JwtBuilder setExpiration(Date exp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.5">
|
||||||
|
* <code>nbf</code></a> (not before) value. A {@code null} value will remove the property from the Claims.
|
||||||
|
*
|
||||||
|
* <p>A JWT obtained before this timestamp should not be used.</p>
|
||||||
|
*
|
||||||
|
* <p>This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set
|
||||||
|
* the Claims {@link Claims#setNotBefore(java.util.Date) notBefore} field with the specified value. This allows
|
||||||
|
* you to write code like this:</p>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* String jwt = Jwts.builder().setNotBefore(new Date()).compact();
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>instead of this:</p>
|
||||||
|
* <pre>
|
||||||
|
* Claims claims = Jwts.claims().setNotBefore(new Date());
|
||||||
|
* String jwt = Jwts.builder().setClaims(claims).compact();
|
||||||
|
* </pre>
|
||||||
|
* <p>if desired.</p>
|
||||||
|
*
|
||||||
|
* @param nbf the JWT {@code nbf} value or {@code null} to remove the property from the Claims map.
|
||||||
|
* @return the builder instance for method chaining.
|
||||||
|
* @since 0.2
|
||||||
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
|
JwtBuilder setNotBefore(Date nbf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.6">
|
||||||
|
* <code>iat</code></a> (issued at) value. A {@code null} value will remove the property from the Claims.
|
||||||
|
*
|
||||||
|
* <p>The value is the timestamp when the JWT was created.</p>
|
||||||
|
*
|
||||||
|
* <p>This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set
|
||||||
|
* the Claims {@link Claims#setIssuedAt(java.util.Date) issuedAt} field with the specified value. This allows
|
||||||
|
* you to write code like this:</p>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* String jwt = Jwts.builder().setIssuedAt(new Date()).compact();
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>instead of this:</p>
|
||||||
|
* <pre>
|
||||||
|
* Claims claims = Jwts.claims().setIssuedAt(new Date());
|
||||||
|
* String jwt = Jwts.builder().setClaims(claims).compact();
|
||||||
|
* </pre>
|
||||||
|
* <p>if desired.</p>
|
||||||
|
*
|
||||||
|
* @param iat the JWT {@code iat} value or {@code null} to remove the property from the Claims map.
|
||||||
|
* @return the builder instance for method chaining.
|
||||||
|
* @since 0.2
|
||||||
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
|
JwtBuilder setIssuedAt(Date iat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the JWT Claims <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.7">
|
||||||
|
* <code>jti</code></a> (JWT ID) value. A {@code null} value will remove the property from the Claims.
|
||||||
|
*
|
||||||
|
* <p>The value is a CaSe-SenSiTiVe unique identifier for the JWT. If specified, this value MUST be assigned in a
|
||||||
|
* manner that ensures that there is a negligible probability that the same value will be accidentally
|
||||||
|
* assigned to a different data object. The ID can be used to prevent the JWT from being replayed.</p>
|
||||||
|
*
|
||||||
|
* <p>This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set
|
||||||
|
* the Claims {@link Claims#setId(String) id} field with the specified value. This allows
|
||||||
|
* you to write code like this:</p>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* String jwt = Jwts.builder().setId(UUID.randomUUID().toString()).compact();
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>instead of this:</p>
|
||||||
|
* <pre>
|
||||||
|
* Claims claims = Jwts.claims().setIssuedAt(UUID.randomUUID().toString());
|
||||||
|
* String jwt = Jwts.builder().setClaims(claims).compact();
|
||||||
|
* </pre>
|
||||||
|
* <p>if desired.</p>
|
||||||
|
*
|
||||||
|
* @param jti the JWT {@code jti} (id) value or {@code null} to remove the property from the Claims map.
|
||||||
|
* @return the builder instance for method chaining.
|
||||||
|
* @since 0.2
|
||||||
|
*/
|
||||||
|
@Override //only for better/targeted JavaDoc
|
||||||
|
JwtBuilder setId(String jti);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a custom JWT Claims parameter value. A {@code null} value will remove the property from the Claims.
|
||||||
|
*
|
||||||
|
* <p>This is a convenience method. It will first ensure a Claims instance exists as the JWT body and then set the
|
||||||
|
* named property on the Claims instance using the Claims {@link Claims#put(Object, Object) put} method. This allows
|
||||||
|
* you to write code like this:</p>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* String jwt = Jwts.builder().claim("aName", "aValue").compact();
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>instead of this:</p>
|
||||||
|
* <pre>
|
||||||
|
* Claims claims = Jwts.claims().put("aName", "aValue");
|
||||||
|
* String jwt = Jwts.builder().setClaims(claims).compact();
|
||||||
|
* </pre>
|
||||||
|
* <p>if desired.</p>
|
||||||
|
*
|
||||||
|
* @param name the JWT Claims property name
|
||||||
|
* @param value the value to set for the specified Claims property name
|
||||||
|
* @return the builder instance for method chaining.
|
||||||
|
* @since 0.2
|
||||||
|
*/
|
||||||
|
JwtBuilder claim(String name, Object value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
|
* Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
|
||||||
*
|
*
|
||||||
|
|
|
@ -29,9 +29,11 @@ import io.jsonwebtoken.impl.crypto.JwtSigner;
|
||||||
import io.jsonwebtoken.lang.Assert;
|
import io.jsonwebtoken.lang.Assert;
|
||||||
import io.jsonwebtoken.lang.Collections;
|
import io.jsonwebtoken.lang.Collections;
|
||||||
import io.jsonwebtoken.lang.Objects;
|
import io.jsonwebtoken.lang.Objects;
|
||||||
|
import io.jsonwebtoken.lang.Strings;
|
||||||
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -117,6 +119,13 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Claims ensureClaims() {
|
||||||
|
if (this.claims == null) {
|
||||||
|
this.claims = new DefaultClaims();
|
||||||
|
}
|
||||||
|
return this.claims;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JwtBuilder setClaims(Claims claims) {
|
public JwtBuilder setClaims(Claims claims) {
|
||||||
this.claims = claims;
|
this.claims = claims;
|
||||||
|
@ -129,13 +138,118 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtBuilder setIssuer(String iss) {
|
||||||
|
if (Strings.hasText(iss)) {
|
||||||
|
ensureClaims().setIssuer(iss);
|
||||||
|
} else {
|
||||||
|
if (this.claims != null) {
|
||||||
|
claims.setIssuer(iss);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtBuilder setSubject(String sub) {
|
||||||
|
if (Strings.hasText(sub)) {
|
||||||
|
ensureClaims().setSubject(sub);
|
||||||
|
} else {
|
||||||
|
if (this.claims != null) {
|
||||||
|
claims.setSubject(sub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtBuilder setAudience(String aud) {
|
||||||
|
if (Strings.hasText(aud)) {
|
||||||
|
ensureClaims().setAudience(aud);
|
||||||
|
} else {
|
||||||
|
if (this.claims != null) {
|
||||||
|
claims.setAudience(aud);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtBuilder setExpiration(Date exp) {
|
||||||
|
if (exp != null) {
|
||||||
|
ensureClaims().setExpiration(exp);
|
||||||
|
} else {
|
||||||
|
if (this.claims != null) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
this.claims.setExpiration(exp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtBuilder setNotBefore(Date nbf) {
|
||||||
|
if (nbf != null) {
|
||||||
|
ensureClaims().setNotBefore(nbf);
|
||||||
|
} else {
|
||||||
|
if (this.claims != null) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
this.claims.setNotBefore(nbf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtBuilder setIssuedAt(Date iat) {
|
||||||
|
if (iat != null) {
|
||||||
|
ensureClaims().setIssuedAt(iat);
|
||||||
|
} else {
|
||||||
|
if (this.claims != null) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
this.claims.setIssuedAt(iat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtBuilder setId(String jti) {
|
||||||
|
if (Strings.hasText(jti)) {
|
||||||
|
ensureClaims().setId(jti);
|
||||||
|
} else {
|
||||||
|
if (this.claims != null) {
|
||||||
|
claims.setId(jti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtBuilder claim(String name, Object value) {
|
||||||
|
Assert.hasText(name, "Claim property name cannot be null or empty.");
|
||||||
|
if (this.claims == null) {
|
||||||
|
if (value != null) {
|
||||||
|
ensureClaims().put(name, value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (value == null) {
|
||||||
|
this.claims.remove(name);
|
||||||
|
} else {
|
||||||
|
this.claims.put(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String compact() {
|
public String compact() {
|
||||||
if (payload == null && claims == null) {
|
if (payload == null && Collections.isEmpty(claims)) {
|
||||||
throw new IllegalStateException("Either 'payload' or 'claims' must be specified.");
|
throw new IllegalStateException("Either 'payload' or 'claims' must be specified.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload != null && claims != null) {
|
if (payload != null && !Collections.isEmpty(claims)) {
|
||||||
throw new IllegalStateException("Both 'payload' and 'claims' cannot both be specified. Choose either one.");
|
throw new IllegalStateException("Both 'payload' and 'claims' cannot both be specified. Choose either one.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,11 +47,13 @@ public class JwtMap implements Map<String,Object> {
|
||||||
} else if (v instanceof Date) {
|
} else if (v instanceof Date) {
|
||||||
return (Date) v;
|
return (Date) v;
|
||||||
} else if (v instanceof Number) {
|
} else if (v instanceof Number) {
|
||||||
int seconds = ((Number) v).intValue();
|
long seconds = ((Number) v).longValue();
|
||||||
return new Date(seconds * 1000);
|
long millis = seconds * 1000;
|
||||||
|
return new Date(millis);
|
||||||
} else if (v instanceof String) {
|
} else if (v instanceof String) {
|
||||||
int seconds = Integer.parseInt((String) v);
|
long seconds = Long.parseLong((String) v);
|
||||||
return new Date(seconds * 1000);
|
long millis = seconds * 1000;
|
||||||
|
return new Date(millis);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Cannot convert '" + name + "' value [" + v + "] to Date instance.");
|
throw new IllegalStateException("Cannot convert '" + name + "' value [" + v + "] to Date instance.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,128 @@ class JwtsTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConvenienceIssuer() {
|
||||||
|
String compact = Jwts.builder().setIssuer("Me").compact();
|
||||||
|
Claims claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
assertEquals claims.getIssuer(), "Me"
|
||||||
|
|
||||||
|
compact = Jwts.builder().setSubject("Joe")
|
||||||
|
.setIssuer("Me") //set it
|
||||||
|
.setIssuer(null) //null should remove it
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
assertNull claims.getIssuer()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConvenienceSubject() {
|
||||||
|
String compact = Jwts.builder().setSubject("Joe").compact();
|
||||||
|
Claims claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
assertEquals claims.getSubject(), "Joe"
|
||||||
|
|
||||||
|
compact = Jwts.builder().setIssuer("Me")
|
||||||
|
.setSubject("Joe") //set it
|
||||||
|
.setSubject(null) //null should remove it
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
assertNull claims.getSubject()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConvenienceAudience() {
|
||||||
|
String compact = Jwts.builder().setAudience("You").compact();
|
||||||
|
Claims claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
assertEquals claims.getAudience(), "You"
|
||||||
|
|
||||||
|
compact = Jwts.builder().setIssuer("Me")
|
||||||
|
.setAudience("You") //set it
|
||||||
|
.setAudience(null) //null should remove it
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
assertNull claims.getAudience()
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date dateWithOnlySecondPrecision() {
|
||||||
|
return dateWithOnlySecondPrecision(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date dateWithOnlySecondPrecision(long millis) {
|
||||||
|
long seconds = millis / 1000;
|
||||||
|
long secondOnlyPrecisionMillis = seconds * 1000;
|
||||||
|
return new Date(secondOnlyPrecisionMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConvenienceExpiration() {
|
||||||
|
Date now = dateWithOnlySecondPrecision() //jwt exp only supports *seconds* since epoch:
|
||||||
|
String compact = Jwts.builder().setExpiration(now).compact();
|
||||||
|
Claims claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
def claimedDate = claims.getExpiration()
|
||||||
|
assertEquals claimedDate, now
|
||||||
|
|
||||||
|
compact = Jwts.builder().setIssuer("Me")
|
||||||
|
.setExpiration(now) //set it
|
||||||
|
.setExpiration(null) //null should remove it
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
assertNull claims.getExpiration()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConvenienceNotBefore() {
|
||||||
|
Date now = dateWithOnlySecondPrecision() //jwt exp only supports *seconds* since epoch:
|
||||||
|
String compact = Jwts.builder().setNotBefore(now).compact();
|
||||||
|
Claims claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
def claimedDate = claims.getNotBefore()
|
||||||
|
assertEquals claimedDate, now
|
||||||
|
|
||||||
|
compact = Jwts.builder().setIssuer("Me")
|
||||||
|
.setNotBefore(now) //set it
|
||||||
|
.setNotBefore(null) //null should remove it
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
assertNull claims.getNotBefore()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConvenienceIssuedAt() {
|
||||||
|
Date now = dateWithOnlySecondPrecision() //jwt exp only supports *seconds* since epoch:
|
||||||
|
String compact = Jwts.builder().setIssuedAt(now).compact();
|
||||||
|
Claims claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
def claimedDate = claims.getIssuedAt()
|
||||||
|
assertEquals claimedDate, now
|
||||||
|
|
||||||
|
compact = Jwts.builder().setIssuer("Me")
|
||||||
|
.setIssuedAt(now) //set it
|
||||||
|
.setIssuedAt(null) //null should remove it
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
assertNull claims.getIssuedAt()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConvenienceId() {
|
||||||
|
String id = UUID.randomUUID().toString();
|
||||||
|
String compact = Jwts.builder().setId(id).compact();
|
||||||
|
Claims claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
assertEquals claims.getId(), id
|
||||||
|
|
||||||
|
compact = Jwts.builder().setIssuer("Me")
|
||||||
|
.setId(id) //set it
|
||||||
|
.setId(null) //null should remove it
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
claims = Jwts.parser().parse(compact).body as Claims
|
||||||
|
assertNull claims.getId()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testHS256() {
|
void testHS256() {
|
||||||
testHmac(SignatureAlgorithm.HS256);
|
testHmac(SignatureAlgorithm.HS256);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package io.jsonwebtoken
|
package io.jsonwebtoken
|
||||||
|
|
||||||
import org.testng.annotations.Test
|
import org.testng.annotations.Test
|
||||||
|
|
||||||
import static org.testng.Assert.*
|
import static org.testng.Assert.*
|
||||||
|
|
||||||
class SignatureAlgorithmTest {
|
class SignatureAlgorithmTest {
|
||||||
|
@ -41,4 +42,38 @@ class SignatureAlgorithmTest {
|
||||||
void testUnrecognizedAlgorithmName() {
|
void testUnrecognizedAlgorithmName() {
|
||||||
SignatureAlgorithm.forName('whatever')
|
SignatureAlgorithm.forName('whatever')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIsHmac() {
|
||||||
|
for(SignatureAlgorithm alg : SignatureAlgorithm.values()) {
|
||||||
|
if (alg.name().startsWith("HS")) {
|
||||||
|
assertTrue alg.isHmac()
|
||||||
|
} else {
|
||||||
|
assertFalse alg.isHmac()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIsRsa() {
|
||||||
|
for(SignatureAlgorithm alg : SignatureAlgorithm.values()) {
|
||||||
|
if (alg.getDescription().startsWith("RSASSA")) {
|
||||||
|
assertTrue alg.isRsa()
|
||||||
|
} else {
|
||||||
|
assertFalse alg.isRsa()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIsEllipticCurve() {
|
||||||
|
for(SignatureAlgorithm alg : SignatureAlgorithm.values()) {
|
||||||
|
if (alg.name().startsWith("ES")) {
|
||||||
|
assertTrue alg.isEllipticCurve()
|
||||||
|
} else {
|
||||||
|
assertFalse alg.isEllipticCurve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue