Skip to content

Commit 29a33c3

Browse files
committed
Made BaseController to provide uniform exception response. Made JwtResponse for uniform responses. Added ensureType method to enforce type on registered claims.
1 parent df9e4d7 commit 29a33c3

5 files changed

Lines changed: 143 additions & 42 deletions

File tree

jjwt/src/main/java/io/jsonwebtoken/jjwtfun/JJWTFunApplication.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
@SpringBootApplication
77
public class JJWTFunApplication {
88

9-
public static void main(String[] args) {
10-
SpringApplication.run(JJWTFunApplication.class, args);
11-
}
9+
public static void main(String[] args) {
10+
SpringApplication.run(JJWTFunApplication.class, args);
11+
}
1212
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.jsonwebtoken.jjwtfun.controller;
2+
3+
import io.jsonwebtoken.JwtException;
4+
import io.jsonwebtoken.MalformedJwtException;
5+
import io.jsonwebtoken.SignatureException;
6+
import io.jsonwebtoken.jjwtfun.model.JwtResponse;
7+
import org.springframework.http.HttpStatus;
8+
import org.springframework.web.bind.annotation.ExceptionHandler;
9+
import org.springframework.web.bind.annotation.ResponseStatus;
10+
11+
public class BaseController {
12+
13+
@ResponseStatus(HttpStatus.BAD_REQUEST)
14+
@ExceptionHandler({SignatureException.class, MalformedJwtException.class, JwtException.class})
15+
public JwtResponse exception(Exception e) {
16+
JwtResponse response = new JwtResponse();
17+
response.setStatus(JwtResponse.Status.ERROR);
18+
response.setMessage(e.getMessage());
19+
response.setExceptionType(e.getClass().getName());
20+
21+
return response;
22+
}
23+
}
Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package io.jsonwebtoken.jjwtfun.controller;
22

33
import io.jsonwebtoken.JwtBuilder;
4+
import io.jsonwebtoken.JwtException;
45
import io.jsonwebtoken.Jwts;
56
import io.jsonwebtoken.SignatureAlgorithm;
7+
import io.jsonwebtoken.jjwtfun.model.JwtResponse;
68
import org.springframework.beans.factory.annotation.Value;
79
import org.springframework.web.bind.annotation.RequestBody;
810
import org.springframework.web.bind.annotation.RequestMapping;
@@ -16,47 +18,55 @@
1618
import static org.springframework.web.bind.annotation.RequestMethod.POST;
1719

1820
@RestController
19-
public class DynamicJWTController {
21+
public class DynamicJWTController extends BaseController {
2022
@Value("#{ @environment['jjwtfun.secret'] ?: 'secret' }")
2123
String secret;
2224

2325
@RequestMapping(value = "/dynamic-builder-general", method = POST)
24-
public String dynamicBuilderGeneric(@RequestBody Map<String, Object> claims) throws UnsupportedEncodingException {
25-
return Jwts.builder()
26+
public JwtResponse dynamicBuilderGeneric(@RequestBody Map<String, Object> claims) throws UnsupportedEncodingException {
27+
String jws = Jwts.builder()
2628
.setClaims(claims)
2729
.signWith(
2830
SignatureAlgorithm.HS256,
2931
secret.getBytes("UTF-8")
3032
)
3133
.compact();
34+
return new JwtResponse(jws);
3235
}
3336

3437
@RequestMapping(value = "/dynamic-builder-specific", method = POST)
35-
public String dynamicBuilderSpecific(@RequestBody Map<String, Object> claims) throws UnsupportedEncodingException {
38+
public JwtResponse dynamicBuilderSpecific(@RequestBody Map<String, Object> claims) throws UnsupportedEncodingException {
3639
JwtBuilder builder = Jwts.builder();
3740

3841
claims.forEach((key, value) -> {
3942
switch (key) {
4043
case "iss":
41-
builder.setIssuer((String)value);
44+
ensureType(key, value, String.class);
45+
builder.setIssuer((String) value);
4246
break;
4347
case "sub":
44-
builder.setSubject((String)value);
48+
ensureType(key, value, String.class);
49+
builder.setSubject((String) value);
4550
break;
4651
case "aud":
47-
builder.setAudience((String)value);
52+
ensureType(key, value, String.class);
53+
builder.setAudience((String) value);
4854
break;
4955
case "exp":
50-
builder.setExpiration(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value))));
56+
value = ensureType(key, value, Long.class);
57+
builder.setExpiration(Date.from(Instant.ofEpochSecond((Long) value)));
5158
break;
5259
case "nbf":
53-
builder.setNotBefore(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value))));
60+
value = ensureType(key, value, Long.class);
61+
builder.setNotBefore(Date.from(Instant.ofEpochSecond((Long) value)));
5462
break;
5563
case "iat":
56-
builder.setIssuedAt(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value))));
64+
value = ensureType(key, value, Long.class);
65+
builder.setIssuedAt(Date.from(Instant.ofEpochSecond((Long) value)));
5766
break;
5867
case "jti":
59-
builder.setId((String)value);
68+
ensureType(key, value, String.class);
69+
builder.setId((String) value);
6070
break;
6171
default:
6272
builder.claim(key, value);
@@ -65,6 +75,23 @@ public String dynamicBuilderSpecific(@RequestBody Map<String, Object> claims) th
6575

6676
builder.signWith(SignatureAlgorithm.HS256, secret.getBytes("UTF-8"));
6777

68-
return builder.compact();
78+
return new JwtResponse(builder.compact());
79+
}
80+
81+
private Object ensureType(String registeredClaim, Object value, Class expectedType) {
82+
// we want to promote Integers to Longs in this case
83+
if (expectedType == Long.class && value instanceof Integer) {
84+
value = ((Integer) value).longValue();
85+
}
86+
87+
boolean isCorrectType = expectedType.isInstance(value);
88+
89+
if (!isCorrectType) {
90+
String msg = "Expected type: " + expectedType.getCanonicalName() + " for registered claim: '" +
91+
registeredClaim + "', but got value: " + value + " of type: " + value.getClass().getCanonicalName();
92+
throw new JwtException(msg);
93+
}
94+
95+
return value;
6996
}
7097
}

jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,65 +3,46 @@
33
import io.jsonwebtoken.Claims;
44
import io.jsonwebtoken.Jws;
55
import io.jsonwebtoken.Jwts;
6-
import io.jsonwebtoken.MalformedJwtException;
76
import io.jsonwebtoken.SignatureAlgorithm;
8-
import io.jsonwebtoken.SignatureException;
9-
import org.springframework.http.HttpStatus;
10-
import org.springframework.web.bind.annotation.ExceptionHandler;
7+
import io.jsonwebtoken.jjwtfun.model.JwtResponse;
118
import org.springframework.web.bind.annotation.RequestMapping;
12-
import org.springframework.web.bind.annotation.RequestMethod;
139
import org.springframework.web.bind.annotation.RequestParam;
14-
import org.springframework.web.bind.annotation.ResponseStatus;
1510
import org.springframework.web.bind.annotation.RestController;
1611

1712
import java.io.UnsupportedEncodingException;
1813
import java.time.Instant;
19-
import java.time.temporal.ChronoUnit;
2014
import java.util.Date;
21-
import java.util.HashMap;
22-
import java.util.Map;
2315

2416
import static org.springframework.web.bind.annotation.RequestMethod.GET;
25-
import static org.springframework.web.bind.annotation.RequestMethod.POST;
2617

2718
@RestController
28-
public class StaticJWTController {
19+
public class StaticJWTController extends BaseController {
2920

3021
@RequestMapping(value = "/static-builder", method = GET)
31-
public String fixedBuilder() throws UnsupportedEncodingException {
22+
public JwtResponse fixedBuilder() throws UnsupportedEncodingException {
3223

3324
String jws = Jwts.builder()
3425
.setIssuer("Stormpath")
3526
.setSubject("msilverman")
3627
.claim("name", "Micah Silverman")
3728
.claim("scope", "admins")
38-
.setIssuedAt(Date.from(Instant.ofEpochSecond(1466796822))) // Fri Jun 24 2016 15:33:42 GMT-0400 (EDT)
39-
.setExpiration(Date.from(Instant.ofEpochSecond(1466883222))) // Sat Jun 25 2016 15:33:42 GMT-0400 (EDT)
29+
.setIssuedAt(Date.from(Instant.ofEpochSecond(1466796822L))) // Fri Jun 24 2016 15:33:42 GMT-0400 (EDT)
30+
.setExpiration(Date.from(Instant.ofEpochSecond(4622470422L))) // Sat Jun 24 2116 15:33:42 GMT-0400 (EDT)
4031
.signWith(
4132
SignatureAlgorithm.HS256,
4233
"secret".getBytes("UTF-8")
4334
)
4435
.compact();
4536

46-
return jws;
37+
return new JwtResponse(jws);
4738
}
4839

4940
@RequestMapping(value = "/parser", method = GET)
50-
public Jws<Claims> fixedParser(@RequestParam String jws) throws UnsupportedEncodingException {
41+
public JwtResponse fixedParser(@RequestParam String jws) throws UnsupportedEncodingException {
5142
Jws<Claims> claims = Jwts.parser()
5243
.setSigningKey("secret".getBytes("UTF-8"))
5344
.parseClaimsJws(jws);
5445

55-
return claims;
56-
}
57-
58-
@ResponseStatus(HttpStatus.BAD_REQUEST)
59-
@ExceptionHandler({SignatureException.class, MalformedJwtException.class})
60-
public Map<String, String> exception(Exception e) {
61-
Map<String, String> response = new HashMap<>();
62-
response.put("status", "ERROR");
63-
response.put("message", e.getMessage());
64-
response.put("exception-type", e.getClass().getName());
65-
return response;
46+
return new JwtResponse(claims);
6647
}
6748
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package io.jsonwebtoken.jjwtfun.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import io.jsonwebtoken.Claims;
5+
import io.jsonwebtoken.Jws;
6+
7+
@JsonInclude(JsonInclude.Include.NON_NULL)
8+
public class JwtResponse {
9+
private String message;
10+
private Status status;
11+
private String exceptionType;
12+
private String jwt;
13+
private Jws<Claims> claims;
14+
15+
public enum Status {
16+
SUCCESS, ERROR
17+
}
18+
19+
public JwtResponse() {}
20+
21+
public JwtResponse(String jwt) {
22+
this.jwt = jwt;
23+
this.status = Status.SUCCESS;
24+
}
25+
26+
public JwtResponse(Jws<Claims> claims) {
27+
this.claims = claims;
28+
this.status = Status.SUCCESS;
29+
}
30+
31+
public String getMessage() {
32+
return message;
33+
}
34+
35+
public void setMessage(String message) {
36+
this.message = message;
37+
}
38+
39+
public Status getStatus() {
40+
return status;
41+
}
42+
43+
public void setStatus(Status status) {
44+
this.status = status;
45+
}
46+
47+
public String getExceptionType() {
48+
return exceptionType;
49+
}
50+
51+
public void setExceptionType(String exceptionType) {
52+
this.exceptionType = exceptionType;
53+
}
54+
55+
public String getJwt() {
56+
return jwt;
57+
}
58+
59+
public void setJwt(String jwt) {
60+
this.jwt = jwt;
61+
}
62+
63+
public Jws<Claims> getClaims() {
64+
return claims;
65+
}
66+
67+
public void setClaims(Jws<Claims> claims) {
68+
this.claims = claims;
69+
}
70+
}

0 commit comments

Comments
 (0)