MyCustomUserDetailService

MyCustomUserDetailService

本文介绍了Spring Boot 中 Spring Security 的困惑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的 UserDetailService 实现器,即 MyCustomUserDetailService,其中 loadUserByName 方法被覆盖.

我有生成 JWT 令牌的令牌生成器类.

我有一个名为 JWTAuthenticationFilter 的类,它扩展了OnceperRequestFilter 我所在的地方有一个 doFilter 方法验证已生成和提供的令牌客户端在 HttpRequest 的标头中.现在从这里开始我真正的问题.代码是这样的:

UserDetails usd=this.myCustomUserDetailService.loadByUserName(userNameFromToke);//userNameFromToke 是从客户端提供的令牌中提取的字符串.UsernamePasswordAuthenticationToken upat=new UsernamePasswordAuthenticationToken(usd,null,usd.getAuthorities());//这里在密码中我传递null.upat.setDetails(new WebAuthenticationDetailsS​​ource().buildDetails(httpRequest));SecurityContextHolder.getContext().setAuthentication(upat);

问题 1:

`ups.setDetails(new WebAuthenticationDetailsS​​ource().buildDetails(httpRequest));`

为什么我们传递整个 HTTP 请求(即 httpRequest)而不是用户详细信息我们从令牌中提取的?为什么我需要这个 setDetails方法,因为我已经传递了用户详细信息、密码和列表UsernamePasswordAuthenticationToken 中构造函数参数中的权限.

问题 2:

setAuthentication 方法和 UsernamePasswordAuthenticationToken 是如何工作的?我正在通过我从令牌中提取的信息,即SecurityContextHolder.getContext().setAuthentication(upat);以及 UsernamePasswordAuthenticationToken 的构造函数中的用户详细信息、密码和权限,但是反对它验证upat"的内容?UsernamePasswordAuthenticationToken 是否在内部自动检查使用MyCustomUserDetailService"?

我知道这个问题有点冗长,但由于我是初学者,我正在努力理解其背后的机制,我已经对其进行了研究,但这种困惑并没有消失.请帮忙.另外,如果您觉得我的问题有问题,请建议我如何简明我的问题.

解决方案
  1. UsernamePasswordAuthenticationToken 中的详细信息完全由您决定,如果您稍后在应用程序中需要来自经过身份验证的用户的更多详细信息,它会有所帮助.就像您调用 SecurityContextHolder.getContext().getAuthentication() 时一样,您可以将此 Authentication 转换为 UsernamePasswordAuthenticationToken 并出于任何业务目的访问其详细信息;

  2. 您的 UsernamePasswordAuthenticationToken 未针对任何内容进行验证,您需要通过调用您的 UserDetailsS​​ervice 并检查密码或注入并调用 来手动进行验证code>AuthenticationManager#authenticate 方法.Spring Security 不在乎 SecurityContextHolder 是如何填充的.在基本场景中,在您将经过身份验证的 SecurityContext 设置到 SecurityContextHolder 后,SecurityContextPersistenceFilter 将获取此 SecurityContext 并保存它在 HttpSession 中作为一个属性.在接下来的请求中,此属性将出现在您的 HttpSession 中,这样 Spring Security 会加载 SecurityContext 并将其设置到 SecurityContextHolder 中.

您可以在 SecurityContextPersistenceFilter 中获得更多详细信息 实现,但我会在这里指出这个问题的具体部分:

HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);//这里 Spring Security 从 HttpSession 加载 SecurityContext,这是在到达你的控制器之前,在调用 FilterChain 之前完成的.SecurityContext contextBeforeChainExecution = this.repo.loadContext(holder);试试{SecurityContextHolder.setContext(contextBeforeChainExecution);if (contextBeforeChainExecution.getAuthentication() == null) {logger.debug(将 SecurityContextHolder 设置为空 SecurityContext");}其他{如果 (this.logger.isDebugEnabled()) {这个记录器.debug(LogMessage.format(Set SecurityContextHolder to %s", contextBeforeChainExecution));}}chain.doFilter(holder.getRequest(), holder.getResponse());}最后{//您已经填充了 SecurityContextHolder,并且在您的应用程序返回后它将在此处可用.所以它会得到 SecurityContext 并将其保存在 HttpSession 中SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();SecurityContextHolder.clearContext();//在 HttpSession 中持久化 SecurityContextthis.repo.saveContext(contextAfterChainExecution,holder.getRequest(),holder.getResponse());request.removeAttribute(FILTER_APPLIED);this.logger.debug(已清除 SecurityContextHolder 以完成请求");}

我希望这能帮助您更好地理解 Spring Security 的工作原理.还有一个参考文档,这是一个了解架构细节的重要来源.

I have a custom UserDetailService implementor i.e. MyCustomUserDetailService where loadUserByName method is overridden.

I have token generator class that generates the JWT token.

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);

I know the question is a bit lengthy but as I am a beginner I am trying hard to understand the mechanism behind it and I have done research on it but this confusion are not getting away. Please help. Also, suggest me how can I concise my question if you seem it's faulty.

解决方案
  1. The details in the UsernamePasswordAuthenticationToken are totally up to you, it helps if you need more details from the authenticated user later on in your application. Like when you call SecurityContextHolder.getContext().getAuthentication(), you can cast this Authentication to UsernamePasswordAuthenticationToken and access its details for any business purposes;

  2. Your UsernamePasswordAuthenticationToken is not being validated against anything, you need to do it manually by either calling your UserDetailsService and checking the password, or injecting and calling AuthenticationManager#authenticate method. Spring Security does not care how the SecurityContextHolder was populated. In basic scenarios, after you setting an authenticated SecurityContext into the SecurityContextHolder, the SecurityContextPersistenceFilter will take this SecurityContext and save it in the HttpSession as an attribute.In the next requests, this attribute will be present in your HttpSession, this way Spring Security loads the SecurityContext and sets it into the SecurityContextHolder.

You can get more details in the SecurityContextPersistenceFilter implementation, but I'll point out the specific part for this question here:

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");
}

I hope this helps you to understand better how Spring Security works. There is also a reference documentation that is a great source to know more about the details of the architecture.

这篇关于Spring Boot 中 Spring Security 的困惑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 09:53