Security Spring安全性:身份验证返回null
我已按如下方式配置Springbean以返回SecurityContext: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
<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());
}
}