【问题标题】:spring-boot custom annotation for validating headers用于验证标头的 spring-boot 自定义注释
【发布时间】:2019-02-26 11:12:30
【问题描述】:

我正在使用 spring-boot-1.5.10,并且在我的应用程序中使用 spring-security。我想创建一个自定义注释,并且应该使用 securityContext holder...让我用示例代码详细说明我的问题。

curl -X GET -H "roles: READ" -H "Content-Type: application/json" -H “接受:应用程序/json” -H “应用程序名称:样本” -H “应用程序 ID:样本” -H "customer-id: 123" -H "market: EN" -H "country-code: EN" -H "Accept-Language: application/json" -H "Cache-Control: no-cache" "http://localhost:9992/api/v1/apps"

控制器

@GetMapping("/apps")
@PreAuthorize("hasAnyAuthority('ROLE_READ', 'ROLE_WRITE')")
public ResponseEntity<List<Apps>> getApps(@AuthenticationPrincipal AppAuthentication appAuthentication) {
    if(appAuthentication.isGrantedAnyOf("ROLE_READ") && isBlank(appAuthentication.getAppContext().customerId())) {
        throw new IllegalArgumentException("Missing header customerId");
    }
    if(appAuthentication.isGrantedAnyOf("ROLE_WRITE") && isBlank(appAuthentication.getAppContext().customerId()) && isBlank(appAuthentication.getAppContext().appId())) {
        throw new IllegalArgumentException("Missing header customerId & AppId");
    }
    //write business logic here
}

spring-security preAuthorize 只会检查角色是否被允许。此外,我可以增强 preAuthorize 注释,但它对于许多微服务来说很常见,而且我无权触及安全领域。所以,我想创建一个自定义注释。我们应该配置角色和标头以验证特定角色。如下所示

@GetMapping("/apps")
@PreAuthorize("hasAnyAuthority('ROLE_READ', 'ROLE_WRITE')")
@ValidateHeaders("role=ROLE_READ",value={"customerId","app-id"})
public ResponseEntity<List<Apps>> getApps(@AuthenticationPrincipal AppAuthentication appAuthentication) {
    //write business logic here
}

任何提示都会非常明显。

【问题讨论】:

  • 希望这会有所帮助:baeldung.com/…
  • 听起来您正在寻找的是 Spring Security ACL。
  • @MebinJoe 感谢您的快速链接。这解释了有关 preAuthorize 的更多信息。正如我在问题中提到的,我无权增强 preAuthorize 注释。是否可以使用自定义注释?
  • @VelNaga 您在寻找自定义过滤器或自定义注释吗?
  • enhance the preAuthorize annotation 是什么意思? if 表达式可以很容易地写为表达式的一部分,这就是它的用途。因此,与其试图在原地硬塞一些额外的/新的东西,不如扩展表达式,因为这是唯一正确的方法。

标签: java spring spring-boot spring-mvc spring-security


【解决方案1】:

Disclamer - 我正在使用 Spring Boot 2,所以并非所有内容都适用于您

这是我不久前实现的东西的精简版。 我建议为角色和值实现枚举。

您不能从 @before 注释进行重定向,因此您必须抛出异常并使用全局 ex 处理程序捕获它,然后从那里重定向。

考虑在注释中添加可选字段——如果是多个角色,匹配全部或一个, 重定向路径,在无法访问时调用的异常类型。然后在异常处理程序中,您可以根据调用的异常进行重定向。由于您正在从 gloabl ex 处理程序进行重定向,因此如果您添加重定向路径,则必须将其与您抛出的异常捆绑在一起,这意味着您需要自定义异常。

注释

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateHeaders {

    Roles[] roles();
    String[] values();
}

方面类

@Aspect
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired)) //Autowired annotated lombok generated constructor
public class ValidateHeadersAspect {


    private final @NonNull HttpServletRequest request; //Inject request to have header access
    private final @NonNull UserService userService;//Your user service here

    //Aspect can be placed on clas or method
    @Before("within(@com.org.package.ValidateHeaders *) || @annotation(com.org.package.ValidateHeaders)") 
    public void validateAspect(JoinPoint joinPoint) throws Throwable {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        HasAccess validateHeaders = method.getAnnotation(ValidateHeaders.class);

        if(validateHeaders == null) { //If null it was a class level annotation
            Class annotatedClass = joinPoint.getSignature().getDeclaringType();
            validateHeaders = (ValidateHeaders)annotatedClass.getAnnotation(ValidateHeaders.class);
        }

        Roles[] roles = validateHeaders.roles(); //Roles listed in annotation
        String[] values = validateHeaders.values(); //Values listed in 


        //Validate request here ... determine isAuthorised


        if( !isAuthorized ){
            throw new HeaderAuthrizationException()
        }
    }

}

异常处理

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(HeaderAuthrizationException.class)
    public RedirectView HeaderAuthrizationException(HeaderAuthrizationException ex) {
        return new RedirectView("/redirect");
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-04
    • 2016-09-26
    • 1970-01-01
    • 2017-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多