如何为Spring MVC控制器创建通用权限管理系统?

时间:2012-12-17 21:44:29

标签: java spring spring-mvc spring-security boilerplate

我正在做一个基于浏览器的游戏。 可以说我有一个弹簧控制器很多控制器~10。每个都有10个url映射。这就像100多种绘图方法。

如果满足某些规则,每个映射只会加载或显示正确的内容。将通过执行数据库查询来检查规则。 例如

我是12级用户并且每个控制器仅允许在用户级别为10 +,20 +,30 +,40 +,50 +等时显示内容。

我可以通过在每个控制器中的每个映射方法下执行查询来实现,但是 boilerplating 会有太多。

有没有办法以某种方式实现中心化,比如将我的限制映射到某处并且不必将它放在每个url映射方法下?

即使设计中可能没有这样的东西,也许你自己也遇到过同样的问题,并提出了一些聪明的解决方案?

1 个答案:

答案 0 :(得分:1)

我建议您将spring-security与自定义PermissionEvaluator一起使用,这样您基本上可以在网页和控制器中使用相同的实现:

在您可以使用的网页中:
<security:authorize access="hasPermission(#shop,'see')"></security:authorize>

在您的控制器和您可以使用的任何服务方法中:
@PreAuthorize("hasPermission(#shop,'see')")

像这样:

@PreAuthorize("hasPermission(#shop,'see')")
@RequestMapping("/someUrl")
public String processSomeUrl(@ModelAttribute("shop") Shop shop){
    shop.getStuff();
}

@PostAuthorize@PostFilter("hasPermission(filterObject,'see')")(过滤列表)

所有这些功能都将根据您自己的权限评估者限制访问或过滤结果列表。他们都将指向相同的实现,看起来像这样:

@Component
public class MyPermissionEvaluator implements PermissionEvaluator {

    private final Log logger = LogFactory.getLog(getClass());

    @Override
    public boolean hasPermission(Authentication auth, Object arg1, Object arg2) {
        logger.info("hasPermission "+auth+" - "+arg1+" - "+arg2+" ");
        if(arg2 instanceof String && arg1 instanceof Shop){
            Shop shop = (Shop)arg1;
            if(((String) arg2).equals("see")){
                //here you can have your own function
                boolean result = hasPermissionSeeShop(auth, project);                   
                return result;
            }
        }
        return false;
    }

    @Override
    public boolean hasPermission(Authentication arg0, Serializable arg1,
        String arg2, Object arg3) {
        logger.info("hasPermission "+arg0+" - "+arg1+" - "+arg2+" - "+arg3+" ");
        return false;
    }
}

此外,当这些方法返回false时,它会自动抛出AccessDeniedException,您可以轻松地将其配置为重定向到http元素中您自己的accessDenied页面:

<http auto-config="true">
    <intercept-url pattern="/admin*" access="ROLE_ADMIN" />
    <access-denied-handler error-page="accessDeniedPage"/>
</http>