【问题标题】:Can you use SpEL in @PreAuthorize referencing a instance property?您可以在 @PreAuthorize 中使用 SpEL 引用实例属性吗?
【发布时间】:2019-12-21 05:23:46
【问题描述】:

有没有办法在一个类中使用一个局部变量(下面的authorizedRoles),它设置了所有角色来授予对 hasAnyRole 值的端点的访问权限?例如,我想要一个角色列表,在配置中定义,并像这样填充 @PreAuthorize 中的 hasAnyRole:

@Controller("myController")
public class MyController {
private String authorizedRoles;

@Autowired
public MyController(ObjectMapper objectMapper, @Value("#{'${security.authorized-roles}'.split(',')}") String authorizedRoles) {
    this.objectMapper = objectMapper;
    this.request = request;
    this.authorizedRoles = authorizedRoles;
}

@RequestMapping(value = "/id", produces = { "application/json" }, consumes = { "application/json" }, method = RequestMethod.POST)
@PreAuthorize("hasAnyRole('#myController.authorizedRoles')")
public ResponseEntity<IdResponse> idPost(@RequestBody IdRequest body) {
  ...
}

【问题讨论】:

  • 你遇到了什么错误?代码看起来不错。
  • 没有错误,只是没有使用该属性。

标签: spring spring-security spring-el


【解决方案1】:

您不能使用 SpEL 以这种方式访问​​私有字段;您需要添加public String getAuthorizedRoles(),当您引用authorizedRoles 属性时,SpEL 会调用它。 SpEL 了解 JavaBean 约定。

编辑

hasAnyRole() 接受String[]

@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class So59419703Application extends GlobalAuthenticationConfigurerAdapter {

    public static void main(String[] args) {
        SpringApplication.run(So59419703Application.class, args);
    }

    @Autowired
    private Foo foo;

    @Bean
    public ApplicationRunner runner() {
        return args -> {
            SecurityContext ctx = SecurityContextHolder.createEmptyContext();
            ctx.setAuthentication(new UsernamePasswordAuthenticationToken("foo", "bar"));
            SecurityContextHolder.setContext(ctx);
            System.out.println(foo.bar());
        };
    }

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("foo").password("bar").roles("baz");
    }

    public interface Foo {

        String bar();

        String[] getRoles();

    }

    @Component("foo")
    public static class FooImpl implements Foo {

        private final String[] roles = StringUtils.commaDelimitedListToStringArray("admin,user,baz");

        @Override
        @PreAuthorize("hasAnyRole(@foo.roles)")
        public String bar() {
            return "authOk";
        }

        @Override
        public String[] getRoles() {
            return this.roles;
        }

    }

}
authOk

【讨论】:

  • 感谢您的帮助!看起来那没有用。我添加了一个公共 getter,并尝试了 @PreAuthorize("hasAnyRole('#myController.authorizedRoles')")@PreAuthorize("hasAnyRole('#authorizedRoles')")
  • 你需要使用@ 而不是# 来引用一个bean,它不应该用引号引起来;试试"hasAnyRole(@myController.authorizedRoles)"
  • hasAnyRole 的参数必须是 String[] - 请参阅 SecurityExpressionRoot - public final boolean hasAnyRole(String... roles),因此您的 getter 需要将角色返回为 String[] 而不是 String。如果您的角色以逗号分隔,则可以使用 StringUtils.commaDelimitedListToStringArray
  • 为我工作;添加了一个示例。
  • 确实如此。感谢您的样品和额外的帮助。非常感谢。
猜你喜欢
  • 2013-02-06
  • 2010-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
  • 2013-08-23
相关资源
最近更新 更多