Java 避免@Secured注释的重复值

Java 避免@Secured注释的重复值,java,spring-boot,spring-security,Java,Spring Boot,Spring Security,我正在尝试使用@Secured保护我的服务方法,如下所示: public interface IUserService { @Secured({"ROLE_ROLE1", "ROLE_ROLE2"}) ResponseEntity saveUser(CreateUserDtoRequest userDto); } 我想知道是否有一种方法可以在变量中定义{“ROLE\u ROLE1”,“ROLE\u ROLE2”},并从属性文件中读取其值? 如

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

public interface IUserService {

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

}
我想知道是否有一种方法可以在变量中定义
{“ROLE\u ROLE1”,“ROLE\u ROLE2”}
,并从
属性文件中读取其
? 如果你能给我建议一个窍门,那就太好了:

  • 在其他方法中删除重复的
    {“ROLE\u ROLE1”、“ROLE\u ROLE2”}
  • 如果将来访问方法所需的角色发生更改,则无需更改代码、重新编译并再次部署

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


    开发自定义的
    MethodSecurityExpressionOperations
    在本文中,您将看到如何处理新的自定义安全方法(第5节)或覆盖当前的
    hasAuthority
    one(第6节)


    开发自定义方法以在
    SpEL
    可能是esier选项,步骤可以是以下步骤:

    1.
    应用程序.yml
    中包含允许的角色(或
    属性

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

    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();
      }
    
    }
    
    import org.springframework.beans.factory.annotation.Value;
    导入org.springframework.security.core.Authentication;
    导入org.springframework.security.core.GrantedAuthority;
    导入org.springframework.security.core.context.SecurityContext;
    导入org.springframework.security.core.context.SecurityContextHolder;
    导入org.springframework.stereotype.Component;
    导入org.springframework.util.CollectionUtils;
    导入java.util.Collection;
    导入java.util.Optional;
    导入java.util.Set;
    导入java.util.stream.stream;
    导入静态java.util.Optional.ofNullable;
    导入静态java.util.stream.Collectors.toSet;
    @组成部分
    来自PropertyRoleSecurityCheck的公共类{
    私有最终静态字符串角色_SEPARATOR=“,”;
    @值(${security.rolesAllowed}”)
    允许私人字符串原始角色;
    公共布尔验证角色(){
    返回getPrincipalAuthorities()
    .map(auth->{
    Set rolesAllowed=Stream.of(rawsrolesallowed.split(角色分隔符))
    .map(字符串::trim)
    .收集(toSet());
    返回verifyAllowedRoles(角色允许,身份验证);
    })
    .orElse(假);
    }
    
    私有选项您可以在应用程序中使用
    @PreAuthorize
    ,但您可以定义用户权限并将其作为角色添加到用户中。User1->role\u adming->[保存用户,编辑用户]。这与您的方法类似:
    @PreAuthorize(value=“hasAnyAuthority”(+)T(ua.pmdev.auctionizer.rest.user.domain.UserPermission).ADMIN.name(),“+”T(ua.pmdev.auctionizer.rest.user.domain.UserPermission.ALL.name()))
    我没有问题解决
    @PreAuthorize
    的问题,因为在线上已经有了一些解决方案。因为
    @Secured
    注释更适合在我的情况下使用(除了不必使用
    conditionalEL
    之外,由于没有
    hasRole
    的内容,因此更简单,可读性更高),我想知道是否可以动态检查
    @Secured
    中的
    角色
    ,谢谢@doctore的回复。您的解决方案看起来很好,我对此表示赞同。此外,我将尝试该解决方案并让您知道结果。该解决方案有效。谢谢。只需一件小事:从那时起就不需要
    角色分隔符
    您可以将
    rawRolesAllowed
    定义为
    List
    ,而不是
    String
    ,很乐意提供帮助。关于
    List
    ,是的,有更简单的方法来使用它:
    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();
      }
    
    }
    
    @PreAuthorize("@fromPropertyRoleSecurityCheck.verifyRoles()")
    public ResponseEntity<MyDto> findById(@PathVariable @Positive Integer id) {
      ...
    }