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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user