# 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>
1
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);
1
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");
AzureAd2Client client = new AzureAd2Client(configuration);
1
2
3
4
5

由 OpenID Connect 提供者提供的 clientIdsecret,以及 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 中获得。

你可以通过 setResponseTypesetResponceMode 方法定义要使用的流:

// implicit flow
config.setResponseType("id_token");
config.setResponseMode("form_post");
1
2
3

你可以通过 setResponseTypesetResponseMode 方法定义要使用的流:

// implicit flow
config.setResponseType("id_token");
config.setResponseMode("form_post");
1
2
3

默认情况下,response_type 设置为 code(授权代码流),response_mode 为空。

你可以用 setScope 方法定义使用的范围(scope):

config.setScope("openid email profile phone");
1

你可以通过以下方式请求使用 nonce 参数来增强安全性:

config.setUseNonce(true);
1

# 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());
1
2
3
4
5
6
7
8

对服务器的请求应具有值为 Bearer{access token}的 Authorization 头。

# 3)高级配置

你可以使用 setClientAuthenticationMethod 方法定义如何将客户端凭据(clientIdsecret)传递给令牌端点:

config.setClientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
1

你还可以通过提供 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);
1
2
3
4
5

在登录过程中验证 IDToken 时,可以设置时钟偏差:

// 1 minute
config.setMaxClockSkew(60);
1
2

你还可以选择首选算法来签署 JSON web 令牌:

config.setPreferredJwsAlgorithm(JWSAlgorithm.RS256);
1

最后,你可以使用 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");
1
2
3
4

可以使用以下方法在配置中定义自定义 state 值:

config.setWithState(true);
config.setStateData("custom-state-value");
1
2

默认情况下,当访问令牌过期时,本地会话将过期,但可以使用以下方法禁用:

config.setExpireSessionWithToken(false);
1

附加参数 TokenExpirationAdvance 允许设置令牌过期之前的时间(以秒为单位),其中过期提前。默认值为 0 秒。

config.setTokenExpirationAdvance(10);
1

从 5.2 版开始,为了加强安全性,ID token 的无密码(即无签名验证)必须通过以下方式明确接受:

config.setAllowUnsignedIdTokens(true);
1

原文链接 (opens new window)