Spring Security 在@PreAuthorize中使用请求头值

mm5n2pyu  于 2023-10-20  发布在  Spring
关注(0)|答案(3)|浏览(174)

是否可以在@PreAuthorize中使用请求头值?
在我的应用程序中,所有请求都包含一个自定义头,我需要将其与用户角色结合使用,以确定是否应该允许他们访问控制器。
如果有人手动指定一个头,这是可以的,因为这不会是一个安全问题,因为最终角色将控制这一点。但是我需要使用它来减少在每个控制器方法中手动检查的次数。
谢谢你,马特

rsl1atfo

rsl1atfo1#

这可能是最快的方法,如果你只在几个地方使用它。

@GetMapping(value = "/private-api-method")
@PreAuthorize("#request.getHeader('header-name') == 'localhost:8080'")
public ResponseEntity<String> privateApiMethod(HttpServletRequest request) {
    return ResponseEntity.ok("OK!");
}

OR

@GetMapping(value = "/private-api-method")
@PreAuthorize("#header == 'localhost:8080'")
public ResponseEntity<String> privateApiMethod(@RequestHeader("header-name") String header) {
    return ResponseEntity.ok("OK!");
}

2 -这可能是最好的方法,如果你会在许多地方使用它。

  • (在SecurityService中,您可以添加多种不同的检查方法。)*
@GetMapping(value = "/private-api-method")
@PreAuthorize("@securityService.checkHeader(#request)")
public ResponseEntity<String> privateApiMethod(HttpServletRequest request) {
    return ResponseEntity.ok("OK!");
}

3 -你可以为自己选择一个特殊的方法
A Custom Security Expression with Spring Security

j8ag8udp

j8ag8udp2#

由于您打算为每个控制器方法检查特定的头/cookie/request-attribute,因此应该选择Filter,因为这将是一个标准,并且您可以通过从OncePerRequestFilter扩展来保证它对每个方法执行一次,并且只执行一次
话虽如此,有两种方法可以实现这一点:

  • 通过扩展AbstractAuthenticationProcessingFilterOncePerRequestFilter

为此,你可以参考spring-security jwt token validation流程,这是所有人都提倡的:

  • 在所需的控制器方法处添加方法安全性,如@PreAuthorize("hasAuthority('USER_ROLE')")
  • 拦截UsernamePasswordAuthenticationFilter之前的请求,从请求中提取Authentication报头或cookies,并验证声明的令牌值。
public class CustomHeaderAuthFilter extends AbstractAuthenticationProcessingFilter{

@Override
  public Authentication attemptAuthentication(
      HttpServletRequest request, HttpServletResponse response){

// Get all the headers from request, throw exception if your header not found    
Enumeration<String> reqHeaders =  request.getHeaderNames();

    Assert.notNull(reqHeaders, "No headers found. Abort operation!");

    Collections.list(reqHeaders)
        .stream()
        .filter(header_ -> header_.equals("TARGET_HEADER_NAME"))
.findAny().ifPresent(header_ -> {
          // header found, would go for success-andler
    });
    
    // Here it means request has no target header
    SecurityContextHolder.clearContext();
    failureHandler.onAuthenticationFailure(request, response, new CustomException(""));
  }

}

通过这种方式,您需要使用WebSecurityConfigurerAdapter注册您的过滤器,如果您从AbstractAuthenticationProcessingFilter扩展,则还可以提供AuthenticationProvider
1.通过使用@RequestHeader访问rest控制器中的HTTP Headers,如dm-tr所提到的。

dsf9zpds

dsf9zpds3#

也许你可以试试这个

@PreAuthorize("hasAuthority('ROLE_SOMETHING')")
@RequestMapping("PATH")
public void checkIt(@RequestHeader("header-name") String header) {
    if (null != header /* && header meets certain condition*/) {
        // stuff
    } else throw new ResponseStatusException(HttpStatus.FORBIDDEN); // PERMISSION NOT GRANTED, 403 ERROR
}

相关问题