Made BaseController to provide uniform exception response. Made JwtResponse for uniform responses. Added ensureType method to enforce type on registered claims.
This commit is contained in:
parent
df9e4d7ef5
commit
29a33c3407
|
@ -6,7 +6,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||
@SpringBootApplication
|
||||
public class JJWTFunApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(JJWTFunApplication.class, args);
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(JJWTFunApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package io.jsonwebtoken.jjwtfun.controller;
|
||||
|
||||
import io.jsonwebtoken.JwtException;
|
||||
import io.jsonwebtoken.MalformedJwtException;
|
||||
import io.jsonwebtoken.SignatureException;
|
||||
import io.jsonwebtoken.jjwtfun.model.JwtResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
public class BaseController {
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler({SignatureException.class, MalformedJwtException.class, JwtException.class})
|
||||
public JwtResponse exception(Exception e) {
|
||||
JwtResponse response = new JwtResponse();
|
||||
response.setStatus(JwtResponse.Status.ERROR);
|
||||
response.setMessage(e.getMessage());
|
||||
response.setExceptionType(e.getClass().getName());
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
package io.jsonwebtoken.jjwtfun.controller;
|
||||
|
||||
import io.jsonwebtoken.JwtBuilder;
|
||||
import io.jsonwebtoken.JwtException;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.jjwtfun.model.JwtResponse;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -16,47 +18,55 @@ import java.util.Map;
|
|||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
@RestController
|
||||
public class DynamicJWTController {
|
||||
public class DynamicJWTController extends BaseController {
|
||||
@Value("#{ @environment['jjwtfun.secret'] ?: 'secret' }")
|
||||
String secret;
|
||||
|
||||
@RequestMapping(value = "/dynamic-builder-general", method = POST)
|
||||
public String dynamicBuilderGeneric(@RequestBody Map<String, Object> claims) throws UnsupportedEncodingException {
|
||||
return Jwts.builder()
|
||||
public JwtResponse dynamicBuilderGeneric(@RequestBody Map<String, Object> claims) throws UnsupportedEncodingException {
|
||||
String jws = Jwts.builder()
|
||||
.setClaims(claims)
|
||||
.signWith(
|
||||
SignatureAlgorithm.HS256,
|
||||
secret.getBytes("UTF-8")
|
||||
)
|
||||
.compact();
|
||||
return new JwtResponse(jws);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/dynamic-builder-specific", method = POST)
|
||||
public String dynamicBuilderSpecific(@RequestBody Map<String, Object> claims) throws UnsupportedEncodingException {
|
||||
public JwtResponse dynamicBuilderSpecific(@RequestBody Map<String, Object> claims) throws UnsupportedEncodingException {
|
||||
JwtBuilder builder = Jwts.builder();
|
||||
|
||||
claims.forEach((key, value) -> {
|
||||
switch (key) {
|
||||
case "iss":
|
||||
builder.setIssuer((String)value);
|
||||
ensureType(key, value, String.class);
|
||||
builder.setIssuer((String) value);
|
||||
break;
|
||||
case "sub":
|
||||
builder.setSubject((String)value);
|
||||
ensureType(key, value, String.class);
|
||||
builder.setSubject((String) value);
|
||||
break;
|
||||
case "aud":
|
||||
builder.setAudience((String)value);
|
||||
ensureType(key, value, String.class);
|
||||
builder.setAudience((String) value);
|
||||
break;
|
||||
case "exp":
|
||||
builder.setExpiration(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value))));
|
||||
value = ensureType(key, value, Long.class);
|
||||
builder.setExpiration(Date.from(Instant.ofEpochSecond((Long) value)));
|
||||
break;
|
||||
case "nbf":
|
||||
builder.setNotBefore(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value))));
|
||||
value = ensureType(key, value, Long.class);
|
||||
builder.setNotBefore(Date.from(Instant.ofEpochSecond((Long) value)));
|
||||
break;
|
||||
case "iat":
|
||||
builder.setIssuedAt(Date.from(Instant.ofEpochSecond(Long.parseLong((String)value))));
|
||||
value = ensureType(key, value, Long.class);
|
||||
builder.setIssuedAt(Date.from(Instant.ofEpochSecond((Long) value)));
|
||||
break;
|
||||
case "jti":
|
||||
builder.setId((String)value);
|
||||
ensureType(key, value, String.class);
|
||||
builder.setId((String) value);
|
||||
break;
|
||||
default:
|
||||
builder.claim(key, value);
|
||||
|
@ -65,6 +75,23 @@ public class DynamicJWTController {
|
|||
|
||||
builder.signWith(SignatureAlgorithm.HS256, secret.getBytes("UTF-8"));
|
||||
|
||||
return builder.compact();
|
||||
return new JwtResponse(builder.compact());
|
||||
}
|
||||
|
||||
private Object ensureType(String registeredClaim, Object value, Class expectedType) {
|
||||
// we want to promote Integers to Longs in this case
|
||||
if (expectedType == Long.class && value instanceof Integer) {
|
||||
value = ((Integer) value).longValue();
|
||||
}
|
||||
|
||||
boolean isCorrectType = expectedType.isInstance(value);
|
||||
|
||||
if (!isCorrectType) {
|
||||
String msg = "Expected type: " + expectedType.getCanonicalName() + " for registered claim: '" +
|
||||
registeredClaim + "', but got value: " + value + " of type: " + value.getClass().getCanonicalName();
|
||||
throw new JwtException(msg);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,65 +3,46 @@ package io.jsonwebtoken.jjwtfun.controller;
|
|||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jws;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.MalformedJwtException;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.SignatureException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import io.jsonwebtoken.jjwtfun.model.JwtResponse;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
@RestController
|
||||
public class StaticJWTController {
|
||||
public class StaticJWTController extends BaseController {
|
||||
|
||||
@RequestMapping(value = "/static-builder", method = GET)
|
||||
public String fixedBuilder() throws UnsupportedEncodingException {
|
||||
public JwtResponse fixedBuilder() throws UnsupportedEncodingException {
|
||||
|
||||
String jws = Jwts.builder()
|
||||
.setIssuer("Stormpath")
|
||||
.setSubject("msilverman")
|
||||
.claim("name", "Micah Silverman")
|
||||
.claim("scope", "admins")
|
||||
.setIssuedAt(Date.from(Instant.ofEpochSecond(1466796822))) // Fri Jun 24 2016 15:33:42 GMT-0400 (EDT)
|
||||
.setExpiration(Date.from(Instant.ofEpochSecond(1466883222))) // Sat Jun 25 2016 15:33:42 GMT-0400 (EDT)
|
||||
.setIssuedAt(Date.from(Instant.ofEpochSecond(1466796822L))) // Fri Jun 24 2016 15:33:42 GMT-0400 (EDT)
|
||||
.setExpiration(Date.from(Instant.ofEpochSecond(4622470422L))) // Sat Jun 24 2116 15:33:42 GMT-0400 (EDT)
|
||||
.signWith(
|
||||
SignatureAlgorithm.HS256,
|
||||
"secret".getBytes("UTF-8")
|
||||
)
|
||||
.compact();
|
||||
|
||||
return jws;
|
||||
return new JwtResponse(jws);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/parser", method = GET)
|
||||
public Jws<Claims> fixedParser(@RequestParam String jws) throws UnsupportedEncodingException {
|
||||
public JwtResponse fixedParser(@RequestParam String jws) throws UnsupportedEncodingException {
|
||||
Jws<Claims> claims = Jwts.parser()
|
||||
.setSigningKey("secret".getBytes("UTF-8"))
|
||||
.parseClaimsJws(jws);
|
||||
|
||||
return claims;
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler({SignatureException.class, MalformedJwtException.class})
|
||||
public Map<String, String> exception(Exception e) {
|
||||
Map<String, String> response = new HashMap<>();
|
||||
response.put("status", "ERROR");
|
||||
response.put("message", e.getMessage());
|
||||
response.put("exception-type", e.getClass().getName());
|
||||
return response;
|
||||
return new JwtResponse(claims);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package io.jsonwebtoken.jjwtfun.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jws;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class JwtResponse {
|
||||
private String message;
|
||||
private Status status;
|
||||
private String exceptionType;
|
||||
private String jwt;
|
||||
private Jws<Claims> claims;
|
||||
|
||||
public enum Status {
|
||||
SUCCESS, ERROR
|
||||
}
|
||||
|
||||
public JwtResponse() {}
|
||||
|
||||
public JwtResponse(String jwt) {
|
||||
this.jwt = jwt;
|
||||
this.status = Status.SUCCESS;
|
||||
}
|
||||
|
||||
public JwtResponse(Jws<Claims> claims) {
|
||||
this.claims = claims;
|
||||
this.status = Status.SUCCESS;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getExceptionType() {
|
||||
return exceptionType;
|
||||
}
|
||||
|
||||
public void setExceptionType(String exceptionType) {
|
||||
this.exceptionType = exceptionType;
|
||||
}
|
||||
|
||||
public String getJwt() {
|
||||
return jwt;
|
||||
}
|
||||
|
||||
public void setJwt(String jwt) {
|
||||
this.jwt = jwt;
|
||||
}
|
||||
|
||||
public Jws<Claims> getClaims() {
|
||||
return claims;
|
||||
}
|
||||
|
||||
public void setClaims(Jws<Claims> claims) {
|
||||
this.claims = claims;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue