I have a question that comes from reading a lot of examples from Spring user and oauth2 but still failing at some basic concepts, maybe someone can point me in good directions/examples or of information to read.
so I'm trying to build a rest based API application. to access the endpoints they will be protected by a JWT token and the idea is that the token is used for SSO across several other applications.
my initial idea was to have some authentication filter interceptors that process the token so I can store whatever additional information I may need and then use that user in the actual business layer of my services. I've implemented some AuthenticationFiler that implements Filter and I can get the additional information after I read the token access from my token store.
Now my first problem starts in fact that most of the examples start by the login/logout page and since I'm having more of an API setup I really don't have that flow.
Second, it seems most times the way to get the user is from the principal (SecurityContextHolder.getContext().getAuthentication().getPrinciple()) something like this but my principal is always null, not sure if this is because I don't really know if this is because of the stateful vs. stateless or the sorts.
So my biggest problems are to understand how can I share user details between my security interceptor and my business layer. maybe this questions is not so much about spring per se and I have more basic knowledge missing but maybe someone can give me some pointers.
this is my authentication filter, what I want to know is how can I create a user instance the same way I can use the MDC to store the user information. Ideally, I would like to create a user instance there and just pass it to the business layer. can I do that with an Autowire?
@Component
@Order(Ordered.LOWEST_PRECEDENCE)
public class AuthenticationFilter implements Filter {
@Autowired
TokenStore tokenStore;
@Autowired
JwtAccessTokenConverter accessTokenConverter;
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
if (authentication instanceof OAuth2Authentication) {
OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) authentication;
OAuth2AuthenticationDetails oauth2AuthenticationDetails = (OAuth2AuthenticationDetails)oAuth2Authentication.getDetails();
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(oauth2AuthenticationDetails.getTokenValue());
Object decodedDetails = oauth2AuthenticationDetails.getDecodedDetails();
Map<String, Object> additionalInformation = oAuth2AccessToken.getAdditionalInformation();
MDC.put("sub", additionalInformation.get("sub").toString());
MDC.put("preferred_username", additionalInformation.get("preferred_username").toString());
}
}
try {
chain.doFilter(request, response);
}
finally {
MDC.remove("sub");
MDC.remove("preferred_username");
}
}
@Override
public void destroy() {
}
}
not sure if this is my miss-understanding but I think what I'm looking for is dependency injections.
somehow I wanto create a new User Bean, fill it in my filter and consumer it elsewhere. I guess I could do a @autowire in my business layer and set it in the filter and use it in the business layer? is this a bad pattern?
As far as I understand you architecture, you are developing this:
and you want this:
If both of the above assumptions are correct, you should read about how spring is doing this in it's microservice architecture. read this for quick start:
https://dzone.com/articles/json-web-tokens-with-spring-cloud-microservices
Hope this helps.