Keycloak Spring 引导配置
Keycloak Spring boot configuration
我正在尝试为 SSO 配置 Spring 启动和 Keycloak。
我创建了一个基本的 AngularJS 应用程序,它向 Spring 启动后端发出一些请求。
using this
Angular 应用程序运行良好,现在我正在尝试遵循新的 Spring Boot Keycloak apdater 文档 here
这是我的 keycloak.json,在 WEB-INF 文件夹中。
{
"realm": "my-backend",
"bearer-only": true,
"realm-public-key": "MIIB...",
"auth-server-url": "http://localhost:8180/auth",
"ssl-required": "external",
"resource": "my-backend",
"principal-attribute": "preferred_username",
"credentials": {
"secret": "a75f55ca-8174-4072-8c60-b545c9ebf7e1"
}
这是我的安全配置:
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
/**
* Registers the KeycloakAuthenticationProvider with the authentication manager.
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
/**
* Defines the session authentication strategy.
*/
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
super.configure(http);
http
.authorizeRequests()
.antMatchers("/api/v1*").hasRole("user")
.antMatchers("/admin/hello*").hasRole("admin")
.anyRequest().permitAll();
}
}
'admin' 和 'user' 这 2 个角色是在 Keycloak 中创建的,当前用户有这个角色。
@RestController
@RequestMapping("/")
@CrossOrigin("*")
public class PharmaController {
public class Response{
private String message;
public Response(String msg){
this.message = msg;
}
/**
* @return the message
*/
public String getMessage() {
return message;
}
/**
* @param message the message to set
*/
public void setMessage(String message) {
this.message = message;
}
}
@RequestMapping(
path="api/v1/userinfo",
method = RequestMethod.GET)
@ResponseBody
public void getUserInformation(KeycloakAuthenticationToken token) {
if(token != null){
System.out.println("token :" + token);
try {
System.out.println(token.getAccount().getPrincipal().getName());
System.out.println(token.getAccount().getRoles());
} catch (Exception e) {
// TODO: handle exception
}
}else{
System.out.println("User not connected.");
}
}
@RequestMapping(
path="admin/hello",
method = RequestMethod.GET)
@ResponseBody
public Response adminHello(KeycloakAuthenticationToken token) {
return new Response("Hello");
}
}
- 即使用户没有任何此角色,他也可以通过此响应访问 api/v1/userinfo
{"data":"","status":200,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"http://localhost:8080/api/v1/userinfo","headers":{"Accept":"application/json, text/plain, */*","Access-Control-Allow-Origin":"*","Authorization":"BEARER eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSN2JSQUgtcmUwNnVEMHh4Vlotd1dyWVIycVI0S0pyMDFIZWQ2QmJMNnA4In0.eyJqdGkiOiI3ZDU4ZGM0Yi0wYzgwLTQwZDYtYWE5OC0yNDk5YzEzZTg2NmMiLCJleHAiOjE0ODM5MTY3OTgsIm5iZiI6MCwiaWF0IjoxNDgzOTE2NDk4LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgxODAvYXV0aC9yZWFsbXMvbXktcGhhcm1hIiwiYXVkIjoicGhhcm1hLXdlYmFwcCIsInN1YiI6IjIxMjI2YzNlLWYwY2UtNGRjNC1hYzk0LTRlNTVmZjc4YWRlMSIsInR5cCI6IkJlYXJlciIsImF6cCI6InBoYXJtYS13ZWJhcHAiLCJub25jZSI6Ijg4MWI1MjhhLWFkOTktNDcwYy04YzJiLTlhYjI0MzM2N2IwOCIsImF1dGhfdGltZSI6MTQ4MzkxNjQ5OCwic2Vzc2lvbl9zdGF0ZSI6Ijg4ZmExODJjLTljOTctNGI2Ny1hMTMzLTk5YjFkNmU4OTZiYyIsImFjciI6IjEiLCJjbGllbnRfc2Vzc2lvbiI6IjJiM2FjNDg1LWQ5ZjUtNDc2ZC1hYjQ1LTA2ZGZmM2VjMTQxMiIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjkwMDAiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsInZpZXctcHJvZmlsZSJdfX0sIm5hbWUiOiJVc2VyMSBGTiBVc2VyMSBMTiIsInByZWZlcnJlZF91c2VybmFtZSI6InVzZXIxIiwiZ2l2ZW5fbmFtZSI6IlVzZXIxIEZOIiwiZmFtaWx5X25hbWUiOiJVc2VyMSBMTiIsImVtYWlsIjoidXNlcjFAeW91LmNvbSJ9.M1RvECaBV3jvNXRxQzLzS4bfKnK-gQp85mkr9GD8HbOsGRui81pZP3Pb_NJ-ieaQ7pca7tO_06UNeSqbHut7c1APV3_GEGTnwuCkKdbu1QKrVwXSXMWNyt0nu_MOdjhzG3bQat3aG68b744KdCSi5i8OBg2L4I3Zmc6nPX5vklf1U7LUXyvs_bswLPZEy1_VQ_ACu_BSIVA8iv64Nl4ng4QlEc6pyEHbhQ2pKpE7wNIiZe-ndfeQWU5FgnV0Ya16b2Up9ZnFw7fpGHDGjzlIEV_As3K32vON171OuAhTKmIbVnG4kuoijQzeqHmkoB-ldfMKPPlLheSILtHvRn8WkA"}},"statusText":""}
- 无法到达端点 admin/hello。
这是堆栈跟踪:
[org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@63858877:org.apache.tomcat.util.net.NioChannel@4d4fa76c:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:51832]], Status in: [OPEN_READ], State out: [OPEN]
2017-01-09 07:11:46.739 DEBUG 14692 --- [nio-8080-exec-2] o.a.coyote.http11.Http11InputBuffer : Received [GET /admin/hello HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Allow-Origin: *
Accept: application/json, text/plain, */*
Origin: http://localhost:9000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36
Authorization: BEARER eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSN2JSQUgtcmUwNnVEMHh4Vlotd1dyWVIycVI0S0pyMDFIZWQ2QmJMNnA4In0.eyJqdGkiOiIyMzMzZmI0OC0yMGE2LTQ2YzctODM1YS0wNGRiMDYyNmEyYWEiLCJleHAiOjE0ODM5MTc0MDQsIm5iZiI6MCwiaWF0IjoxNDgzOTE3MTA0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgxODAvYXV0aC9yZWFsbXMvbXktcGhhcm1hIiwiYXVkIjoicGhhcm1hLXdlYmFwcCIsInN1YiI6IjIxMjI2YzNlLWYwY2UtNGRjNC1hYzk0LTRlNTVmZjc4YWRlMSIsInR5cCI6IkJlYXJlciIsImF6cCI6InBoYXJtYS13ZWJhcHAiLCJub25jZSI6IjQwZDc3MzAyLWViNTYtNGFhMS05OTllLTcyNDRiNmY3MTFkYiIsImF1dGhfdGltZSI6MTQ4MzkxNzEwNCwic2Vzc2lvbl9zdGF0ZSI6IjdmODlkODMyLTNkNTktNDc1Yi04NzI3LTRiZGQ5MDc4ODQ5YSIsImFjciI6IjEiLCJjbGllbnRfc2Vzc2lvbiI6IjJiOGNjMzc3LWY1NjUtNGE3NS1iMWY5LWEyNWFlZTY0ZGM3MCIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjkwMDAiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsInZpZXctcHJvZmlsZSJdfX0sIm5hbWUiOiJVc2VyMSBGTiBVc2VyMSBMTiIsInByZWZlcnJlZF91c2VybmFtZSI6InVzZXIxIiwiZ2l2ZW5fbmFtZSI6IlVzZXIxIEZOIiwiZmFtaWx5X25hbWUiOiJVc2VyMSBMTiIsImVtYWlsIjoidXNlcjFAeW91LmNvbSJ9.S5Jhrea_JzlXEuMPSfJ9Sd8HdNQyknklfdZFDMH_vaFWHiQShVVQAhM3wbwrz8NoJs3M6iFnkA-kuMPhCUR52y65HJ9mEXSxrUN6hPY4U9mEYIKw_kGVXFf_xOirA8lO9cvEmw7c7p2BN0DWmi85RshqhM6CEdGAtIL4z-rl-b3UDJkm9dT3uaMxcYb3l8lq0AkixqnaI8seFLdLgacdhfMblnKuyP6bgWUD2jl2X9ruVGfIHQeBdA19WesMJKHm9XqQaF1mjl0AM0k52bU7GZZ6cOD3yFwl2RMAUMlUPPyX9xq2L5kNEsgYdw4qlgdvjLaX_HipqHh7JHQksJv4Sg
Referer: http://localhost:9000/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6,fr;q=0.4
]
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.authenticator.AuthenticatorBase : Security checking request GET /admin/hello
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] org.apache.catalina.realm.RealmBase : No applicable constraints defined
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.authenticator.AuthenticatorBase : Not subject to any constraint
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] org.apache.tomcat.util.http.Parameters : Set encoding to UTF-8
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.w.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade@2683da6f
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /admin/hello' doesn't match 'OPTIONS /**
2017-01-09 07:11:46.741 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2017-01-09 07:11:46.741 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2017-01-09 07:11:46.742 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2017-01-09 07:11:46.742 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2017-01-09 07:11:46.743 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2017-01-09 07:11:46.743 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 5 of 13 in additional filter chain; firing Filter: 'KeycloakPreAuthActionsFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.k.adapters.PreAuthActionsHandler : adminRequest http://localhost:8080/admin/hello
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 6 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /admin/hello' doesn't match 'POST /sso/logout
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 7 of 13 in additional filter chain; firing Filter: 'KeycloakAuthenticationProcessingFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/sso/login']
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/admin/hello'; against '/sso/login'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=Authorization, expectedHeaderValue=null]
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : matched
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Request is to process authentication
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Attempting Keycloak authentication
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] a.s.a.SpringSecurityRequestAuthenticator : Completing bearer authentication. Bearer roles: [uma_authorization]
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] o.k.adapters.RequestAuthenticator : User 'user1' invoking 'http://localhost:8080/admin/hello' on client 'pharma-backend'
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] o.k.adapters.RequestAuthenticator : Bearer AUTHENTICATED
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Auth outcome: AUTHENTICATED
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.authentication.ProviderManager : Authentication attempt using org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider
2017-01-09 07:11:46.872 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2017-01-09 07:11:46.889 DEBUG 14692 --- [nio-8080-exec-2] o.k.a.s.management.HttpSessionManager : Session created: D309F84825BE807C7B34F16B111E92CD
2017-01-09 07:11:46.890 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Registering session D309F84825BE807C7B34F16B111E92CD, for principal user1
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Authentication success using bearer token/basic authentication. Updating SecurityContextHolder to contain: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 8 of 13 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 9 of 13 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 10 of 13 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : SecurityContextHolder not populated with anonymous token, as it already contained: 'org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 11 of 13 in additional filter chain; firing Filter: 'SessionManagementFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] s.CompositeSessionAuthenticationStrategy : Delegating to org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy@29a23c3d
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Registering session D309F84825BE807C7B34F16B111E92CD, for principal user1
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Removing session D309F84825BE807C7B34F16B111E92CD from principal's set of registered sessions
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Removing principal user1 from registry
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] s.CompositeSessionAuthenticationStrategy : Delegating to org.springframework.security.web.csrf.CsrfAuthenticationStrategy@20f0cc02
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@a08a84cd: Authentication: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@1a43aa14
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 12 of 13 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 13 of 13 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /admin/hello' doesn't match 'POST /sso/logout
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/admin/hello'; against '/api/v1*'
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/admin/hello'; against '/admin/hello*'
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /admin/hello; Attributes: [hasRole('ROLE_admin')]
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}
2017-01-09 07:11:46.895 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@58311096, returned: -1
2017-01-09 07:11:46.896 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) ~[spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115) ~[spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
...
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.6.jar:8.5.6]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5ca0c4c5
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@a08a84cd: Authentication: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@1a43aa14
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@2683da6f
2017-01-09 07:11:46.900 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost] : Processing ErrorPage[errorCode=0, location=/error]
2017-01-09 07:11:46.901 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/error]
2017-01-09 07:11:46.902 DEBUG 14692 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
2017-01-09 07:11:46.904 DEBUG 14692 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)]
2017-01-09 07:11:46.904 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'basicErrorController'
2017-01-09 07:11:46.904 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/error] is: -1
2017-01-09 07:11:46.927 DEBUG 14692 --- [nio-8080-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Written [{timestamp=Mon Jan 09 07:11:46 MYT 2017, status=403, error=Forbidden, message=Access is denied, path=/admin/hello}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@45db4b8b]
2017-01-09 07:11:46.927 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2017-01-09 07:11:46.927 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Successfully completed request
2017-01-09 07:11:46.928 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Disabling the response for futher output
2017-01-09 07:11:46.928 DEBUG 14692 --- [nio-8080-exec-2] o.apache.coyote.http11.Http11Processor : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@63858877:org.apache.tomcat.util.net.NioChannel@4d4fa76c:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:51832]], Status in: [OPEN_READ], State out: [OPEN]
我通过用 hasAuthority() 替换 hasRole() 自己解决了这个问题。
我仍然不知道为什么 keycloak 角色映射到 spring 安全权限。欢迎任何解释。
谢谢。
我经历了同样的事情,这是我的发现。
org.springframework.security.access.vote.RoleVoter 假定您的角色从
开始
private String rolePrefix = "ROLE_";
Keycloak 中没有这样的假设(除非你命名所有角色 ROLE_someName),因此实际上没有找到匹配的角色。
类似的解释可以从 Spring SecurityExpressionOperations class 的安全 Javadoc 中获得 hasRole 方法
This is similar to {@link #hasAuthority(String)} except that this method implies
that the String passed in is a role. For example, if "USER" is passed in the
implementation may convert it to use "ROLE_USER" instead. The way in which the role
is converted may depend on the implementation settings.
总而言之,我以与您完全相同的解决方案结束,现在使用 hasAuthority 而不是 hasRole。
您可以实施 SimpleAuthorityMapper() :
@Bean
public GrantedAuthoritiesMapper grantedAuthoritiesMapper() {
SimpleAuthorityMapper mapper = new SimpleAuthorityMapper();
mapper.setConvertToUpperCase(true);
return mapper;
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper( grantedAuthoritiesMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
configureGlobal:这里我们更改授权权限映射器。默认情况下,在 Spring 安全性中,角色以 ROLE_ 为前缀。我们可以在我们的 Realm 配置中更改它,但它可能会让不了解此约定的其他应用程序感到困惑,因此在这里我们分配一个 SimpleAuthorityMapper 以确保不添加前缀。
点击here!
ROLE_ is the prefix default for sring security roles.
我正在尝试为 SSO 配置 Spring 启动和 Keycloak。 我创建了一个基本的 AngularJS 应用程序,它向 Spring 启动后端发出一些请求。 using this
Angular 应用程序运行良好,现在我正在尝试遵循新的 Spring Boot Keycloak apdater 文档 here
这是我的 keycloak.json,在 WEB-INF 文件夹中。
{
"realm": "my-backend",
"bearer-only": true,
"realm-public-key": "MIIB...",
"auth-server-url": "http://localhost:8180/auth",
"ssl-required": "external",
"resource": "my-backend",
"principal-attribute": "preferred_username",
"credentials": {
"secret": "a75f55ca-8174-4072-8c60-b545c9ebf7e1"
}
这是我的安全配置:
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
/**
* Registers the KeycloakAuthenticationProvider with the authentication manager.
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
/**
* Defines the session authentication strategy.
*/
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
super.configure(http);
http
.authorizeRequests()
.antMatchers("/api/v1*").hasRole("user")
.antMatchers("/admin/hello*").hasRole("admin")
.anyRequest().permitAll();
}
}
'admin' 和 'user' 这 2 个角色是在 Keycloak 中创建的,当前用户有这个角色。
@RestController
@RequestMapping("/")
@CrossOrigin("*")
public class PharmaController {
public class Response{
private String message;
public Response(String msg){
this.message = msg;
}
/**
* @return the message
*/
public String getMessage() {
return message;
}
/**
* @param message the message to set
*/
public void setMessage(String message) {
this.message = message;
}
}
@RequestMapping(
path="api/v1/userinfo",
method = RequestMethod.GET)
@ResponseBody
public void getUserInformation(KeycloakAuthenticationToken token) {
if(token != null){
System.out.println("token :" + token);
try {
System.out.println(token.getAccount().getPrincipal().getName());
System.out.println(token.getAccount().getRoles());
} catch (Exception e) {
// TODO: handle exception
}
}else{
System.out.println("User not connected.");
}
}
@RequestMapping(
path="admin/hello",
method = RequestMethod.GET)
@ResponseBody
public Response adminHello(KeycloakAuthenticationToken token) {
return new Response("Hello");
}
}
- 即使用户没有任何此角色,他也可以通过此响应访问 api/v1/userinfo
{"data":"","status":200,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"http://localhost:8080/api/v1/userinfo","headers":{"Accept":"application/json, text/plain, */*","Access-Control-Allow-Origin":"*","Authorization":"BEARER eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSN2JSQUgtcmUwNnVEMHh4Vlotd1dyWVIycVI0S0pyMDFIZWQ2QmJMNnA4In0.eyJqdGkiOiI3ZDU4ZGM0Yi0wYzgwLTQwZDYtYWE5OC0yNDk5YzEzZTg2NmMiLCJleHAiOjE0ODM5MTY3OTgsIm5iZiI6MCwiaWF0IjoxNDgzOTE2NDk4LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgxODAvYXV0aC9yZWFsbXMvbXktcGhhcm1hIiwiYXVkIjoicGhhcm1hLXdlYmFwcCIsInN1YiI6IjIxMjI2YzNlLWYwY2UtNGRjNC1hYzk0LTRlNTVmZjc4YWRlMSIsInR5cCI6IkJlYXJlciIsImF6cCI6InBoYXJtYS13ZWJhcHAiLCJub25jZSI6Ijg4MWI1MjhhLWFkOTktNDcwYy04YzJiLTlhYjI0MzM2N2IwOCIsImF1dGhfdGltZSI6MTQ4MzkxNjQ5OCwic2Vzc2lvbl9zdGF0ZSI6Ijg4ZmExODJjLTljOTctNGI2Ny1hMTMzLTk5YjFkNmU4OTZiYyIsImFjciI6IjEiLCJjbGllbnRfc2Vzc2lvbiI6IjJiM2FjNDg1LWQ5ZjUtNDc2ZC1hYjQ1LTA2ZGZmM2VjMTQxMiIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjkwMDAiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsInZpZXctcHJvZmlsZSJdfX0sIm5hbWUiOiJVc2VyMSBGTiBVc2VyMSBMTiIsInByZWZlcnJlZF91c2VybmFtZSI6InVzZXIxIiwiZ2l2ZW5fbmFtZSI6IlVzZXIxIEZOIiwiZmFtaWx5X25hbWUiOiJVc2VyMSBMTiIsImVtYWlsIjoidXNlcjFAeW91LmNvbSJ9.M1RvECaBV3jvNXRxQzLzS4bfKnK-gQp85mkr9GD8HbOsGRui81pZP3Pb_NJ-ieaQ7pca7tO_06UNeSqbHut7c1APV3_GEGTnwuCkKdbu1QKrVwXSXMWNyt0nu_MOdjhzG3bQat3aG68b744KdCSi5i8OBg2L4I3Zmc6nPX5vklf1U7LUXyvs_bswLPZEy1_VQ_ACu_BSIVA8iv64Nl4ng4QlEc6pyEHbhQ2pKpE7wNIiZe-ndfeQWU5FgnV0Ya16b2Up9ZnFw7fpGHDGjzlIEV_As3K32vON171OuAhTKmIbVnG4kuoijQzeqHmkoB-ldfMKPPlLheSILtHvRn8WkA"}},"statusText":""}
- 无法到达端点 admin/hello。
这是堆栈跟踪:
[org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@63858877:org.apache.tomcat.util.net.NioChannel@4d4fa76c:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:51832]], Status in: [OPEN_READ], State out: [OPEN]
2017-01-09 07:11:46.739 DEBUG 14692 --- [nio-8080-exec-2] o.a.coyote.http11.Http11InputBuffer : Received [GET /admin/hello HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Allow-Origin: *
Accept: application/json, text/plain, */*
Origin: http://localhost:9000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36
Authorization: BEARER eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSN2JSQUgtcmUwNnVEMHh4Vlotd1dyWVIycVI0S0pyMDFIZWQ2QmJMNnA4In0.eyJqdGkiOiIyMzMzZmI0OC0yMGE2LTQ2YzctODM1YS0wNGRiMDYyNmEyYWEiLCJleHAiOjE0ODM5MTc0MDQsIm5iZiI6MCwiaWF0IjoxNDgzOTE3MTA0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgxODAvYXV0aC9yZWFsbXMvbXktcGhhcm1hIiwiYXVkIjoicGhhcm1hLXdlYmFwcCIsInN1YiI6IjIxMjI2YzNlLWYwY2UtNGRjNC1hYzk0LTRlNTVmZjc4YWRlMSIsInR5cCI6IkJlYXJlciIsImF6cCI6InBoYXJtYS13ZWJhcHAiLCJub25jZSI6IjQwZDc3MzAyLWViNTYtNGFhMS05OTllLTcyNDRiNmY3MTFkYiIsImF1dGhfdGltZSI6MTQ4MzkxNzEwNCwic2Vzc2lvbl9zdGF0ZSI6IjdmODlkODMyLTNkNTktNDc1Yi04NzI3LTRiZGQ5MDc4ODQ5YSIsImFjciI6IjEiLCJjbGllbnRfc2Vzc2lvbiI6IjJiOGNjMzc3LWY1NjUtNGE3NS1iMWY5LWEyNWFlZTY0ZGM3MCIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjkwMDAiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsInZpZXctcHJvZmlsZSJdfX0sIm5hbWUiOiJVc2VyMSBGTiBVc2VyMSBMTiIsInByZWZlcnJlZF91c2VybmFtZSI6InVzZXIxIiwiZ2l2ZW5fbmFtZSI6IlVzZXIxIEZOIiwiZmFtaWx5X25hbWUiOiJVc2VyMSBMTiIsImVtYWlsIjoidXNlcjFAeW91LmNvbSJ9.S5Jhrea_JzlXEuMPSfJ9Sd8HdNQyknklfdZFDMH_vaFWHiQShVVQAhM3wbwrz8NoJs3M6iFnkA-kuMPhCUR52y65HJ9mEXSxrUN6hPY4U9mEYIKw_kGVXFf_xOirA8lO9cvEmw7c7p2BN0DWmi85RshqhM6CEdGAtIL4z-rl-b3UDJkm9dT3uaMxcYb3l8lq0AkixqnaI8seFLdLgacdhfMblnKuyP6bgWUD2jl2X9ruVGfIHQeBdA19WesMJKHm9XqQaF1mjl0AM0k52bU7GZZ6cOD3yFwl2RMAUMlUPPyX9xq2L5kNEsgYdw4qlgdvjLaX_HipqHh7JHQksJv4Sg
Referer: http://localhost:9000/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6,fr;q=0.4
]
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.authenticator.AuthenticatorBase : Security checking request GET /admin/hello
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] org.apache.catalina.realm.RealmBase : No applicable constraints defined
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.authenticator.AuthenticatorBase : Not subject to any constraint
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] org.apache.tomcat.util.http.Parameters : Set encoding to UTF-8
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.w.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade@2683da6f
2017-01-09 07:11:46.740 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /admin/hello' doesn't match 'OPTIONS /**
2017-01-09 07:11:46.741 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2017-01-09 07:11:46.741 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2017-01-09 07:11:46.742 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2017-01-09 07:11:46.742 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2017-01-09 07:11:46.743 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2017-01-09 07:11:46.743 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 5 of 13 in additional filter chain; firing Filter: 'KeycloakPreAuthActionsFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.k.adapters.PreAuthActionsHandler : adminRequest http://localhost:8080/admin/hello
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 6 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /admin/hello' doesn't match 'POST /sso/logout
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 7 of 13 in additional filter chain; firing Filter: 'KeycloakAuthenticationProcessingFilter'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/sso/login']
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/admin/hello'; against '/sso/login'
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=Authorization, expectedHeaderValue=null]
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : matched
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Request is to process authentication
2017-01-09 07:11:46.744 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Attempting Keycloak authentication
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] a.s.a.SpringSecurityRequestAuthenticator : Completing bearer authentication. Bearer roles: [uma_authorization]
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] o.k.adapters.RequestAuthenticator : User 'user1' invoking 'http://localhost:8080/admin/hello' on client 'pharma-backend'
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] o.k.adapters.RequestAuthenticator : Bearer AUTHENTICATED
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Auth outcome: AUTHENTICATED
2017-01-09 07:11:46.871 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.authentication.ProviderManager : Authentication attempt using org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider
2017-01-09 07:11:46.872 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2017-01-09 07:11:46.889 DEBUG 14692 --- [nio-8080-exec-2] o.k.a.s.management.HttpSessionManager : Session created: D309F84825BE807C7B34F16B111E92CD
2017-01-09 07:11:46.890 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Registering session D309F84825BE807C7B34F16B111E92CD, for principal user1
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] f.KeycloakAuthenticationProcessingFilter : Authentication success using bearer token/basic authentication. Updating SecurityContextHolder to contain: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 8 of 13 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2017-01-09 07:11:46.891 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 9 of 13 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 10 of 13 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : SecurityContextHolder not populated with anonymous token, as it already contained: 'org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 11 of 13 in additional filter chain; firing Filter: 'SessionManagementFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] s.CompositeSessionAuthenticationStrategy : Delegating to org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy@29a23c3d
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Registering session D309F84825BE807C7B34F16B111E92CD, for principal user1
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Removing session D309F84825BE807C7B34F16B111E92CD from principal's set of registered sessions
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.core.session.SessionRegistryImpl : Removing principal user1 from registry
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] s.CompositeSessionAuthenticationStrategy : Delegating to org.springframework.security.web.csrf.CsrfAuthenticationStrategy@20f0cc02
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@a08a84cd: Authentication: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@1a43aa14
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 12 of 13 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2017-01-09 07:11:46.892 DEBUG 14692 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /admin/hello at position 13 of 13 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /admin/hello' doesn't match 'POST /sso/logout
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/admin/hello'; against '/api/v1*'
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/admin/hello'; against '/admin/hello*'
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /admin/hello; Attributes: [hasRole('ROLE_admin')]
2017-01-09 07:11:46.893 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}
2017-01-09 07:11:46.895 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@58311096, returned: -1
2017-01-09 07:11:46.896 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) ~[spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115) ~[spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.4.RELEASE.jar:4.1.4.RELEASE]
...
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.6.jar:8.5.6]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5ca0c4c5
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@a08a84cd: Authentication: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@a08a84cd: Principal: user1; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@4ebe3c30; Granted Authorities: KeycloakRole{role='uma_authorization'}' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@1a43aa14
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2017-01-09 07:11:46.899 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@2683da6f
2017-01-09 07:11:46.900 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost] : Processing ErrorPage[errorCode=0, location=/error]
2017-01-09 07:11:46.901 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/error]
2017-01-09 07:11:46.902 DEBUG 14692 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
2017-01-09 07:11:46.904 DEBUG 14692 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)]
2017-01-09 07:11:46.904 DEBUG 14692 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'basicErrorController'
2017-01-09 07:11:46.904 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/error] is: -1
2017-01-09 07:11:46.927 DEBUG 14692 --- [nio-8080-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Written [{timestamp=Mon Jan 09 07:11:46 MYT 2017, status=403, error=Forbidden, message=Access is denied, path=/admin/hello}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@45db4b8b]
2017-01-09 07:11:46.927 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2017-01-09 07:11:46.927 DEBUG 14692 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Successfully completed request
2017-01-09 07:11:46.928 DEBUG 14692 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Disabling the response for futher output
2017-01-09 07:11:46.928 DEBUG 14692 --- [nio-8080-exec-2] o.apache.coyote.http11.Http11Processor : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@63858877:org.apache.tomcat.util.net.NioChannel@4d4fa76c:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:51832]], Status in: [OPEN_READ], State out: [OPEN]
我通过用 hasAuthority() 替换 hasRole() 自己解决了这个问题。 我仍然不知道为什么 keycloak 角色映射到 spring 安全权限。欢迎任何解释。 谢谢。
我经历了同样的事情,这是我的发现。
org.springframework.security.access.vote.RoleVoter 假定您的角色从
开始private String rolePrefix = "ROLE_";
Keycloak 中没有这样的假设(除非你命名所有角色 ROLE_someName),因此实际上没有找到匹配的角色。
类似的解释可以从 Spring SecurityExpressionOperations class 的安全 Javadoc 中获得 hasRole 方法
This is similar to {@link #hasAuthority(String)} except that this method implies
that the String passed in is a role. For example, if "USER" is passed in the
implementation may convert it to use "ROLE_USER" instead. The way in which the role
is converted may depend on the implementation settings.
总而言之,我以与您完全相同的解决方案结束,现在使用 hasAuthority 而不是 hasRole。
您可以实施 SimpleAuthorityMapper() :
@Bean
public GrantedAuthoritiesMapper grantedAuthoritiesMapper() {
SimpleAuthorityMapper mapper = new SimpleAuthorityMapper();
mapper.setConvertToUpperCase(true);
return mapper;
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper( grantedAuthoritiesMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
configureGlobal:这里我们更改授权权限映射器。默认情况下,在 Spring 安全性中,角色以 ROLE_ 为前缀。我们可以在我们的 Realm 配置中更改它,但它可能会让不了解此约定的其他应用程序感到困惑,因此在这里我们分配一个 SimpleAuthorityMapper 以确保不添加前缀。
点击here!
ROLE_ is the prefix default for sring security roles.