Spring安全性:为什么身份验证要扩展主体?

Spring安全性:为什么身份验证要扩展主体?,spring,spring-security,Spring,Spring Security,Spring Security假设身份验证是一个主体 public interface Authentication extends Principal, Serializable {} HttpServletRequest的方法负责访问主体对象 让我们考虑一下这个例子: public interface RealPrincipal extends Principal { public Integer getId(); } 公共模块A具有真正的主体接口和实现 模块A使用通用模块A、Se

Spring Security假设身份验证是一个主体

public interface Authentication extends Principal, Serializable {}
HttpServletRequest的方法负责访问主体对象

让我们考虑一下这个例子:

public interface RealPrincipal extends Principal {
   public Integer getId();
}
公共模块A具有真正的主体接口和实现

模块A使用通用模块A、Servlet Api,不依赖于Spring安全性:

模块B使用公共模块A、Servlet Api并配置Spring安全性。此模块负责安全和用户详细信息的实现

Web A使用模块A和模块B

为了使用请求方法,我最终实现了这样一个实现:

public ModelAndView someRequestHandler(Principal principal) {
   User activeUser = (User) ((Authentication) principal).getPrincipal();
   ...
}
这迫使我对模块A和其他模块具有Spring安全性的依赖性。我相信一个合适的servlet api抽象不应该依赖于spring安全性。request.getUserPrincipal应返回实际主体

请解释org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper返回的原因

身份验证而不是真正的主体


编辑:我已经将公共模块A添加到我的场景中,并更新了模块B负责安全性。

简单的回答是,
身份验证是一个
主体
,因此可以在需要它的API(如您提到的servlet API方法)中使用

这在实践中意味着什么?不多。Java的接口只有一个方法
getName
,因此如果您想做的不仅仅是呈现用户名,那么您需要了解有关实现的更多信息


当您使用短语“真正的主体”和“适当的servlet api抽象”时,您可能应该考虑一下您的意思。例如,如果主体是一个“真实”的主体,您希望如何实现您的
someRequestHandler
方法?

正如Luke所述,Spring Security使用主体身份验证,因为它实现主体身份验证。它不使用身份验证#getPrincipal(),因为它不能保证是主体(它是一个对象)。事实上,在大多数情况下,Spring Security的身份验证#getPrincipal()返回一个用户(不实现Principal)、框架用户提供的自定义UserDetails或字符串

如果您希望Spring安全性来处理这个问题,您可能需要按照Luke的建议使用HttpServletRequestWrapper来实现这个逻辑。例如,您可以执行以下操作:

public RealPrincipalFilter extends OncePerRequestFilter {

    public void doFiter(HttpServletRequest request, HttpServletResponse response, FilterChain) {
        chain.doFilter(new RealPrincipalRequestWrapper(request), response);
    }

    private static final class RealPrincipalRequestWrapper 
          extends HttpServletRequestWrapper {
        public Principal getUserPrincipal() {
            Authentication auth = (Authentication) super.getPrincipal();
            return auth == null ? null : (RealPrincipal) auth.getPrincipal()
        }
    }
}

@Configuration
@EnableWebSecurity
public WebSecurityConfig extends WebSecurityConfigurerAdapter {
    public configure(HttpSecurity http) {
        http
            // ... other config ...
            .addFilterAfter(new RealPrincipalFilter(), SecurityContextHolderAwareRequestFilter.class);
    }
    ...
}

或者,看看我对您的另一个问题的回答,了解与SpringMVC集成的选项-

将RealPrincipal视为principal的子类。它有所有必要的方法,如用户名、电子邮件、密码等。。。我可以相信。没问题。但依靠Spring安全性并不是一个可行的解决方案。还有一个问题。Spring MVC正在向主体注入request.getUserPrincipal。如果我将RealPrincipal声明为控制器方法参数,则它不能注入。因为身份验证不是真正的主体,而是主体。这导致了一个错误。请看我的另一个问题。
RealPrincipal
是什么?您希望它来自哪里?i、 是谁提供的,你如何依赖它?我添加了RealPrincipal接口。它来自另一个模块,比如ServletAPI。模块B提供了必要的实现。顺便说一下,这不是一个虚构的场景。我的情况与上面所写的完全相同。如果您希望从
getUserPrincipal
方法返回
RealPrincipal
,那么最好的选择可能是在spring安全过滤器链之后添加一个单独的过滤器,该过滤器链使用
HttpServletRequestWrapper
来定制该方法。您还可以禁用内置包装器。感谢Rob为您提供的精彩答案。现在我了解到,Spring安全性不仅与Web应用程序相关,还与独立应用程序相关。这意味着用户不需要是主体。为了符合Http Api,身份验证实现了主体接口。到目前为止还不错:)我的问题是:如果SpringSecurity自定义用户已经实现了主体接口,该怎么办?这导致了这样一个完美的实现,我想:你认为呢?你所建议的更改是非被动的,所以充其量也可以包含在4.x版本中。我不认为这是大多数人都需要的用例,所以我也不认为它会包含在4.x中。这并不是说你没有很好的理由去做你正在做的事情,而是说作为一个框架,我们需要尝试瞄准90%的用例,并为其他用例设置挂钩。