我尝试保护我的 Spring Boot 应用程序服务器,我使用 keycloak 来保护它。我想使用谷歌身份验证创建社交登录。这是我的钥匙斗篷配置:
包 com.example.keycloaklearning.config;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@KeycloakConfiguration
class KeyCloakConfig extends KeycloakWebSecurityConfigurerAdapter {
// Disable default role prefix ROLE_
@Autowired
public void configureGlobal(
AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider
= keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
// Use Spring Boot property files instead of default keycloak.json
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
// Register authentication strategy for public or confidential applications
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(
new SessionRegistryImpl());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/test/unprotected-data").permitAll()
.antMatchers("/test/generator").permitAll()
.anyRequest().authenticated();
}
}
还有我的控制器:
package com.example.keycloaklearning.controllers;
import lombok.extern.java.Log;
import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.KeycloakUriBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
@RequestMapping(value = "/test")
@RestController
@Log
public class TestUserController {
private String authServerUrl = "http://localhost:8080/auth";
private String realm = "keycloak-lerning-realm";
private String clientId = "keycloak-lerning-server";
@GetMapping(path = "/generator")
public String brokerGenerator(HttpServletRequest httpServletRequest) throws ServletException {
String provider = "google";
String nonce = UUID.randomUUID().toString();
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
String input = nonce + clientId + provider;
byte[] check = md.digest(input.getBytes(StandardCharsets.UTF_8));
String hash = Base64Url.encode(check);
httpServletRequest.getSession().setAttribute("hash", hash);
String redirectUri = "http://localhost:8081/test/redirect";
return KeycloakUriBuilder.fromUri(authServerUrl)
.path("/realms/keycloak-lerning-realm/protocol/openid-connect/auth") // Url changed
.queryParam("response_type", "code") // Autherization Code Flow
.queryParam("scope", "openid") // Add additional scopes if needed
.queryParam("kc_idp_hint", "google") // This should match IDP name registered in Keycloak
.queryParam("nonce", nonce)
.queryParam("hash", hash)
.queryParam("client_id", clientId)
.queryParam("redirect_uri", redirectUri).build(realm, provider).toString();
}
@GetMapping(value = "/unprotected-data")
public String getName() {
return "Hello, this api is not protected.";
}
@GetMapping(value = "/protected-data")
public String getEmail() {
return "Hello, this api is protected.";
}
@GetMapping(value = "/redirect")
public String getRedirectMessage() {
return "Redirect message.";
}
}
-
我去 http://localhost:8081/test/unprotected-data
这很好用。
-
然后我去 http://localhost:8081/test/protected-data
该页面是安全的,我得到了 keycloak 登录页面,我不想使用它,我转到 http://localhost:8081/test/generator
-
当我访问 http://localhost:8081/test/generator 时
我得到的网址是这样的:
http://localhost:8080/auth/realms/keycloak-lerning-realm/protocol/openid-connect/auth?response_type=code&scope=openid&kc_idp_hint=google&nonce=1d339be6-72b8-487f-8d18-a3b84a1663de&hash=4VZz9Xtk-VqRprnjW8sJC f95EH2dGYIsgkSGYxNtlxU&client_id=keycloak- lerning-server&redirect_uri=http%3A%2F%2Flocalhost%3A8081%2Ftest%2Fredirect
-
当我通过这个地址输入我的谷歌数据(电子邮件和密码)时,我收到错误:
此页面无法正常工作,localhost 已将您重定向了太多次。
尝试清除您的cookie。
ERR_TOO_MANY_REDIRECTS
在我的“网络”选项卡中,我看到许多这样的请求:
General:
Request URL: http://localhost:8081/sso/login?session_state=fc107364-ae64-4ab6-923d-d3e8abec6b0b&code=b0fb2c6f-93a0-45ee-bead-500202ef46b8.fc107364-ae64-4ab6-923d-d3e8abec6b0b.4b1cdc54-90bb-4c12-97d7-e04a72d98a49
Request Method: GET
Status Code: 302
Remote Address: [::1]:8081
Referrer Policy: strict-origin-when-cross-origin
Response Headers:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Length: 0
Date: Sun, 24 Oct 2021 10:43:56 GMT
Expires: 0
Keep-Alive: timeout=60
Location: http://localhost:8081/sso/login?session_state=fc107364-ae64-4ab6-923d-d3e8abec6b0b&code=b0fb2c6f-93a0-45ee-bead-500202ef46b8.fc107364-ae64-4ab6-923d-d3e8abec6b0b.4b1cdc54-90bb-4c12-97d7-e04a72d98a49
Pragma: no-cache
Set-Cookie: OAuth_Token_Request_State=; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Request headers:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: ru
Connection: keep-alive
Cookie: JSESSIONID=C6A7D049775893649E853257B1B8645F; OAuth_Token_Request_State=704778b2-b484-4102-beda-f95e18ddc759
Host: localhost:8081
sec-ch-ua: "Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36
Query string parameters:
session_state: fc107364-ae64-4ab6-923d-d3e8abec6b0b
code: b0fb2c6f-93a0-45ee-bead-500202ef46b8.fc107364-ae64-4ab6-923d-d3e8abec6b0b.4b1cdc54-90bb-4c12-97d7-e04a72d98a49
我尝试清理我的 cookie 并打开新的隐身标签,但这不起作用。