Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Security Spring安全性:身份验证返回null_Security_Spring_Authentication_Struts2 - Fatal编程技术网

Security Spring安全性:身份验证返回null

Security Spring安全性:身份验证返回null,security,spring,authentication,struts2,Security,Spring,Authentication,Struts2,我已按如下方式配置Springbean以返回SecurityContext: <bean id="securityContext" class="org.springframework.security.context.SecurityContextHolder" factory-method="getContext"> </bean> 上面的第二行导致NPE。这对我来说似乎很奇怪,因为以下代码按预期返回了权限: GrantedAuthority[] aut

我已按如下方式配置Springbean以返回SecurityContext:

<bean id="securityContext" class="org.springframework.security.context.SecurityContextHolder"
    factory-method="getContext">
</bean>  
上面的第二行导致NPE。这对我来说似乎很奇怪,因为以下代码按预期返回了权限:

GrantedAuthority[] authorities =   
SecurityContextHolder.getContext().getAuthentication().getAuthorities();
基本上,我试图消除对SecurityContextHolder.getContext()的静态调用,以使代码更易于测试

有什么想法可以补救吗?为什么Spring返回的SecurityContext不能返回权限,而我自己的代码中的静态调用可以返回权限


仅供参考,我正在Struts 2操作中执行代码。

SecurityContextHolder.getContext()返回与当前线程关联的上下文。在bean实例化中,存储在bean中的上下文与应用程序运行时所需的上下文不同。我认为不可能将上下文存储在bean中并一直使用它。

您可以使用静态方法使代码可测试。您只需创建自己的org.springframework.security.Authentication实现

所以在你的JUnit测试中

//Assuming you've loaded the user, create your stub
Authentication authentication = new TestAuthentication(userDetails);
//Update the context
SecurityContextHolder.getContext().setAuthentication(authentication);
在上面的示例中,“userDetails”是实现“userDetails”并通常包装域用户对象的类

我的TestAuthentication类-希望这有帮助

public class TestAuthentication implements Authentication {

    private UserDetails userDetails;
    private boolean authentication = true;

    public TestAuthentication(UserDetails userDetails){
        NullArgumentException.assertNotNull(userDetails, "userDetails");
        this.userDetails = userDetails;
    }

    public TestAuthentication(UserDetails userDetails, boolean authentication){
        NullArgumentException.assertNotNull(userDetails, "userDetails");
        this.userDetails = userDetails;
        this.authentication = authentication;
    }


    public GrantedAuthority[] getAuthorities() {
        return userDetails.getAuthorities();
    }


    public Object getCredentials() {
        return null;
    }


    public Object getDetails() {
        return null;
    }


    public Object getPrincipal() {
        return this.userDetails;
    }


    public boolean isAuthenticated() {
        return authentication;
    }


    public void setAuthenticated(boolean arg0)
            throws IllegalArgumentException {
        this.authentication = arg0;
    }


    public String getName() {
        return null;
    }
}

这是因为您创建的bean没有定义作用域——所以它基本上是一个单例。
若要使其按您的意愿工作,您需要将其设置为请求/会话范围。

请使用您可以注入默认供应商的供应商

public class UserDetailsArgumentResolver implements HandlerMethodArgumentResolver {

    private final Supplier<SecurityContext> contextSupplier;

    public UserDetailsArgumentResolver(Supplier<SecurityContext> contextSupplier) {
        this.contextSupplier = contextSupplier;
    }

    public UserDetailsArgumentResolver() {
        this.contextSupplier = SecurityContextHolder::getContext;
    }

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return UserDetails.class.isAssignableFrom(methodParameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        Authentication authentication = contextSupplier.get().getAuthentication();
        return new UserDetails(authentication.getName(), authentication.getAuthorities());
    }
}
公共类UserDetailsArgumentResolver实现HandlerMethodArgumentResolver{
私人最终供应商上下文供应商;
public UserDetailsArgumentResolver(供应商上下文供应商){
this.contextSupplier=contextSupplier;
}
public UserDetailsArgumentResolver(){
this.contextSupplier=SecurityContextHolder::getContext;
}
@凌驾
公共布尔支持参数(MethodParameter MethodParameter){
返回UserDetails.class.isAssignableFrom(methodParameter.getParameterType());
}
@凌驾
公共对象resolveArgument(MethodParameter MethodParameter、ModelAndViewContainer ModelAndViewContainer、NativeWebRequest NativeWebRequest、WebDataBinder Factory WebDataBinder Factory)引发异常{
Authentication Authentication=contextSupplier.get().getAuthentication();
返回新的UserDetails(authentication.getName()、authentication.getAuthories());
}
}

谢谢你的建议。如果安全上下文可以被注入,那么它看起来会容易得多,因为这样它就可以被模拟。。相反,使用这种方法,我必须创建一组测试dummy和stub,包括用于身份验证和授权的测试dummy和stub。但最终这是我不得不采取的方法。:-)您可以轻松地使用模拟的UserDetails对象,并将其传递给setAuthentication。Authentication=EasyMock.createNiceMock(Authentication.class);expect(authentication.getPrincipal()).andReturn(userDetails);SecurityContextHolder.getContext().setAuthentication(身份验证);
public class UserDetailsArgumentResolver implements HandlerMethodArgumentResolver {

    private final Supplier<SecurityContext> contextSupplier;

    public UserDetailsArgumentResolver(Supplier<SecurityContext> contextSupplier) {
        this.contextSupplier = contextSupplier;
    }

    public UserDetailsArgumentResolver() {
        this.contextSupplier = SecurityContextHolder::getContext;
    }

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return UserDetails.class.isAssignableFrom(methodParameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        Authentication authentication = contextSupplier.get().getAuthentication();
        return new UserDetails(authentication.getName(), authentication.getAuthorities());
    }
}