在@PreAuthorize 中使用请求 header 值
Using a request header value in @PreAuthorize
是否可以在@PreAuthorize 中使用请求 header 值?
在我的应用程序中,所有请求都包含一个自定义 header,我需要将其与用户角色结合使用以确定是否应允许它们访问控制器。
如果有人手动指定 header 也没关系,因为这不会成为安全问题,因为最终角色将控制它。但我将需要使用它来减少在每个控制器方法中手动检查的次数。
谢谢,
马特
也许你可以试试这个
@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
}
1 - 如果您只在少数地方使用它,这可能是最快的方法。
@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 - 如果您要在很多地方使用它,这可能是最好的方法。 (在SecurityServise
中可以添加多种不同的检查方法。)
@GetMapping(value = "/private-api-method")
@PreAuthorize("@securityService.checkHeader(#request)")
public ResponseEntity<String> privateApiMethod(HttpServletRequest request) {
return ResponseEntity.ok("OK!");
}
3 - 您可以选择适合自己的特殊方法
由于您打算为每个控制器方法检查一个特定的 header/cookie/request-attribute,您应该选择一个过滤器,因为这将是一个标准,并且您可以保证它对每个方法都执行而且从 OncePerRequestFilter
扩展也只有一次
话虽如此,您可以通过两种方式实现这一目标:
通过扩展 AbstractAuthenticationProcessingFilter
或 OncePerRequestFilter
为此,您可以参考 spring-security jwt 令牌验证流程,所有人都提倡:
- 在您想要的控制器方法中添加方法安全性
@PreAuthorize("hasAuthority('USER_ROLE')")
- 拦截
UsernamePasswordAuthenticationFilter
之前的请求,从请求中提取 Authentication
header 或 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
- 如 dm-tr 所述,使用
@RequestHeader
在 rest 控制器中访问 HTTP Headers
。
是否可以在@PreAuthorize 中使用请求 header 值?
在我的应用程序中,所有请求都包含一个自定义 header,我需要将其与用户角色结合使用以确定是否应允许它们访问控制器。
如果有人手动指定 header 也没关系,因为这不会成为安全问题,因为最终角色将控制它。但我将需要使用它来减少在每个控制器方法中手动检查的次数。
谢谢, 马特
也许你可以试试这个
@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
}
1 - 如果您只在少数地方使用它,这可能是最快的方法。
@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 - 如果您要在很多地方使用它,这可能是最好的方法。 (在SecurityServise
中可以添加多种不同的检查方法。)
@GetMapping(value = "/private-api-method")
@PreAuthorize("@securityService.checkHeader(#request)")
public ResponseEntity<String> privateApiMethod(HttpServletRequest request) {
return ResponseEntity.ok("OK!");
}
3 - 您可以选择适合自己的特殊方法
由于您打算为每个控制器方法检查一个特定的 header/cookie/request-attribute,您应该选择一个过滤器,因为这将是一个标准,并且您可以保证它对每个方法都执行而且从 OncePerRequestFilter
话虽如此,您可以通过两种方式实现这一目标:
通过扩展
AbstractAuthenticationProcessingFilter
或OncePerRequestFilter
为此,您可以参考 spring-security jwt 令牌验证流程,所有人都提倡:
- 在您想要的控制器方法中添加方法安全性
@PreAuthorize("hasAuthority('USER_ROLE')")
- 拦截
UsernamePasswordAuthenticationFilter
之前的请求,从请求中提取Authentication
header 或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
- 如 dm-tr 所述,使用
@RequestHeader
在 rest 控制器中访问HTTP Headers
。