java - 使用从 KeyCloak JWT 中提取角色的 @PreAuthorize(hasRole('ROLE_NEW')) 注释保护 REST API
问题描述
我的目标是使用@PreAuthorize(hasRole('ROLE_NEW'))
注释在 Spring Boot 应用程序中保护 REST API 端点。角色必须从 KeyCloak 提供的 JWT 中提取。
RestController 在下面。该项目与SpringBoot REST Service Protected Using Keycloak Authorization Services相同。
@RestController
public class ApplicationController {
@PreAuthorize(hasRole('ROLE_NEW'))
@RequestMapping(value = "/api/resourceannotated", method = RequestMethod.GET)
public String handleResourceAnnotated() {
return createResponse();
}
@RequestMapping(value = "/api/resourcea", method = RequestMethod.GET)
public String handleResourceA() {
return createResponse();
}
@RequestMapping(value = "/api/resourceb", method = RequestMethod.GET)
public String handleResourceB() {
return createResponse();
}
@RequestMapping(value = "/api/premium", method = RequestMethod.GET)
public String handlePremiumResource() {
return createResponse();
}
@RequestMapping(value = "/api/admin", method = RequestMethod.GET)
public String handleAdminResource() {
return createResponse();
}
private String createResponse() {
return "Access Granted";
}
角色为NEW的用户测试已添加到KeyCloak 中,我希望使用 JWT 发送到/ api/resourceannotated端点的请求仅授权给角色为NEW的用户,该角色将从JWT中提取。
动机是将请求保存到KeyCloak,它使用策略执行器强制对 /api/resourcea、/api/resourceb、/api/premium、/api/admin端点的访问控制。
如何正确执行?尝试将 JWT 与 Spring Security 的 @PreAuthorize 注释一起用于方法特定的安全性,并在您的SPRING BOOT 2 应用程序中使用 KEYCLOAK ,但未成功。我收到以下错误:
{ "timestamp": "2018-08-30T14:37:39.409+0000", "status": 401, "error": "Unauthorized", "message": "Unauthorized", "path": "/api/resourceannotated " }
在调试模式下运行时会打印 2 条消息:
2018-08-30 17:55:47.586 调试 31006 --- [nio-8180-exec-3] osbwsfOrderedRequestContextFilter:将请求上下文绑定到线程:org.apache.catalina.connector.RequestFacade@62b92856 2018-08-30 17: 55:47.592 调试 31006 --- [nio-8180-exec-3] osbwsfOrderedRequestContextFilter:清除线程绑定请求上下文:org.apache.catalina.connector.RequestFacade@62b92856
为org.springframework.security启用调试日志记录
并得到以下错误:
DEBUG 30677 --- [ main] s.s.c.a.w.c.WebSecurityConfigurerAdapter : Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).
DEBUG 30677 --- [ main] edFilterInvocationSecurityMetadataSource : Adding web access control expression 'authenticated', for org.springframework.security.web.util.matcher.AnyRequestMatcher@1
DEBUG 30677 --- [ main] o.s.s.w.a.i.FilterSecurityInterceptor : Validated configuration attributes
DEBUG 30677 --- [ main] o.s.s.w.a.i.FilterSecurityInterceptor : Validated configuration attributes
INFO 30677 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@31c2affc, org.springframework.security.web.context.SecurityContextPersistenceFilter@f72203, org.springframework.security.web.header.HeaderWriterFilter@2d2acd89, org.springframework.security.web.csrf.CsrfFilter@6e1d4137, org.springframework.security.web.authentication.logout.LogoutFilter@149f5761, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@1237e0be, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@2ab2710, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@6441c486, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@540dbda9, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@27b000f7, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1dc2de84, org.springframework.security.web.session.SessionManagementFilter@1e6dad8, org.springframework.security.web.access.ExceptionTranslationFilter@2d5f7182, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@58a4a74d]
INFO 30677 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
INFO 30677 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8180 (http) with context path ''
INFO 30677 --- [ main] o.k.quickstart.springboot.MyApplication : Started MyApplication in 14.439 seconds (JVM running for 17.843)
INFO 30677 --- [] o.k.a.authorization.PolicyEnforcer : Paths provided in configuration.
INFO 30677 --- [] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
INFO 30677 --- [] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
INFO 30677 --- [] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 73 ms
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG 30677 --- [] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
DEBUG 30677 --- [] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 5 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG 30677 --- [] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /api/resourceannotated' doesn't match 'POST /logout
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 6 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
DEBUG 30677 --- [] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /api/resourceannotated' doesn't match 'POST /login
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 7 of 14 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 8 of 14 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 9 of 14 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 10 of 14 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 11 of 14 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG 30677 --- [] o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@c551e2ad: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@1de6: RemoteIpAddress: 10.88.0.23; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 12 of 14 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG 30677 --- [] o.s.s.w.session.SessionManagementFilter : Requested session ID A64F605948A7B529457A226B238A5EEC is invalid.
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 13 of 14 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG 30677 --- [] o.s.security.web.FilterChainProxy : /api/resourceannotated at position 14 of 14 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG 30677 --- [] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /api/resourceannotated; Attributes: [authenticated]
DEBUG 30677 --- [] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@c551e2ad: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@1de6: RemoteIpAddress: 10.88.0.23; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
DEBUG 30677 --- [] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@14cd10fa, returned: -1
DEBUG 30677 --- [] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
解决方案
推荐阅读
- python - 雪问题 - 存储变量时出错
- javascript - React Native webview 在可选检查时崩溃
- java - 在选项卡上添加假玩家
- ios - 当用户快速将屏幕从纵向更改为横向时,如何使滚动视图内的 UIView 适应屏幕方向
- javascript - 使用 CKEditor 插件防止粘贴图像
- c# - 使用带有自定义向导组件的 EditForm 时,验证消息不可见
- c++ - 未定义符号:NLopt 中的 nlopt_get_errmsg
- html - 过渡属性对悬停时边框大小的奇怪影响
- react-redux - deck.gl - 在地图上突出显示对象的最佳方式?
- linux-kernel - 解决 Kconfig 中的依赖关系