簡體   English   中英

用於驗證標題的spring-boot自定義注釋

[英]spring-boot custom annotation for validating headers

我正在使用spring-boot-1.5.10,並且在我的應用程序中使用spring-security。 我想創建一個自定義批注,並且應該使用securityContextholder ...讓我用示例代碼詳細說明我的問題。

curl -X GET -H“角色:讀取” -H“內容類型:application / json” -H“接受:application / json” -H“應用名稱:sample” -H“應用ID:sample”- H“客戶ID:123” -H“市場:EN” -H“國家/地區代碼:EN” -H“接受語言:application / json” -H“緩存控制:無緩存”“ 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
}

任何提示都是非常可觀的。

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");
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM