如何在Spring Security @ PreAuthorize/@ PostAuthorize批注中使用自定义表达式 [英] How to use custom expressions in Spring Security @PreAuthorize/@PostAuthorize annotations

查看:521
本文介绍了如何在Spring Security @ PreAuthorize/@ PostAuthorize批注中使用自定义表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法在@Preauthorize块中创建更具表现力的语句?这是我重复的例子,因为@Preauthorize并非开箱即用.

Is there a way to create more expressive statements in @Preauthorize blocks? Here's an example of something I find myself repeating, because the @Preauthorize is not terribly smart out of the box.

@RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public void deleteGame(@PathVariable int id, @ModelAttribute User authenticatingUser) {
    Game currentGame = gameService.findById(id);
    if(authenticatingUser.isAdmin() || currentGame.getOwner().equals(authenticatingUser)) {
        gameService.delete(gameService.findById(id));
    } else {
        throw new SecurityException("Only an admin, or an owner can delete a game.");
    }
}

我想要的是类似的东西.

What I would prefer is something like.

@RequestMapping(value = "{id}", method = RequestMethod.DELETE)
@Preauthorize(isAdmin(authenicatingUser) OR isOwner(authenicatingUser, id)
public void deleteGame(@PathVariable int id, @ModelAttribute User authenticatingUser, @ModelAttribute currentGame ) { //I'm not sure how to add this either :(
   gameService.delete(gameService.findById(id));
}

部分问题是,我需要查询数据库以获取其中一些内容以验证权限,例如查询数据库以获取游戏副本,然后将游戏所有者与提出请求的人.我不太确定所有这些如何在@Preauthorize注释处理器的上下文中运行,或者如何将这些东西添加到@Preauthorize(")value属性中可用的对象集合中.

Part of the problem is that I need to make a query to the database to fetch some of this stuff to verify permissions, such as querying the database to get a copy of the game, and then comparing the owner of the game to the person making the request. I'm not really sure how all of that operates within the context of a @Preauthorize annotation processor, or how I add things to the collection of objects made available in the @Preauthorize("") value attribute.

推荐答案

1)首先,您必须重新实现MethodSecurityExpressionRoot,其中包含额外的方法特定功能.最初的Spring Security实现是程序包私有的,因此不可能仅对其进行扩展.我建议检查给定类的源代码.

1) First you have to reimplement MethodSecurityExpressionRoot which contains extra method-specific functionality. The original Spring Security implementation is package private and hence it is not possible to just extend it. I suggest checking the source code for the given class.

public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {

    // copy everything from the original Spring Security MethodSecurityExpressionRoot

    // add your custom methods

    public boolean isAdmin() {
        // do whatever you need to do, e.g. delegate to other components

        // hint: you can here directly access Authentication object 
        // via inherited authentication field
    }

    public boolean isOwner(Long id) {
        // do whatever you need to do, e.g. delegate to other components
    }
}

2)接下来,您必须实现将使用上面定义的CustomMethodSecurityExpressionRoot的自定义MethodSecurityExpressionHandler.

2) Next you have to implement custom MethodSecurityExpressionHandler that will use the above defined CustomMethodSecurityExpressionRoot.

public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {

    private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();

    @Override
    public void setReturnObject(Object returnObject, EvaluationContext ctx) {
        ((MethodSecurityExpressionRoot) ctx.getRootObject().getValue()).setReturnObject(returnObject);
    }

    @Override
    protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
        MethodInvocation invocation) {
        final CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
        root.setThis(invocation.getThis());
        root.setPermissionEvaluator(getPermissionEvaluator());
        root.setTrustResolver(this.trustResolver);
        root.setRoleHierarchy(getRoleHierarchy());

        return root;
    }
}

3)在您的上下文中定义表达式处理程序bean,例如通过XML,您可以执行以下操作

3) Define expression handler bean in your context, e.g. via XML you can do it as follows

<bean id="methodSecurityExpressionHandler"
    class="my.package.CustomMethodSecurityExpressionHandler">
    <property name="roleHierarchy" ref="roleHierarchy" />
    <property name="permissionEvaluator" ref="permissionEvaluator" />
</bean>

4)注册上面定义的处理程序

4) Register the above defined handler

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

5)然后只需在@PreAuthorize和/或@PostAuthorize批注中使用定义的表达式

5) Then just use the defined expressions in your @PreAuthorize and/or @PostAuthorize annotations

@PreAuthorize("isAdmin() or isOwner(#id)")
public void deleteGame(@PathVariable int id, @ModelAttribute currentGame) {
    // do whatever needed
}

还有一件事.使用方法级别的安全性来保护控制器方法的安全性不是很常见,而是使用业务逻辑来保护方法(也就是您的服务层方法).然后,您可以使用类似下面的内容.

And one more thing. It is not very common to use method level security to secure controller methods but rather to secure methods with business logic (a.k.a. your service layer methods). Then you could use something like the below.

public interface GameService {

    // rest omitted

    @PreAuthorize("principal.admin or #game.owner = principal.username")
    public void delete(@P("game") Game game);
}

但是请记住,这只是一个例子.它希望实际的主体具有isAdmin()方法,并且游戏具有getOwner()方法,返回所有者的用户名.

But keep in mind that this is just an example. It expects that the actual principal has isAdmin() method and that the game has getOwner() method returning username of the owner.

这篇关于如何在Spring Security @ PreAuthorize/@ PostAuthorize批注中使用自定义表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆