代码之家  ›  专栏  ›  技术社区  ›  peter_pilgrim

如何使REST Call注销与Spring Boot、Vaadin 10和keypolt 4一起工作?

  •  0
  • peter_pilgrim  · 技术社区  · 7 年前

    我用KeyCovert 4.4.0.Final和4.6.0.Final试过这个。我检查了keypoct服务器日志,在控制台输出中看到了以下警告消息。

    10:33:22,882 WARN  [org.keycloak.events] (default task-1) type=REFRESH_TOKEN_ERROR, realmId=master, clientId=security-admin-console, userId=null, ipAddress=127.0.0.1, error=invalid_token, grant_type=refresh_token, client_auth_method=client-secret
    10:40:41,376 WARN  [org.keycloak.events] (default task-5) type=LOGOUT_ERROR, realmId=demo, clientId=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJqYTBjX18xMHJXZi1KTEpYSGNqNEdSNWViczRmQlpGS3NpSHItbDlud2F3In0.eyJqdGkiOiI1ZTdhYzQ4Zi1mYjkyLTRkZTYtYjcxNC01MTRlMTZiMmJiNDYiLCJleHAiOjE1NDM0MDE2MDksIm5iZiI6MCwiaWF0IjoxNTQzNDAxMzA5LCJpc3MiOiJodHRwOi8vMTI3Lj, userId=null, ipAddress=127.0.0.1, error=invalid_client_credentials
    

    那么,如何构建HTTP请求呢?首先,我从HttpSession中检索到用户主体并强制转换为内部keypoct实例类型:

    KeycloakAuthenticationToken keycloakAuthenticationToken = (KeycloakAuthenticationToken) request.getUserPrincipal();
    final KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal)keycloakAuthenticationToken.getPrincipal();
    final RefreshableKeycloakSecurityContext context = (RefreshableKeycloakSecurityContext) keycloakPrincipal.getKeycloakSecurityContext();
    final AccessToken accessToken = context.getToken();
    final IDToken idToken = context.getIdToken();
    

    第二,我创建了注销URL,如在顶部堆栈溢出答案(见上文)中所示:

    final String logoutURI = idToken.getIssuer() +"/protocol/openid-connect/logout?"+
                "redirect_uri="+response.encodeRedirectURL(url.toString());
    

    现在我构建其余的HTTP请求,如下所示:

    KeycloakRestTemplate keycloakRestTemplate = new KeycloakRestTemplate(keycloakClientRequestFactory);
    HttpHeaders headers = new HttpHeaders();
    headers.put("Authorization", Collections.singletonList("Bearer "+idToken.getId()));
    headers.put("Content-Type", Collections.singletonList("application/x-www-form-urlencoded"));
    

    并构建正文内容字符串:

    StringBuilder bodyContent = new StringBuilder();
    bodyContent.append("client_id=").append(context.getTokenString())
                .append("&")
                .append("client_secret=").append(keycloakCredentialsSecret)
                .append("&")
                .append("user_name=").append(keycloakPrincipal.getName())
                .append("&")
                .append("user_id=").append(idToken.getId())
                .append("&")
                .append("refresh_token=").append(context.getRefreshToken())
                .append("&")
                .append("token=").append(accessToken.getId());
    HttpEntity<String> entity = new HttpEntity<>(bodyContent.toString(), headers);
    //   ...
    ResponseEntity<String> forEntity = keycloakRestTemplate.exchange(logoutURI, HttpMethod.POST, entity, String.class); // *FAILURE*
    

    正如您所看到的,我尝试了许多不同的主题,但我一直得到无效的用户身份验证。 哦,是的。我从 application.properties 使用@Value进入对象实例字段

    @Value("${keycloak.credentials.secret}")
    private String keycloakCredentialsSecret;
    

    Java Spring安全经验丰富的工程师有什么想法吗?

    附录 我在KC中创建了一个名为“demo”的域和一个名为“web portal”的客户端 具有以下参数:

    Client Protocol: openid-connect
    Access Type: public
    Standard Flow Enabled: On
    Implicit Flow Enabled: Off
    Direct Access Grants Enabled: On
    Authorization Enabled: Off
    

    这是重建重定向URI的代码,我忘了在这里包含它。

    final String scheme = request.getScheme();             // http
    final String serverName = request.getServerName();     // hostname.com
    final int serverPort = request.getServerPort();        // 80
    final String contextPath = request.getContextPath();   // /mywebapp
    
    // Reconstruct original requesting URL
    StringBuilder url = new StringBuilder();
    url.append(scheme).append("://").append(serverName);
    
    if (serverPort != 80 && serverPort != 443) {
        url.append(":").append(serverPort);
    }
    
    url.append(contextPath).append("/offline-page.html");
    

    这就是全部

    0 回复  |  直到 7 年前