避免@Secured 注释的重复值 [英] Avoid repetitive values for @Secured annotation

查看:23
本文介绍了避免@Secured 注释的重复值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 @Secured 来保护我的服务方法,如下所示:

I am trying to secure my service methods using @Secured as below:

public interface IUserService {

@Secured({"ROLE_ROLE1", "ROLE_ROLE2"})
    ResponseEntity saveUser(CreateUserDtoRequest userDto);

}

我想知道有没有办法在变量中定义 {ROLE_ROLE1", ROLE_ROLE2"} 并从 属性中读取它的 value 文件?如果你能建议我一个技巧,那就太好了:

I wanna know is there a way to define {"ROLE_ROLE1", "ROLE_ROLE2"} in a variable and read its value from a properties file? That would be great if you can suggest me a trick, to:

  1. 去除其他方法中重复的{ROLE_ROLE1"、ROLE_ROLE2"}
  2. 如果将来访问方法所需的角色发生变化,则无需更改代码、重新编译和再次部署.

推荐答案

有几种方法可以满足您的需求:

There are several ways to do what you need:

在这个教程中,您将看到如何处理新的自定义安全方法(第 5 节)或覆盖当前的hasAuthority(第 6 节)

In this tutorial you will see how to deal with a new custom security method (section 5) or override the current hasAuthority one (section 6)

可能是更简单的选择,步骤可能如下:

Probably an esier option, the steps could be the following ones:

1. 在您的 application.yml(或 properties)中包含允许的角色

1. Include the allowed roles in your application.yml (or properties)

security:
  rolesAllowed: ADMIN,USER

2. 定义类以检查这些角色和授权用户.例如:

2. Define the class to check those roles and authorized user ones. For example:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;

import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toSet;

@Component
public class FromPropertyRoleSecurityCheck {

  private final static String ROLE_SEPARATOR = ",";

  @Value("${security.rolesAllowed}")
  private String rawRolesAllowed;


  public boolean verifyRoles() {
    return getPrincipalAuthorities()
            .map(auth -> {
                Set<String> rolesAllowed = Stream.of(rawRolesAllowed.split(ROLE_SEPARATOR))
                        .map(String::trim)
                        .collect(toSet());
                return verifyAllowedRoles(rolesAllowed, auth);
            })
            .orElse(false);
  }


  private Optional<Collection<? extends GrantedAuthority>> getPrincipalAuthorities() {
    return ofNullable(SecurityContextHolder.getContext())
            .map(SecurityContext::getAuthentication)
            .map(Authentication::getAuthorities);
  }


  private boolean verifyAllowedRoles(final Collection<String> rolesAllowed,
                                     final Collection<? extends GrantedAuthority> principalAuthorities) {
    if (CollectionUtils.isEmpty(rolesAllowed)) {
        return true;
    }
    if (CollectionUtils.isEmpty(principalAuthorities)) {
        return false;
    }
    Set<String> rolesDiff = principalAuthorities.stream().map(GrantedAuthority::getAuthority).collect(toSet());
    rolesDiff.removeAll(rolesAllowed);
    return rolesDiff.size() != principalAuthorities.size();
  }

}

3. 添加安全检查:

@PreAuthorize("@fromPropertyRoleSecurityCheck.verifyRoles()")
public ResponseEntity<MyDto> findById(@PathVariable @Positive Integer id) {
  ...
}


如果你不想每次这些角色改变时都重新编译/部署项目,你可以将它们保存在一个外部存储中,例如数据库(更新任何提供的示例来处理这种情况).在第二个中,我使用了一个属性来保持简单,但是很容易在 FromPropertyRoleSecurityCheck 中包含一个 Repository 以从数据库中获取它们.


If you don't want to recompile/deploy the project every time those roles change, you can save them in an external storage like database for example (shouldn't be a problem to update any of provided examples to deal with such situations). In the second one I used a property to keep it simple, but is quite easy to include a Repository in FromPropertyRoleSecurityCheck to get them from database.

PD.提供链接和自定义链接的示例是在控制器层开发的,但它们也应该在服务层中工作.

PD. Examples of provided link and custom one were developed in Controller layer, but they should work in the Service one too.

这篇关于避免@Secured 注释的重复值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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