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

查看:36
本文介绍了如何在 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.");
    }
}

我更喜欢类似的东西.

@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("") 值属性中提供的对象集合中.

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) 接下来你必须实现自定义的MethodSecurityExpressionHandler,它将使用上面定义的CustomMethodSecurityExpressionRoot.

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天全站免登陆