我有一个自定义的UserDetailService
实现器,即MyCustomUserDetailService
,其中loadUserByName方法被重写。
我有生成 JWT token 的 token 生成器类。
I have a class called
JWTAuthenticationFilter
that extendsOnceperRequestFilter
where there is adoFilter
method where I am validating the token that has been generated and provided by the client in the header of the HttpRequest. Now from here is my real question starts. The code is something like this:
UserDetails usd=this.myCustomUserDetailService.loadByUserName(userNameFromToke);//userNameFromToke is a String that got extracted from the token that client provided.
UsernamePasswordAuthenticationToken upat=new UsernamePasswordAuthenticationToken(usd,null,usd.getAuthorities()); //Here in the password I am passing null.
upat.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
SecurityContextHolder.getContext().setAuthentication(upat);
Question 1:
`ups.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));`
why we are passing the whole HTTP Request(i.e.httpRequest) rather than the userdetails that we extracted from the token? And why do I need this
setDetails
method as I have already passed the userdetails,pasword and the list of authorities in the constructor argument inUsernamePasswordAuthenticationToken
.Question 2:
How is the setAuthentication method and UsernamePasswordAuthenticationToken working? I am passing the information that I have extracted from the token i.e.
SecurityContextHolder.getContext().setAuthentication(upat)
; and userdetails,passowords and authorities in the constructor ofUsernamePasswordAuthenticationToken
but against what it is validating "upat"? IsUsernamePasswordAuthenticationToken
automatically internally checking with the "MyCustomUserDetailService
"?
我知道这个问题有点长,但由于我是初学者,我正在努力理解其背后的机制,并且我已经对其进行了研究,但这种困惑并没有消失。请帮忙。另外,如果您认为我的问题有问题,请建议我如何简洁地表达我的问题。
最佳答案
UsernamePasswordAuthenticationToken
中的详细信息完全取决于您,如果您稍后在应用程序中需要来自经过身份验证的用户的更多详细信息,它会有所帮助。就像调用SecurityContextHolder.getContext().getAuthentication()
时一样,您可以将此Authentication
强制转换为UsernamePasswordAuthenticationToken
并出于任何业务目的访问其详细信息;您的
UsernamePasswordAuthenticationToken
未针对任何内容进行验证,您需要通过调用UserDetailsService
并检查密码,或者注入(inject)并调用AuthenticationManager#authenticate
方法。 Spring 安全does not care如何填充SecurityContextHolder
。在基本场景中,将经过身份验证的SecurityContext
设置到SecurityContextHolder
中后,SecurityContextPersistenceFilter
将获取此SecurityContext
并保存它在HttpSession
中作为属性。 在接下来的请求中,此属性将出现在您的HttpSession
中,这样 Spring Security 会加载SecurityContext
并将其设置到SecurityContextHolder
中。
您可以在SecurityContextPersistenceFilter
implementation中获取更多详细信息,但我会在这里指出这个问题的具体部分:
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
// Here Spring Security loads the SecurityContext from the HttpSession, this is done before reaching your controllers, before calling the FilterChain.
SecurityContext contextBeforeChainExecution = this.repo.loadContext(holder);
try {
SecurityContextHolder.setContext(contextBeforeChainExecution);
if (contextBeforeChainExecution.getAuthentication() == null) {
logger.debug("Set SecurityContextHolder to empty SecurityContext");
}
else {
if (this.logger.isDebugEnabled()) {
this.logger
.debug(LogMessage.format("Set SecurityContextHolder to %s", contextBeforeChainExecution));
}
}
chain.doFilter(holder.getRequest(), holder.getResponse());
}
finally {
// You've populated the SecurityContextHolder and it'll be available here after you application returns. So it'll get the SecurityContext and persist it in the HttpSession
SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
SecurityContextHolder.clearContext();
// Persisting the SecurityContext in the HttpSession
this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
request.removeAttribute(FILTER_APPLIED);
this.logger.debug("Cleared SecurityContextHolder to complete request");
}
我希望这可以帮助您更好地理解 Spring Security 的工作原理。还有一个reference documentation这是了解更多架构细节的重要来源。
关于spring-boot - Spring Boot 中 Spring Security 的困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68113942/