2013-04-23 68 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"; 
}