官网Guides - Keycloak
下载 Downloads 18.0.0 - Keycloak
GitHub: https://github.com/keycloak/keycloak/tags?after=17.0.1
=============================
1-安装启动
参照readme文件
启动
bin\kc.bat start-dev
初始化超管账号密码admin admin
参考官方教程 OpenJDK - Keycloak
打开超管界面http://localhost:8080/admin
创建realm
往realm中添加用户myuser,并设置密码为test
激活myuser
登录myuser的界面http://localhost:8080/realms/myrealm/account
可以看到myuser自己的一些信息
===============================================
2-对接一个项目
打开ADMIN页面配置
打开官网的测试网站Test application - Keycloak
根据官方教程就发现登录成功并且回调回来了。
============================================================
3-自己用java代码实现
打开F12观察刚才官方教程浏览器的认证回调的请求,自己照着写:
第一步拉起登录页面
package com.example.demokeycloak2;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
// private static final String KEYCLOAK_LOGIN_URL = "http://keycloak-server/auth/realms/your-realm/protocol/openid-connect/auth";
private static final String KEYCLOAK_LOGIN_URL = "http://localhost:8080/realms/myrealm/protocol/openid-connect/auth";
private static final String CLIENT_ID = "myclient";
private static final String REDIRECT_URI = "http://localhost:8081/callback"; // 替换为你的应用程序的回调 URL
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 生成 Keycloak 登录的 URL
String keycloakLoginURL = KEYCLOAK_LOGIN_URL +
"?client_id=" + CLIENT_ID +
"&redirect_uri=" + REDIRECT_URI +
"&response_type=code";
// 重定向到 Keycloak 登录页面
response.sendRedirect(keycloakLoginURL);
}
}
第二步手动在登录页面输入账号密码
第三步认证成功,回调到callback
package com.example.demokeycloak2;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@WebServlet("/callback")
public class CallbackServlet extends HttpServlet {
private static final String TOKEN_ENDPOINT = "http://localhost:8080/realms/myrealm/protocol/openid-connect/token";
private static final String CLIENT_ID = "myclient";
private static final String REDIRECT_URI = "http://localhost:8081/callback"; // 替换为你的应用程序的回调 URL
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String code = request.getParameter("code"); // 获取授权码
String error = request.getParameter("error"); // 检查是否有错误信息
if (error != null) {
// 处理错误情况
response.getWriter().println("登录失败:" + error);
} else if (code != null) {
// 使用授权码获取访问令牌
String accessToken = getAccessToken(code);
if (accessToken != null) {
System.out.println("accessToken");
System.out.println(accessToken);
// 在此处执行你的业务逻辑,例如获取用户信息或访问受保护的资源
// ...
// 示例:重定向到用户仪表板页面
// response.sendRedirect("/dashboard");
response.setContentType("text/html");
// Hello
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>" + "hello:" + accessToken + "</h1>");
out.println("</body></html>");
} else {
// 获取访问令牌失败
response.getWriter().println("获取访问令牌失败");
}
} else {
// 无效的请求,缺少授权码或错误信息
response.getWriter().println("无效的请求");
}
}
private String getAccessToken(String code) throws IOException {
// 构建获取访问令牌的请求参数
String requestBody =
"grant_type=authorization_code" +
"&client_id=" + CLIENT_ID
+ "&code=" + code
+ "&redirect_uri=" + REDIRECT_URI;
// 发送获取访问令牌的请求
HttpURLConnection connection = null;
try {
URL url = new URL(TOKEN_ENDPOINT);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setDoOutput(true);
try (OutputStream outputStream = connection.getOutputStream()) {
outputStream.write(requestBody.getBytes());
}
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
// 读取响应
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
StringBuilder responseBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
responseBuilder.append(line);
}
String responseJson = responseBuilder.toString();
System.out.println("responseJson");
System.out.println(responseJson);
// 解析响应 JSON,提取访问令牌
return extractAccessToken(responseJson);
}
} else {
// 获取访问令牌失败
return null;
}
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
private String extractAccessToken(String token) {
// 解析 JSON 提取访问令牌的逻辑
// 这里需要根据 Keycloak 返回的 JSON 结构进行解析
// 返回访问令牌字符串
JSONObject jsonObject = (JSONObject) JSON.parse(token);
String content = jsonObject.get("access_token").toString();
System.out.println(content);
String s = content.split("\\.")[1];
//解码
Base64.Decoder decoder = Base64.getDecoder();
System.out.println("access_token");
System.out.println(new String(decoder.decode(s), StandardCharsets.UTF_8));
return new String(decoder.decode(s), StandardCharsets.UTF_8);
}
}
显然也需要将回调地址和来源地址在超管控制台加上,同时注意access type为public这样才能不使用client secret来获取到access token
项目的根路径也要改成/
成功获取到用户信息name等