I am using Spring authorization Server 1.0.0. In this I have customized the JWT as per my requirement as follows. Let's say there is a user "vinay". And his role is also "vinay".
I am adding extra field "authority" : [{"role":"ROLE_vinay"}] in JWT. Below is the payload of JWT.
{ "sub": "vinay", "aud": "messaging-client", "nbf": 1671430162, "authority": [ { "role": "ROLE_vinay" } ], "scope": [ "openid" ], "iss": "http://localhost:8000", "exp": 1671430462, "iat": 1671430162 }
For Role "vinay", there are multiple permissions/restrictions. This data is present in MySQL. After user authentication(login), I am adding this data in Redis in KEY:VALUE pair where key is "vinay", value is [Restriction 1, Permission 1, Permission 2].
"vinay" : [Permission 1, Permission 2, Restriction 1]
After succesful login from user(vinay), Client gets the custom token, and sends the request to spring resource server with custom JWT in the header with Bearer prefix. For each request How to decode incoming JWT and get "role" and verify it from Redis? If there is any restriction in Redis, it should not allow it. It should throw "401 unauthorized". If there is permission, then It shall proceed with the request.
In your latest comment you described using only MySQL, and I think that makes sense. I don't see Redis fitting in anywhere in this scenario. So the flow is:
OAuth2TokenCustomizer<JwtEncodingContext>
to add theauthority
field to the JWT (e.g.ROLE_xyz
).JwtGrantedAuthoritiesConverter
to map theauthority
field of the JWT toauthentication.getAuthorities()
in Spring Security.The challenge is that in your DB, you're mapping roles directly to a set of allowed URLs (e.g.
ROLE_xyz
=>POST /customer
, ...). Perhaps you're dealing with an existing database schema and can't design the data or relationships from scratch. What I would expect is a mapping of roles to a set of permissions (e.g.ROLE_xyz
=>customer.write
, ...).If you have a permissions scheme like this, you could do the lookup in the
JwtGrantedAuthoritiesConverter
above and map those permissions as authorities instead.However, if the data in MySQL maps roles to URL patterns, your best bet is to use the
AuthorizationManager
API to integrate authorization with your MySQL table (see Configure RequestMatcherDelegatingAuthorizationManager under Authorize HttpServletRequests with AuthorizationFilter for an example).A custom
AuthorizationManager
can be implemented to look upROLE_xyz
and dynamically build a list of authorization rules withRequestMatcherDelegatingAuthorizationManager.builder()
.For example:
This may seem complex, but your authorization scheme (using OAuth2 + JWTs AND roles/authorities AND MySQL to manage roles) is a somewhat complex setup. The
AuthorizationManager
API actually makes it easier than it has been in earlier versions of Spring Security.Also note that the above example assumes that role mappings in the database can change at runtime, and so must be looked up every time. If this is not the case, the example could be changed to load data from MySQL only on startup. MySQL lookup performance could also be improved with caching if needed.