非Spring Boot Java应用:集成Keycloak实现REST接口无页面认证
可行解决方案
方案1:排除API登录路径的Keycloak拦截
Keycloak的Servlet适配器默认会拦截配置范围内的所有请求并触发重定向登录。你需要将/api/authentication/login路径从Keycloak的拦截范围中排除,让原有接口继续处理凭证校验,再通过Keycloak API获取令牌返回:
- 在
web.xml中配置Keycloak过滤器时,添加排除规则:<filter> <filter-name>Keycloak Filter</filter-name> <filter-class>org.keycloak.adapters.servlet.KeycloakOIDCFilter</filter-class> </filter> <filter-mapping> <filter-name>Keycloak Filter</filter-name> <url-pattern>/*</url-pattern> <exclude-url-pattern>/api/authentication/login</exclude-url-pattern> </filter-mapping> - 或者在Keycloak配置文件(
keycloak.json)中添加排除规则:{ "exclude-patterns": ["/api/authentication/login"] } - 排除后,原有接口可提取请求头中的
Authorization凭证(如admin:admin),然后后端调用Keycloak的Token Endpoint(POST {keycloak-url}/realms/{你的realm}/protocol/openid-connect/token),使用password授权模式,传入参数:
拿到Keycloak返回的令牌后,直接返回给调用方。grant_type=password username=xxx password=xxx client_id=你的客户端ID client_secret=你的客户端密钥(若客户端为confidential类型)
方案2:直接复用Keycloak密码授权模式替换原有接口
放弃原有自定义登录逻辑,将/api/authentication/login接口改造为Keycloak密码授权模式的代理:
- 在Keycloak控制台配置对应客户端:
- 将客户端的Access Type设为
confidential(需维护client secret)或public; - 在Advanced Settings > Grant Types中勾选
Password;
- 将客户端的Access Type设为
- 后端接口接收请求中的用户名密码(可从
Authorization头解析,或请求体参数),直接构造请求转发到Keycloak的Token Endpoint,参数同方案1中的password授权模式参数; - 将Keycloak返回的令牌(包含
access_token、refresh_token等)原样或包装后返回给调用方,无需自己校验凭证。
方案3:自定义Keycloak认证过滤器处理API路径
如果不想排除路径,可自定义过滤器继承Keycloak的BaseKeycloakFilter,针对/api/authentication/login路径做特殊处理:
- 重写
doFilter方法,判断当前请求路径是否为目标API:public class CustomKeycloakFilter extends BaseKeycloakFilter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; if ("/api/authentication/login".equals(req.getPathInfo())) { // 提取用户名密码(从Authorization头或请求体) String authHeader = req.getHeader("Authorization"); String[] credentials = decodeBase64(authHeader.split(" ")[1]).split(":"); String username = credentials[0]; String password = credentials[1]; // 调用Keycloak API校验凭证并获取令牌 String token = fetchTokenFromKeycloak(username, password); // 返回令牌给客户端 HttpServletResponse res = (HttpServletResponse) response; res.setContentType("application/json"); res.getWriter().write("{\"access_token\":\"" + token + "\"}"); return; } // 其他路径走正常Keycloak认证流程 chain.doFilter(request, response); } private String fetchTokenFromKeycloak(String username, String password) { // 实现调用Keycloak Token Endpoint的逻辑,同方案1 return ""; } } - 在
web.xml中替换原有的Keycloak过滤器为自定义过滤器。
关于你之前尝试无效的原因
新建覆盖/api路径的客户端并设置Client Authentication=false无法解决问题,因为Keycloak Servlet适配器通常是按应用全局配置拦截规则,路径与客户端的绑定并非直接生效;且默认的认证流程是针对浏览器的重定向授权,不会自动适配API的凭证校验场景,因此仍会触发登录页重定向。
内容的提问来源于stack exchange,提问作者jmizv
相关产品推荐
相关产品推荐

