You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot API集成Keycloak后频繁返回401 Unauthorized问题求助

Keycloak认证后API持续返回401 Unauthorized问题排查

我按照YouTube教程搭建了Keycloak服务器用于API认证,完成了realm、client及用户配置,可通过OpenID密码模式成功获取token。首次调用API端点返回200正常,但一段时间后持续返回401 Unauthorized,即使清除Cookie重新认证获取token也无法解决问题。

我的OpenID端点配置如下:

{"issuer":"http://127.0.0.1:8080/realms/spring-cloud-client-realm","authorization_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/auth","token_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/token","introspection_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/token/introspect","userinfo_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/userinfo","end_session_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/logout","frontchannel_logout_session_supported":true,"frontchannel_logout_supported":true,"jwks_uri":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/certs","check_session_iframe":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/login-status-iframe.html","grant_types_supported":["authorization_code","implicit","refresh_token","password","client_credentials","urn:ietf:params:oauth:grant-type:device_code","urn:openid:params:grant-type:ciba"],"acr_values_supported":["0","1"],"response_types_supported":["code","none","id_token","token","id_token token","code id_token","code token","code id_token token"],"subject_types_supported":["public","pairwise"],"id_token_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"id_token_encryption_alg_values_supported":["RSA-OAEP","RSA-OAEP-256","RSA1_5"],"id_token_encryption_enc_values_supported":["A256GCM","A192GCM","A128GCM","A128CBC-HS256","A192CBC-HS384","A256CBC-HS512"],"userinfo_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512","none"],"userinfo_encryption_alg_values_supported":["RSA-OAEP","RSA-OAEP-256","RSA1_5"],"userinfo_encryption_enc_values_supported":["A256GCM","A192GCM","A128GCM","A128CBC-HS256","A192CBC-HS384","A256CBC-HS512"],"request_object_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512","none"],"request_object_encryption_alg_values_supported":["RSA-OAEP","RSA-OAEP-256","RSA1_5"],"request_object_encryption_enc_values_supported":["A256GCM","A192GCM","A128GCM","A128CBC-HS256","A192CBC-HS384","A256CBC-HS512"],"response_modes_supported":["query","fragment","form_post","query.jwt","fragment.jwt","form_post.jwt","jwt"],"registration_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/clients-registrations/openid-connect","token_endpoint_auth_methods_supported":["private_key_jwt","client_secret_basic","client_secret_post","tls_client_auth","client_secret_jwt"],"token_endpoint_auth_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"introspection_endpoint_auth_methods_supported":["private_key_jwt","client_secret_basic","client_secret_post","tls_client_auth","client_secret_jwt"],"introspection_endpoint_auth_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"authorization_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"authorization_encryption_alg_values_supported":["RSA-OAEP","RSA-OAEP-256","RSA1_5"],"authorization_encryption_enc_values_supported":["A256GCM","A192GCM","A128GCM","A128CBC-HS256","A192CBC-HS384","A256CBC-HS512"],"claims_supported":["aud","sub","iss","auth_time","name","given_name","family_name","preferred_username","email","acr"],"claim_types_supported":["normal"],"claims_parameter_supported":true,"scopes_supported":["openid","roles","phone","email","address","profile","acr","microprofile-jwt","offline_access","web-origins"],"request_parameter_supported":true,"request_uri_parameter_supported":true,"require_request_uri_registration":true,"code_challenge_methods_supported":["plain","S256"],"tls_client_certificate_bound_access_tokens":true,"revocation_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/revoke","revocation_endpoint_auth_methods_supported":["private_key_jwt","client_secret_basic","client_secret_post","tls_client_auth","client_secret_jwt"],"revocation_endpoint_auth_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"backchannel_logout_supported":true,"backchannel_logout_session_supported":true,"device_authorization_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/auth/device","backchannel_token_delivery_modes_supported":["poll","ping"],"backchannel_authentication_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/ext/ciba/auth","backchannel_authentication_request_signing_alg_values_supported":["PS384","ES384","RS384","ES256","RS256","ES512","PS256","PS512","RS512"],"require_pushed_authorization_requests":false,"pushed_authorization_request_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/ext/par/request","mtls_endpoint_aliases":{"token_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/token","revocation_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/revoke","introspection_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/token/introspect","device_authorization_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/auth/device","registration_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/clients-registrations/openid-connect","userinfo_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/userinfo","pushed_authorization_request_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/ext/par/request","backchannel_authentication_endpoint":"http://127.0.0.1:8080/realms/spring-cloud-client-realm/protocol/openid-connect/ext/ciba/auth"}}

我通过Postman认证可正常获取token,但使用该token调用API始终返回401,请求解决建议。

排查与解决建议
  • 检查Token的Audience(受众):解码获取到的JWT token,查看aud字段是否包含API客户端的ID。如果API服务配置了验证audience,而token里没有对应值,会直接返回401。可使用本地JWT解码工具查看token内容。

  • 验证API服务的认证配置:

    • 确认API服务使用的Keycloak issuer地址和获取token时的一致(均为http://127.0.0.1:8080/realms/spring-cloud-client-realm),避免因域名/IP不一致导致签名验证失败。
    • 若API服务开启了token introspection,需确保API服务使用的客户端有访问introspect端点的权限,且客户端凭证正确。
  • 检查Keycloak证书缓存:Keycloak会定期更新签名证书,API服务若缓存了旧证书,会导致新token验证失败。可重启API服务清除缓存,或配置API服务定期刷新Keycloak的JWKS证书。

  • 确认Token有效性:

    • 查看token的exp字段,确认token未过期。
    • 检查token的签名算法是否与API服务配置一致,比如token用RS256签名,API服务需配置对应公钥验证。
  • 检查Keycloak客户端与用户状态:

    • 确认客户端未被禁用,在Keycloak控制台Clients->目标客户端->Settings中,Access Type设置为confidential或public(匹配API服务需求),Valid Redirect URIs或Web Origins包含API服务地址(若有需要)。
    • 确认用户未被锁定,且拥有API所需角色/权限,检查token的realm_access.roles或resource_access.目标客户端ID.roles字段是否包含API要求的角色。
  • 开启调试日志排查:

    • 在API服务中开启认证相关DEBUG日志,查看401具体原因(如签名验证失败、aud不匹配、token已撤销等)。
    • 在Keycloak控制台开启Events日志,查看token颁发和验证过程中的错误信息。
  • 测试Token Introspection端点:用Postman调用Keycloak的introspection_endpoint,传入获取到的token和客户端凭证,查看返回的active字段是否为true。若返回false,说明token已失效或不被认可,可根据其他返回字段排查原因。

内容的提问来源于stack exchange,提问作者donaldjbrewer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 03:24:22