Spring Security:为什么身份验证正在扩展Principal?

时间:2013-07-19 10:47:55

标签: spring spring-security

Spring Security假设Authentication是Principal。

public interface Authentication extends Principal, Serializable {}

HttpServletRequest的方法为getUserPrincipal,负责访问主体对象。

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

public interface RealPrincipal extends Principal {
   public Integer getId();
}

通用模块A具有Real Principal接口和实现。

模块A使用Common Module A,Servlet Api并且不依赖于Spring Security:

模块B使用Common Module A,Servlet Api并配置Spring Security。该模块负责安全性和UserDetails的实现。

Web A使用模块A和模块B.

为了使用请求方法,我最终得到了这样的实现:

public ModelAndView someRequestHandler(Principal principal) {
   User activeUser = (User) ((Authentication) principal).getPrincipal();
   ...
}

这迫使我对模块A和其他模块依赖Spring Security。我认为适当的servlet api抽象不应该依赖于spring安全性。 request.getUserPrincipal应返回真实主体。

请解释为什么org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper返回

身份验证而不是Real Principal

编辑:我已在我的方案中添加了通用模块A,并更新了模块B负责安全性。

2 个答案:

答案 0 :(得分:3)

正如Luke所说,Spring Security使用Principal身份验证,因为它实现了Principal。它不使用Authentication#getPrincipal(),因为它不能保证是Principal(它是一个Object)。事实上,在大多数情况下,Spring Security的Authentication#getPrincipal()返回一个User(不实现Principal),框架用户提供的自定义UserDetails或String。

如果你想让Spring Security处理这个问题,你可能需要使用HttpServletRequestWrapper来实现这个逻辑,正如Luke建议的那样。例如,您可以执行以下操作:

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

或者,看看我对你的另一个问题的答案,了解与Spring MVC集成的选项 - Injecting Custom Principal to Controllers by Spring Security

答案 1 :(得分:1)

简短的回答是AuthenticationPrincipal,因此可以在需要的API(例如您提到的servlet API方法)中使用它。

这在实践中意味着什么?不是很多。 Java的Principal接口只有一个方法getName,所以如果你想做的不仅仅是渲染用户名,你还需要了解更多关于实现的信息。

当您使用短语“真实主体”和“正确的servlet api抽象”时,您应该考虑一下您的意思。例如,如果委托人是“真正的”主体,您期望如何实施someRequestHandler方法?