我正在使用 Spring 4.1.7.RELEASE 和 Spring Security 4.0.2.RELEASE 。
...
<global-method-security pre-post-annotations="enabled" />
<http auto-config="true" use-expressions="true">
<form-login login-page="/user/login" />
<logout invalidate-session="true" logout-success-url="/user/login?logout"/>
<intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/user/login**" access="permitAll" />
<intercept-url pattern="/login**" access="permitAll" />
<intercept-url pattern="/user/create" access="hasAuthority('user_access_full')"/>
<csrf />
</http>
<authentication-manager>
<authentication-provider user-service-ref="myUserDetailsService" >
<password-encoder hash="bcrypt" />
</authentication-provider>
</authentication-manager>
<beans:bean id="myUserDetailsService" class="my.service.MyUserDetailsService" autowire="byType"/>
...
我想使用@PreFilter
过滤用户服务输入,以便为新用户分配角色。
@Entity
public class JRole implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@NotEmpty
@Column(nullable = false, unique = true)
private String name;
private String displayName;
public JRole(){
}
public JRole(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
}
...
@Transactional
@PreFilter(value = "hasRole('admin') or (filterObject.name!='admin' and filterObject.name!='office_admin')")
public void create(JUser user, Set<JRole> roles) {
JUser u2 = userDao.findByUsername(user.getUsername());
if (u2 != null) {
throw new MessageException("username duplicate!");
}
if (roles == null || roles.isEmpty()) {
throw new MessageException("empty roles");
}
user.setRoles(roles);
doCreate(user);
}
如果我的控制器调用上述方法:
@RequestMapping(value = "/create", method = RequestMethod.POST)
public String create2(Model model, @Valid @ModelAttribute("user") JUser user, BindingResult result) {
addAttributes(model, CREATE);
if (!result.hasErrors()) {
if (user.getOfficeType() == null) {
user.setOfficeType(office.getType());
}
if (user.getEnabled() == null) {
user.setEnabled(true);
}
System.out.println(user.getRoles().size());
try {
userService.create(user, user.getRoles());// method arguments for PreFilter
model.addAttribute("createSuccess", "کاربر به نام " + user.getFullName() + " ساخته شد.<br/>" + " نام کاربری:" + user.getUsername());
} catch (MessageException ex) {
String mess = NUtil.getDeepMessage(ex);
result.rejectValue(null, "hey", mess + "salam");
}
System.out.println(user.getFullName());
}
System.out.println(result);
return "user/manage";
}
我遇到这个例外:
java.lang.NullPointerException
at org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice.findFilterTarget(ExpressionBasedPreInvocationAdvice.java:71)
at org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice.before(ExpressionBasedPreInvocationAdvice.java:35)
at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:57)
at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:25)
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:62)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at ir.iais.nezarat.service.UserService$$EnhancerBySpringCGLIB$$3a7efc2e.create(<generated>)
at ir.iais.nezarat.controller.UserController.create2(UserController.java:105)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(Applicatio ...
...
...
此行发生NullPointerException:
//user is not null, user.getRoles() is not null
userService.create(user, user.getRoles());
请帮忙!
答案 0 :(得分:3)
您也可以使用
@PreFilter
在方法调用之前进行过滤,尽管这是一个不太常见的要求。语法是一样的,但如果有多个参数是集合类型,那么您必须使用此批注的filterTarget
属性按名称选择一个。
source code仅检查参数的数量,而不检查参数的类型:
private Object findFilterTarget(String filterTargetName, EvaluationContext ctx, MethodInvocation mi) {
Object filterTarget = null;
if (filterTargetName.length() > 0) {
filterTarget = ctx.lookupVariable(filterTargetName);
if (filterTarget == null) {
throw new IllegalArgumentException(
"Filter target was null, or no argument with name "
+ filterTargetName + " found in method");
}
}
else if (mi.getArguments().length == 1) {
Object arg = mi.getArguments()[0];
if (arg.getClass().isArray() || arg instanceof Collection<?>) {
filterTarget = arg;
}
if (filterTarget == null) {
throw new IllegalArgumentException(
"A PreFilter expression was set but the method argument type"
+ arg.getClass() + " is not filterable");
}
}
if (filterTarget.getClass().isArray()) {
throw new IllegalArgumentException(
"Pre-filtering on array types is not supported. "
+ "Using a Collection will solve this problem");
}
return filterTarget;
}
对于具有单个参数(即集合类型)的方法,此参数将用作过滤器目标。
[...]
应该过滤的参数的名称(必须是非空的集合实例)如果方法包含单个集合参数,则可以省略此属性。
您尚未定义filterTarget
但有两个参数,因此您获得了NullPointerException
。
您必须添加filterTarget
参数:
@Transactional
@PreFilter(filterTarget="roles", value = "hasRole('admin') or (filterObject.name!='admin' and filterObject.name!='office_admin')")
public void create(JUser user, Set<JRole> roles) {
JUser u2 = userDao.findByUsername(user.getUsername());
if (u2 != null) {
throw new MessageException("username duplicate!");
}
if (roles == null || roles.isEmpty()) {
throw new MessageException("empty roles");
}
user.setRoles(roles);
doCreate(user);
}