使用spring security和/或shiro的权利的最佳实践

时间:2011-05-16 15:04:37

标签: java spring-security shiro

我对使用Spring Security或Shiro处理“权利”概念的最佳方式的意见感兴趣。

例如,想象一下,JAX-RS端点的签名如下:

AccountDetails getAccountDetails(String accountId);

使用Spring Security,我可能会注释一个类似的实现:

@Secured(AUTHORIZED_USER)
public AccountDetails getAccountDetails(String accountId) { ... }

或使用Shiro,

@RequiresAuthentication
public AccountDetails getAccountDetails(String accountId) { ... }

然而,我所寻找的是关于如何确保用户有权访问特定帐户ID(我认为称为“权利管理”)的“最佳实践”的一些建议。

我可以想象几种不同的方法:

@Secured(AUTHORIZED_USER)
@AccountEntitled
public AccountDetails getAccountDetails(@Account String accountId) { ... }

(这让我觉得使用Spring Security并不是那么简单,但我喜欢错了)。

或者,我可以想象引入一个AccountId域对象,以及一个只有当前安全上下文所持有的原则允许String成为AccountId时才能成功的工厂用户看到该帐户。但这开始变得有些混乱。

总的来说,我不想在这里发明新概念;这看起来像面包&黄油的东西,但我没有太多运气在这里找到关于最佳实践的可靠建议。

感谢您的任何建议。

1 个答案:

答案 0 :(得分:1)

听起来你要做的就是为特定帐户实现行级安全性。还有其他Stackoverflow问题(How to implement row-level security in Java?Database independent row level security solution)讨论了解决这个问题的潜在解决方案。此外,第一个答案中提供的链接讨论了实施Row Level Security with Spring and Hibernate。但是,排名较高的答案建议直接在数据库级别实现行级安全性。

与Shiro合作后,我可以说可以做到。但是,您必须实现自己的安全性结构(Realms,Permissions,Annotations)以适应您描述的功能类型。一种方法是添加一个类似于上一个示例中的注释,指示该方法需要权限检查。此注释将与Interceptor绑定,Interceptor将生成相应的权限,然后调用安全框架来验证权限。

它看起来像这样。

方法:

@RequiresAuthorization
@Entitled
public AccountDetails getAccountDetails(@Account String accountId) {...}

拦截器:

@Interceptor
@Entitled
public class EntitledInterceptor {
    @AroundInvoke
    public void interceptOrder(InvocationContext ctx) {
        // return type is AccountDetails 
        // parameter[0] is acccoundId
        Permission p = new CustomPermission(context.getMethod().getReturnType(),
                                            ctx.getParameters()[0]);
        if(SecurityUtils.getSubject().isPermitted(p)){
          return ctx.proceed();
        } else {
         throw new RowLevelSecurityException("No access!");
        }
}

领域:

public boolean isPermitted(SubjectPrincipals principal, Permission p){
    if( p instanceof CustomPermission){
        CustomPermission cp = (CustomPermission) p;
        Class<?> type = cp.getType(); //AccountDetails
        Integer id = cp.getId(); //accountId
        Integer userId = principal.getPrimaryPrincipal(); //or username
        customPermissionCheckingLogic(userId, type, id);
    }
}

显然,这种实现依赖于CDI,您可以根据提供的对象类型确定要检查的表(JPA注释在这方面起作用)。此外,可能有一些方法可以挂钩Shiro的注释扫描,以提供比我在这里所做的更直接/原生的权限功能。

Documentation on CDI interceptors.