# OpenID Connect
pac4j 允许你使用 OpenID Connect 协议 v1.0 登录。
它已经通过各种 OpenID Connect 提供者进行了测试:Google、AzureAD、Okta、IdentityServer3(以及 4)、MitreID、Keycloak 4.6 ……
# 1)依赖性
你需要使用以下模块:pac4j-oidc
。
示例(Maven 依赖项):
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-oidc</artifactId>
<version>${pac4j.version}</version>
</dependency>
2
3
4
5
# 2)客户端
# a)间接客户端
对于任何 OpenID Connect 认证提供者,你应该使用通用 OidcClient (opens new window)(或其子类之一)。它是基于 Web 浏览器的认证的间接客户端。配置是通过 OidcConfiguration (opens new window) 组件定义的。
示例:
OidcConfiguration config = new OidcConfiguration();
config.setClientId(clientId);
config.setSecret(secret);
config.setDiscoveryURI(discoveryUri);
OidcClient oidcClient = new OidcClient(config);
2
3
4
5
在某些情况下(如示例中当发现 URL 已经知道时),你可以使用特定的客户端,例如 Google (opens new window)、Azure Active Directory (opens new window)、Keycloak (opens new window) 或 Apple (opens new window)。
示例:
OidcConfiguration configuration = new OidcConfiguration();
configuration.setClientId("788339d7-1c44-4732-97c9-134cb201f01f");
configuration.setSecret("we/31zi+JYa7zOugO4TbSw0hzn+hv2wmENO9AS3T84s=");
configuration.setDiscoveryURI("https://login.microsoftonline.com/38c46e5a-21f0-46e5-940d-3ca06fd1a330/.well-known/openid-configuration");
AzureAdClient client = new AzureAdClient(configuration);
2
3
4
5
由 OpenID Connect 提供者提供的 clientId
和 secret
,以及 discoveryUri
(用于认证提供者的元数据)。如果未定义 discoveryUri
,则需要通过 setProviderMetadata
方法提供提供者元数据。
成功进行认证后返回 OidcProfile (opens new window)(或其子类之一:AzureAdProfile (opens new window)、GoogleOidcProfile (opens new window) 或 KeycloakOidcProfile (opens new window))。即使你可以通过 getIdToken()
方法直接获取 ID Token,ID Token 中返回的所有属性都可在 OidcProfile
中获得。
你可以通过 setResponseType
和 setResponceMode
方法定义要使用的流:
// implicit flow
config.setResponseType("id_token");
config.setResponseMode("form_post");
2
3
你可以通过 setResponseType
和 setResponseMode
方法定义要使用的流:
// implicit flow
config.setResponseType("id_token");
config.setResponseMode("form_post");
2
3
默认情况下,response_type
设置为 code
(授权代码流),response_mode
为空。
你可以用 setScope
方法定义使用的范围(scope
):
config.setScope("openid email profile phone");
你可以通过以下方式请求使用 nonce 参数来增强安全性:
config.setUseNonce(true);
# b)直接客户端
对于直接客户端(web 服务),你可以从任何 OpenID Connect 认证提供者获取 access token(访问令牌),并在请求中使用该令牌获取用户配置文件。
为此,HeaderClient (opens new window) 将与 oidcClient.getProfileCreator()
一起使用。
OidcConfiguration config = new OidcConfiguration();
config.setClientId(clientId);
config.setSecret(secret);
config.setDiscoveryURI(discoveryUri);
OidcClient oidcClient = new OidcClient(config);
oidcClient.setCallbackUrl("notused");
oidcClient.init();
HeaderClient client = new HeaderClient("Authorization", "Bearer ", oidcClient.getProfileCreator());
2
3
4
5
6
7
8
对服务器的请求应具有值为 Bearer{access token}
的 Authorization 头。
# 3)高级配置
你可以使用 setClientAuthenticationMethod
方法定义如何将客户端凭据(clientId
和 secret
)传递给令牌端点:
config.setClientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
你还可以通过提供 PrivateKeyJWTClientAuthnMethodConfig
组件来使用 PRIVATE_KEY_JWT
认证方法:
oidcConfiguration.setClientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT);
var privateKey = org.jasig.cas.client.util.PrivateKeyUtils.createKey("private-key.pem", "RSA");
var privateKeyJwtConfig = new PrivateKeyJWTClientAuthnMethodConfig(JWSAlgorithm.RS256, privateKey, "12345");
oidcConfiguration.setPrivateKeyJWTClientAuthnMethodConfig(privateKeyJwtConfig);
2
3
4
5
在登录过程中验证 IDToken 时,可以设置时钟偏差:
// 1 minute
config.setMaxClockSkew(60);
2
你还可以选择首选算法来签署 JSON web 令牌:
config.setPreferredJwsAlgorithm(JWSAlgorithm.RS256);
最后,你可以使用 addCustomParam
(String key、String value)方法设置其他参数:
// select display mode: page, popup, touch, and wap
config.addCustomParam("display", "popup");
// select prompt mode: none, consent, select_account
config.addCustomParam("prompt", "none");
2
3
4
可以使用以下方法在配置中定义自定义 state
值:
config.setWithState(true);
config.setStateData("custom-state-value");
2
默认情况下,当访问令牌过期时,本地会话将过期,但可以使用以下方法禁用:
config.setExpireSessionWithToken(false);
附加参数 TokenExpirationAdvance
允许设置令牌过期之前的时间(以秒为单位),其中过期提前。默认值为 0
秒。
config.setTokenExpirationAdvance(10);
从 5.2 版开始,为了加强安全性,ID token 的无密码(即无签名验证)必须通过以下方式明确接受:
config.setAllowUnsignedIdTokens(true);