I have used the official
spring-security-jwt provided by Spring as an implementation of JWT. This toolkit is no longer maintained. And it is not particularly compatible with the latest
Spring Security OAuth2 Client and
Spring Authorization Server. So I took two days to re-implement JWT with these two new dependencies.
The JOSE library
Nimbus is used by default in the latest Spring Security. This library is currently one of the most used JOSE class libraries and most of the transformation work has been done around this library.
The process of conversion
The process is roughly the same as the Spring Security hands-on dry run.
Load the certificate
The certificate still uses keytool to generate a 2048-length RSA key.
Here we used a more “violent” way to read KeyStore directly and then use public and private keys, this time the certificate loaded by KeyStore is transformed into JWK (Json Web Key) in JOSE specification.
JWT is defined in Spring Security as
org.springframework.security.oauth2.jwt.Jwt object, and operations on JWT can be abstracted into two aspects.
The first is JWT generation, which is not provided by Spring Security itself, but only by the incubating
Spring Authorization Server, which provides the abstract interface
JwtEncoder for JWT generation.
Claimsare abstracted accordingly as
So I used
Nimbus to implement
JwtEncoder, which is actually a port of the
Spring Authorization Server implementation. Of course, it’s not a copy of the original, it’s just to make sure the facade is consistent, so that if the project matures, we can be seamlessly compatible.
Since there is
JwtEncoder, there must be
JwtDecoder. This is provided in the
Spring Security OAuth2 Client and is also slightly modified. In addition, this decoder is not only responsible for parsing JWT strings into JWT objects, but it also takes on the validation function, where there is a delegating validator
DelegatingOAuth2TokenValidator that we can flexibly customize to perform multiple JWT validation policies.
We all know that usually Tokens in JWTs come in pairs. Previously, we simply used a class to encapsulate the string form of
refreshToken. This time we use the
OAuth2AccessTokenResponse provided by
spring ecurity oauth2 core :
This class expresses much richer and more flexible content. The corresponding json is as follows.
The rest is largely unchanged, keeping as much of the original flavor as possible, while being compatible with the future style of Spring Security. How can you be compatible and flexible at the same time during code iteration? The key is to have a unified entry abstraction and exit abstraction. If you can do this, the quality of your code will be significantly better.