2013-04-23 236 views
2

我想在我的应用程序中使用@PreAuthorize Spring注释来控制访问。@PreAuthorize with hasPermission()执行代码两次

问题是,我有很多条件不取决于请求参数,而是取决于数据库实体。

概述:

我有一个Route实体,具有User owner场。仅当您是所有者时,您才能删除Route

我写我的控制器方法:

@RequestMapping(value = "/route/remove/{id}", method = RequestMethod.GET) 
@PreAuthorize("hasPermission(#id, 'RouteRemove')") 
    public String removeRoute(@PathVariable("id") Integer id, ModelMap model) { 

    Route route = routeBO.getById(id); 

    if(null == route) 
    return "forward:/errors/404"; 

    // ... remove route here. 
    // routeBO.remove(id); 
} 

RouteRemove许可被定义为:

@Component 
public class RouteRemovePermission implements Permission { 

    @Autowired 
    private RouteBO routeBO; 

    @Override 
    public boolean isAllowed(Authentication authentication, Object targetDomainObject) { 
     if(!(targetDomainObject instanceof Integer)) 
      return false; 

     Route route = routeBO.getById((Integer) targetDomainObject); 

     if(route == null) 
      return false; 

     User user = AthenticationUtil.getUser(); 

     return null != user && user.equals(route.getOwner()); 
    } 

} 

正如你所看到的,我必须评估routeBO.getById()两次。

问:

,才有可能只有一次评估这个代码?

当然,我曾尝试:

@RequestMapping(value = "/route/remove/{id}", method = RequestMethod.GET) 
public String removeRoute(@PathVariable("id") Integer id, ModelMap model) { 

Route route = routeBO.getById(id); 

if(null == route) 
    return "forward:/errors/404"; 

return removeRoute(route, model); 
} 

@PreAuthorize("hasPermission(#id, 'RouteRemove')") 
public String removeRoute(Route id, ModelMap model) { 

    return "route/display"; 
} 

removeRoute(Route id, ModelMap model)之前无权调用方法。也许我有不正确的配置?

MVC-调度-servlet.xml中

<sec:global-method-security secured-annotations="enabled" pre-post-annotations="enabled"> 
    <sec:expression-handler ref="expressionHandler"/> 
</sec:global-method-security> 

的security.xml

<beans:bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler"> 
    <beans:property name="permissionEvaluator" ref="permissionEvaluator"/> 
</beans:bean> 

<beans:bean id="permissionEvaluator" class="pl.wsiadamy.common.security.BasePermissionEvaluator"> 
    <beans:constructor-arg index="0"> 
     <beans:map key-type="java.lang.String" 
      value-type="pl.wsiadamy.common.security.Permission"> 
      <beans:entry key="RouteView" value-ref="routeViewPermission" /> 
      <beans:entry key="RouteRemove" value-ref="routeRemovePermission" /> 
     </beans:map> 
    </beans:constructor-arg> 
</beans:bean> 
<beans:bean id="routeViewPermission" class="pl.wsiadamy.common.security.permission.RouteViewPermission" /> 
<beans:bean id="routeRemovePermission" class="pl.wsiadamy.common.security.permission.RouteRemovePermission" /> 

回答

2

我建议你打破了你的安全标注removeRoute方法到一个单独的服务类,如:

@Service 
public class RouteService { 
    @PreAuthorize("hasPermission(#route, 'RouteRemove')") 
    public void removeRoute(Route route) { 
     // remove route here 
    } 
} 

然后你在你的网络控制器中使用它:

@Autowired RouteService routeService; 

@RequestMapping(value = "/route/remove/{id}", method = RequestMethod.GET) 
public String removeRoute(@PathVariable("id") Integer id, ModelMap model) { 
    Route route = routeBO.getById(id); 
    if(null == route) 
     return "forward:/errors/404"; 
    routeService.removeRoute(route); 
    return "route/display"; 
}