Keycloak Spring 启动配置

Posted

技术标签:

【中文标题】Keycloak Spring 启动配置【英文标题】:Keycloak Spring boot configuration 【发布时间】:2017-05-23 04:19:25 【问题描述】:

我正在尝试为 SSO 配置 Spring Boot 和 Keycloak。 我创建了一个基本的 AngularJS 应用程序,它向 Spring 引导后端发出一些请求。 using this

Angular 应用运行良好,现在我正在尝试关注新的 Spring Boot Keycloak apdater 文档here

这是我在 WEB-INF 文件夹中的 keycloak.json。


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


在 Keycloak 中创建了 'admin' 和 'user' 这 2 个角色,并且当前用户具有此角色。

@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: KeycloakRolerole='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: KeycloakRolerole='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: KeycloakRolerole='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: KeycloakRolerole='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: KeycloakRolerole='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]

【问题讨论】:

用户信息,请尝试从"/api/v1*"切换到"/api/v1/**" 【参考方案1】:

我也经历了同样的事情,这是我的发现。

org.springframework.security.access.vote.RoleVoter 假设你的角色从

private String rolePrefix = "ROLE_";

Keycloak 中没有这样的假设(除非您将所有角色命名为 ROLE_someName),因此实际上找不到匹配的角色。

类似的解释可以从 Spring Security Javadoc 的 SecurityExpressionOperations 类的 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。

【讨论】:

【参考方案2】:

我自己解决了这个问题,将 hasRole() 替换为 hasAuthority()。 我还是不知道为什么 keycloak 角色映射到 spring 安全权限。欢迎任何解释。 谢谢。

【讨论】:

【参考方案3】:

你可以实现 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 Security 中,角色以 ROLE_ 为前缀。我们可以在我们的 Realm 配置中更改它,但是对于不知道此约定的其他应用程序可能会造成混淆,因此在这里我们分配一个 SimpleAuthorityMapper 来确保不添加前缀。

点击here!

ROLE_ 是 sring 安全角色的默认前缀。

【讨论】:

以上是关于Keycloak Spring 启动配置的主要内容,如果未能解决你的问题,请参考以下文章

如何使基本身份验证作为 Angular JS/Spring 启动应用程序中 keycloak 的替代品

Spring Boot 中的 Keycloak 无法应用 Liquibase 补丁

Keycloak Spring 多租户空指针异常

如何在 Spring Boot 应用程序中使用 Keycloak Policy Enforcer

HttpSecurity 配置不适用于 Spring 上的 Keycloak Adapter

客户端角色的 Keycloak Spring Boot 配置