I can get the user principal as the below code, but I am puzzled how Spring Security knows to inject the correct principal. Usually, we would pass the args to call a method with parameters. So, where does Spring call the Controller Method with Principal args? Thanks for any help.
@ResponseBody
@RequestMapping({"/api/user"})
public Principal user(Principal principal) {
return principal;
}
As the comment says, HandlerMethodArgumentResolver
is a strategy interface for resolving method parameters into argument values in the context of a given request. Actually, Principal argument would be resolved in ServletRequestMethodArgumentResolver
. Talk is cheap, and show the source code.
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Class<?> paramType = parameter.getParameterType();
// WebRequest / NativeWebRequest / ServletWebRequest
if (WebRequest.class.isAssignableFrom(paramType)) {
if (!paramType.isInstance(webRequest)) {
throw new IllegalStateException(
"Current request is not of type [" + paramType.getName() + "]: " + webRequest);
}
return webRequest;
}
// ServletRequest / HttpServletRequest / MultipartRequest / MultipartHttpServletRequest
if (ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType)) {
return resolveNativeRequest(webRequest, paramType);
}
// HttpServletRequest required for all further argument types
return resolveArgument(paramType, resolveNativeRequest(webRequest, HttpServletRequest.class));
}
Now you can see the the key code as Principal.class.isAssignableFrom(paramType), and if you look for furtherly, you can see the code SecurityContextHolder.getContext().getAuthentication()
to get the actual argument. Ok, that's all, thanks for @chrylis -on strike- comments.
@Nullable
private Object resolveArgument(Class<?> paramType, HttpServletRequest request) throws IOException {
//omitted......
else if (Principal.class.isAssignableFrom(paramType)) {
Principal userPrincipal = request.getUserPrincipal();
if (userPrincipal != null && !paramType.isInstance(userPrincipal)) {
throw new IllegalStateException(
"Current user principal is not of type [" + paramType.getName() + "]: " + userPrincipal);
}
return userPrincipal;
}
//omitted......
}