V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Authing
V2EX  ›  OAuth

OIDC & OAuth2.0 认证协议最佳实践系列 02 - 授权码模式(Authorization Code)接入 Authing

  •  
  •   Authing · 2023-03-03 19:00:02 +08:00 · 906 次点击
    这是一个创建于 629 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在上一篇文章中,我们整体介绍 OIDC / OAuth2.0 协议,本次我们将重点围绕授权码模式( Authorization Code )以及接入 Authing 进行介绍,从而让你的系统快速具备接入用户认证的标准体系。

    接入 Authing 后的优势: 在整个 Authing 的身份源中,已经包含了社会化登录方式 微信、微博、QQ 、FB 、TW ...等等,企业登录方式 飞书、钉钉、企微、AD 等等,只要你完成了接入 Authing 就意味着你的业务系统具备了这些能力。

    01 授权码模式( Authorization Code )

    1.1 整体流程

    整体上,有以下流程

    1. 在你的应用中,让用户访问登录链接,浏览器跳转到 Authing ,用户在 Authing 完成认证。
    2. 浏览器接收到一个从 Authing 服务器发来的授权码。
    3. 浏览器通过重定向将授权码发送到你的应用后端。
    4. 你的应用服务将授权码发送到 Authing 获取 AccessToken 和 IdToken ,如果需要,还会返回 refresh token 。
    5. 你的应用后端现在知道了用户的身份,后续可以保存用户信息,重定向到前端其他页面,使用 AccessToken 调用资源方的其他 API 等等。

    流程图如下:

    1.2 准备接入

    • 在 Authing 创建应用及配置

    创建应用:

    配置登录回调和登出回调,配置为你实际项目的地址,我们在这里配置 localhost 用于测试。

    若你想匹配多个登录 /登出回调,可以使用 ‘*’ 号进行通配,登录 /登出回调可以是如下格式:

    在协议配置中,我们勾选 authorization_code 并且使用 code 作为返回类型,如下图所示:

    1.3 接入测试

    • 01 所需调用接口列表
    GET${host}/oidc/auth 发起登录(拼接你的发起登录地址)
    POST${host}/oidc/token 获取 Token
    GET${host}/session/me 获取用户信息
    POST${host}/oidc/token/introspection 校验 Token
    POST${host}/oidc/token 刷新 Token
    POST${host}/oidc/revocation 吊销 Token
    GET${host}/session/end 登出
    
    • 02 Run in Postman

    以下要介绍的接口可以通过我们的在线 postman collection 自行 fork 体验。

    • 03 发起登录
    GET${host}/oidc/auth
    

    这是基于浏览器的 OIDC 的起点,请求对用户进行身份验证,并会在验证成功后返回授权码到您所指定的 redirect_uri 。

    拼接发起登录地址(浏览器中打开): https://{host}/oidc/auth?scope=openid+profile+email+phone+username&redirect_uri={redirect_uri}&response_type=code&client_id={应用 ID}&state={state}

    如您需要额外获取 refresh_token 则请求格式为: https://{host}/oidc/auth? scope=openid+profile+offline_access+username+email+phone&redirect_uri=http://localhost:8080/&response_type=code&client_id={应用 ID}&prompt=consent&state={state}

    点此体验https://oidc-authorization-code.authing.cn/oidc/auth?scope=openid+profile+offline_access+username+email+phone&redirect_uri=http://localhost:8080/&response_type=code&prompt=consent&nonce=054d3c0e-9df9-46f2-a8fa-a7f479032660&client_id=63eb4585156d977101dd3750&state=1676366724

    参数说明

    • 04 获取 Token
    POST${host}/oidc/token
    

    用户在 Authing 侧完成登录操作后,Authing 会将生成的 code 作为参数回调到 redirect_uri 地址,此时通过 code 换 token 接口即可拿到对应的访问令牌 access_token 。

    请求参数

    请求事例

    curl --location --request POST 'https://{host}/oidc/token' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'client_id={应用 ID}' \
    --data-urlencode 'client_secret={应用密钥}' \
    --data-urlencode 'grant_type=authorization_code' \
    --data-urlencode 'redirect_uri={发起登录时指定的 redirect_uri}' \
    --data-urlencode 'code={/oidc/auth 返回的 code}'
    

    响应示例 (成功)

    {
        "scope": "openid username email phone offline_access profile",
        "token_type": "Bearer",
        "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImVtSzBGbVRIa0xlQWFjeS1YWEpVT3J6SzkxV243TkdoNGFlYUVlSjVQOUUifQ.eyJzdWIiOiI2M2ViNTNjNDQxYTVjMmYwNWYyNGJiMDMiLCJhdWQiOiI2M2ViNDU4NTE1NmQ5NzcxMDFkZDM3NTAiLCJzY29wZSI6Im9wZW5pZCB1c2VybmFtZSBlbWFpbCBwaG9uZSBvZmZsaW5lX2FjY2VzcyBwcm9maWxlIiwiaWF0IjoxNjc2MzY2OTE0LCJleHAiOjE2Nzc1NzY1MTQsImp0aSI6ImVmVU04enNrbl92LXYzeXZfbDVHRV9fQ2JEY0NNZDhEVDFnYVI0bHRqcHAiLCJpc3MiOiJodHRwczovL29pZGMtYXV0aG9yaXphdGlvbi1jb2RlLmF1dGhpbmcuY24vb2lkYyJ9.E3gAYzCQbJmrtM5zl91OPHm2YPnDxzRejw75oVMF1tLqCS0trj6CSBxyxP3Z9t6Eb_oAu1f_3I6XC3KC-l0DTM6q7_R2rnW4LWlik2rDCLuGpG0FqFScLZhwafmrPsVn93yaBQfEEoaLviqKhj3DgOymKqHZzFG3taaz2k_pWsxt4z97DtKjRTiqyMvcSfHsVrjSKELaC-5S_PHPWcQ70iX85IwUb6i5ldZGxYmODCvChNC9p4D4IOT3atvyEHgBTmjA9ZKI-T7hCVHSO91WZY3l1p4iWdi6KdP1oMGTy8WbmUHG9SiWO1Efh_9I5ZpRzVNWXINLv-lZ0d2aZKjg2w",
        "expires_in": 1209600,
        "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2M2ViNTNjNDQxYTVjMmYwNWYyNGJiMDMiLCJhdWQiOiI2M2ViNDU4NTE1NmQ5NzcxMDFkZDM3NTAiLCJpYXQiOjE2NzYzNjY5MTQsImV4cCI6MTY3NzU3NjUxNCwiaXNzIjoiaHR0cHM6Ly9vaWRjLWF1dGhvcml6YXRpb24tY29kZS5hdXRoaW5nLmNuL29pZGMiLCJub25jZSI6IjhiYjg3MjdhLWU1MGUtNDUzOC05ZmZmLWZhOTFlNWQ0Y2MwYSIsIm5hbWUiOm51bGwsImdpdmVuX25hbWUiOm51bGwsIm1pZGRsZV9uYW1lIjpudWxsLCJmYW1pbHlfbmFtZSI6bnVsbCwibmlja25hbWUiOm51bGwsInByZWZlcnJlZF91c2VybmFtZSI6bnVsbCwicHJvZmlsZSI6bnVsbCwicGljdHVyZSI6Imh0dHBzOi8vZmlsZXMuYXV0aGluZy5jby9hdXRoaW5nLWNvbnNvbGUvZGVmYXVsdC11c2VyLWF2YXRhci5wbmciLCJ3ZWJzaXRlIjpudWxsLCJiaXJ0aGRhdGUiOm51bGwsImdlbmRlciI6IlUiLCJ6b25laW5mbyI6bnVsbCwibG9jYWxlIjpudWxsLCJ1cGRhdGVkX2F0IjoiMjAyMy0wMi0xNFQwOToyNjoyOC4wNjhaIiwiZW1haWwiOm51bGwsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicGhvbmVfbnVtYmVyIjoiMTg1MTY4Mjk5OTUiLCJwaG9uZV9udW1iZXJfdmVyaWZpZWQiOnRydWUsInVzZXJuYW1lIjpudWxsfQ.GweoWBCEyHQGP6G9ohbfBMUMALlbZMM9hRAes1De7BM",
        "refresh_token": "KanvCEmonS_FgCRdFftOCwka2f8Qjj4tcsIfJF-VC1W"
    }
    

    响应示例 (失败)

    {
        "error": "invalid_grant",
        "error_description": "授权码无效或已过期"
    }
    
    • 05 通过 AccessToken 获取用户信息
    GET${host}/session/me 获取用户信息
    

    此端点是 OIDC 获取用户端点,可以通过 AccessToken 获取有关当前登录用户的信息。

    请求参数

    请求示例

    curl --location --request GET 'https://{host}/oidc/me?access_token={access_token}' 
    

    响应示例 (成功)

    {
        "name": null,
        "given_name": null,
        "middle_name": null,
        "family_name": null,
        "nickname": null,
        "preferred_username": null,
        "profile": null,
        "picture": "https://files.authing.co/authing-console/default-user-avatar.png",
        "website": null,
        "birthdate": null,
        "gender": "U",
        "zoneinfo": null,
        "locale": null,
        "updated_at": "2023-02-14T09:26:28.068Z",
        "email": "[email protected]",
        "email_verified": true,
        "phone_number": "185xxxx9995",
        "phone_number_verified": true,
        "username": "neo",
        "sub": "63eb53c441a5c2f05f24bb03"
    }
    

    响应示例 (失败)

    {
        "error": "invalid_grant",
        "error_description": "Access Token 无效"
    }
    
    • 06 校验 Token
    POST${host}/oidc/token/introspection
    

    此端点接受 access_token 、id_token 、refresh_token ,并返回一个布尔值,指示它是否处于活动状态。如果令牌处于活动状态,还将返回有关令牌的其他数据。如果 token 无效、过期或被吊销,则认为它处于非活动状态。

    1.验证 Token 分为两种方式

    本地验证与使用 Authing 在线验证。我们建议在本地验证 JWT Token ,因为可以节省你的服务器带宽并加快验证速度。你也可以选择将 Token 发送到 Authing 的验证接口由 Authing 进行验证并返回结果,但这样会造成网络延迟,而且在网络拥塞时可能会有慢速请求。

    access_token 可以使用 RS256 签名算法或 HS256 签名算法进行签名。下面是这两种签名算法的区别

    RS256 是使用 RSA 算法的一种数字签名算法,它使用公钥 /私钥对来加密和验证信息。RS256 签名生成的令牌比 HS256 签名生成的令牌更加安全,因为使用 RSA 密钥对进行签名可以提供更高的保护级别。使用 RS256 签名算法的令牌可以使用公钥进行验证,公钥可以通过 JWK 端点获取。

    HS256 是使用对称密钥的一种数字签名算法。它使用同一个密钥进行签名和验证。HS256 签名算法在性能方面比 RS256 签名算法更快,因为它使用的是对称密钥,而不是使用 RSA 公钥 /私钥对来签名和验证。使用 HS256 签名算法的令牌可以通过 shared secret (应用密钥)进行验证。 在实际应用中,RS256 算法更加安全,但同时也更加消耗资源,如果系统需要高性能,可以选择 HS256 签名算法。

    以下是本地验证和在线验证的优劣对比:

    2.在线验证

    需要注意的是,id_token 目前无法在线校验,因为 id_token 只是一个标识,若需要校验 id_token 则需要您在离线自行校验。

    请求参数

    请求示例

    curl --location --request POST 'https://{host}/oidc/token/introspection' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'client_id={应用 ID}' \
    --data-urlencode 'client_secret={应用密钥}' \
    --data-urlencode 'token={ token }' \
    --data-urlencode 'token_type_hint={token_type_hint}'
    

    校验 access_token 响应示例(校验通过)

    {
        "active": true,
        "sub": "63eb53c441a5c2f05f24bb03",
        "client_id": "63eb4585156d977101dd3750",
        "exp": 1677648467,
        "iat": 1676438867,
        "iss": "https://oidc-authorization-code.authing.cn/oidc",
        "jti": "ObgavGBUocr1wsrUvtDLHmuFSgoebxsiOY4JNRqIhaQ",
        "scope": "offline_access username profile openid phone email",
        "token_type": "Bearer"
    }
    

    校验 access_token 响应示例(校验未通过)

    {
        "active": false
    }
    

    校验 refresh_token 响应示例 (校验通过)

    {
        "active": true,
        "sub": "63eb53c441a5c2f05f24bb03",
        "client_id": "63eb4585156d977101dd3750",
        "exp": 1679030867,
        "iat": 1676438867,
        "iss": "https://oidc-authorization-code.authing.cn/oidc",
        "jti": "6F2TO1v1YZ1_N7I3jXYHjK-vZzKtlD0IiP5KPoUFUCQ",
        "scope": "offline_access username profile openid phone email"
    }
    

    校验 refresh_token 响应示例(校验未通过)

    {
        "active": false
    }
    

    3.离线校验

    可参考文档:离线校验( 文档链接: https://docs.authing.cn/v2/guides/faqs/how-to-validate-user-token.html#

    我们简单说下,若您使用离线校验应该对 token 进行如下规则的校验

    1.格式校验 - 校验 token 格式是否是 JWT 格式 2.类型校验 - 校验 token 是否是目标 token 类型,比如 access_token 、id_token 、refresh_token 3.issuer 校验 - 校验 token 是否为信赖的 issuer 颁发 4.签名校验 - 校验 token 签名是否由 issuer 签发,防止伪造 5.时间校验 - 校验 token 是否在有效期内 6.claims 校验 - 是否符合与预期的一致

    以上 6 点均校验通过,我们才能认为 token 是有效且合法的

    下面是一个示例 Java 代码,可以用于在本地校验 OIDC RS256 和 HS256 签发的 access_token 。

    import com.nimbusds.jose.JWSObject;
    import com.nimbusds.jwt.JWTClaimsSet;
    import com.nimbusds.jwt.SignedJWT;
    
    import java.net.URL;
    import java.text.ParseException;
    import java.util.Date;
    
    public class OIDCValidator {
        private static final String ISSUER = "https://your-issuer.com";
        private static final String AUDIENCE = "your-client-id";
    
        private final URL jwkUrl;
    
        public OIDCValidator(final URL jwkUrl) {
            this.jwkUrl = jwkUrl;
        }
    
        public JWTClaimsSet validateToken(final String accessToken) throws ParseException {
            final SignedJWT signedJWT = SignedJWT.parse(accessToken);
            if (signedJWT == null) {
                throw new RuntimeException("Access token is null or empty");
            }
    
            final JWTClaimsSet claims = signedJWT.getJWTClaimsSet();
            if (claims == null) {
                throw new RuntimeException("No claims present in the access token");
            }
    
            if (!claims.getIssuer().equals(ISSUER)) {
                throw new RuntimeException("Invalid issuer in access token");
            }
    
            if (!claims.getAudience().contains(AUDIENCE)) {
                throw new RuntimeException("Invalid audience in access token");
            }
    
            final JWSObject jwsObject = signedJWT.getJWSObject();
            if (jwsObject == null) {
                throw new RuntimeException("No JWS object found in the access token");
            }
    
            // Fetch the JWKs from the JWK set URL
            final JWKSet jwkSet = JWKSet.load(jwkUrl);
            final JWK jwk = jwkSet.getKeyByKeyId(jwsObject.getHeader().getKeyID());
            if (jwk == null) {
                throw new RuntimeException("No JWK found for the access token");
            }
    
            if (!jwsObject.verify(jwk.getKey())) {
                throw new RuntimeException("Invalid signature in access token");
            }
    
            if (claims.getExpirationTime() == null || claims.getExpirationTime().before(new Date())) {
                throw new RuntimeException("Expired access token");
            }
    
            return claims;
        }
    }
    

    这段代码使用 Nimbus JOSE+JWT 库来解析和验证 JWT token 。它使用指定的 issuer 和 audience 值对 access_token 进行验证,并验证 JWT 中 claims 的格式、类型、签名、有效期和 issuer 。如果发生任何验证错误,则将抛出 RuntimeException 。使用时需要传入对应的 JWK URL 和 access_token 进行调用,例如:

    final URL jwkUrl = new URL("https://your-issuer.com/.well-known/jwks.json");
    final OIDCValidator validator = new OIDCValidator(jwkUrl);
    final String accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
    final JWTClaimsSet claims = validator.validateToken(accessToken);
    

    这个示例只校验了 RS256 和 HS256 签名算法。

    • 07 刷新 Token
    POST${host}/oidc/token
    

    此功能用于用户 token 的刷新操作,在 token 获取阶段需要先获取到 refresh_token 。

    请求参数

    请求示例

    curl --location --request POST 'https://{host}/oidc/token' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'client_id={应用 ID}' \
    --data-urlencode 'client_secret={应用密钥}' \
    --data-urlencode 'refresh_token={刷新令牌}' \
    --data-urlencode 'grant_type=refresh_token'
    

    响应示例(成功)

    {
        "refresh_token": "6F2TO1v1YZ1_N7I3jXYHjK-vZzKtlD0IiP5KPoUFUCQ",
        "scope": "offline_access username profile openid phone email",
        "token_type": "Bearer",
        "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImVtSzBGbVRIa0xlQWFjeS1YWEpVT3J6SzkxV243TkdoNGFlYUVlSjVQOUUifQ.eyJzdWIiOiI2M2ViNTNjNDQxYTVjMmYwNWYyNGJiMDMiLCJhdWQiOiI2M2ViNDU4NTE1NmQ5NzcxMDFkZDM3NTAiLCJzY29wZSI6Im9mZmxpbmVfYWNjZXNzIHVzZXJuYW1lIHByb2ZpbGUgb3BlbmlkIHBob25lIGVtYWlsIiwiaWF0IjoxNjc2NDQ0MjY4LCJleHAiOjE2Nzc2NTM4NjgsImp0aSI6IkEtZUlQYkJ5N3lJLTliUmp1RnJHeXNCSXdjbWtOUl9WalpYODB2aU05VFkiLCJpc3MiOiJodHRwczovL29pZGMtYXV0aG9yaXphdGlvbi1jb2RlLmF1dGhpbmcuY24vb2lkYyJ9.Kk3jSK5BSUEDVTQMdMAdG5cBCxZt31vQiD-XYHNA84Gd3Mo8eDLcQpjMEzQ8HJ4_b9IgMOz5ydXz0zAQ6AjLMW3Rl49qhTGDB7Kq7tHTFmDO8itoO2LQTCLPCPtP3TkoOgptlFD_sd32nefH-HojNhuqwKw469Byw3xnW5xEs3wSuOoUdHwR2n9j1T1Zgp3e90xmBjbtbofQE1z0IWtCnrfJ9ujWsKXoN_7OAXbCTa-Ak_DhgLHU7xutQaaBOgD28lLLT5xclgBWfv7Leyx_kBnVGT5Jvo1tfA6AUEp6wJO4GUBzsijLefI04VDzBGypNuFJlw_jOhSp-SWxJjQSwQ",
        "expires_in": 1209600,
        "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2M2ViNTNjNDQxYTVjMmYwNWYyNGJiMDMiLCJhdWQiOiI2M2ViNDU4NTE1NmQ5NzcxMDFkZDM3NTAiLCJpYXQiOjE2NzY0NDQyNjgsImV4cCI6MTY3NzY1Mzg2OCwiaXNzIjoiaHR0cHM6Ly9vaWRjLWF1dGhvcml6YXRpb24tY29kZS5hdXRoaW5nLmNuL29pZGMiLCJuYW1lIjpudWxsLCJnaXZlbl9uYW1lIjpudWxsLCJtaWRkbGVfbmFtZSI6bnVsbCwiZmFtaWx5X25hbWUiOm51bGwsIm5pY2tuYW1lIjpudWxsLCJwcmVmZXJyZWRfdXNlcm5hbWUiOm51bGwsInByb2ZpbGUiOm51bGwsInBpY3R1cmUiOiJodHRwczovL2ZpbGVzLmF1dGhpbmcuY28vYXV0aGluZy1jb25zb2xlL2RlZmF1bHQtdXNlci1hdmF0YXIucG5nIiwid2Vic2l0ZSI6bnVsbCwiYmlydGhkYXRlIjpudWxsLCJnZW5kZXIiOiJVIiwiem9uZWluZm8iOm51bGwsImxvY2FsZSI6bnVsbCwidXBkYXRlZF9hdCI6IjIwMjMtMDItMTRUMDk6MjY6MjguMDY4WiIsImVtYWlsIjpudWxsLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInBob25lX251bWJlciI6IjE4NTE2ODI5OTk1IiwicGhvbmVfbnVtYmVyX3ZlcmlmaWVkIjp0cnVlLCJ1c2VybmFtZSI6bnVsbH0.DGoJrzkgti44zw-MotVM1KpLxbJTzc5pfh-xYun_xDQ"
    }
    

    响应示例(失败)

    {
        "error": "invalid_grant",
        "error_description": "Refresh Token 无效或已过期"
    }
    
    • 08 撤回 Token
    POST${host}/oidc/token/revocation
    

    撤销 access_token / refresh_token

    请求参数

    请求示例

    curl --location --request POST 'https://{host}/oidc/token/revocation' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'client_id={应用 ID}' \
    --data-urlencode 'client_secret={应用密钥}' \
    --data-urlencode 'token= {token}' \
    --data-urlencode 'token_type_hint={token_type_hint}'
    

    响应示例(成功)

    HTTP 200 OK
    

    响应示例(失败)

    {
        "error": "xxxx",
        "error_description": "xxxx"
    }
    
    • 09 用户登出
    GET${host}/oidc/session/end
    

    使用此操作通过删除用户的浏览器会话来注销用户。 post_logout_redirect_uri 可以指定在执行注销后重定向的地址。否则,浏览器将重定向到默认页面

    请求参数

    请求示例 (浏览器访问)

    GET https://oidc-authorization-code.authing.cn/oidc/session/end?id_token_hint={id_token}&post_logout_redirect_uri=http://localhost:8080/&state=1676452381
    

    02 SSO (Single Sign-On) 单点登录 & SLO (Single Logout) 单点登出

    2.1 SSO 实现

    SSO(Single Sign-On) 单点登录,即同时访问多个应用仅需要登录一次。

    举例:我们现在有两个站点分别是 uthing.com ething.com 我们希望用户在 uthing.com 进行认证后,跳转到 ething 后无需二次认证,反之也是一样的。

    具体流程

    1.用户访问 uthing.com ,uthing 前端发现用户未认证,跳转至 Authing 进行认证。

    2.用户在 Authing 发起认证完成,Authing 创建 SSO Session ,下发临时授权码 (code) 重定向到 uthing 后台。

    需要注意的是,在这里我们也可以重定向到前端页面,再由前端页面自行判断如果是 Authing 回调请求,则携带临时 code 到 uthing 后台去获取 token 。

    3.uthing 后台通过 code 向 Authing 换取 access_token 、id_token 、refresh_token 等,并下发给前端。

    4.uthing 前端通过 access_token 可以直接向 Authing OIDC 用户信息端点获取当前用户信息。

    5.uthing 前端在在后续请求后台时,携带由 Authing 颁发的 access_token ,后台在接受到用户请求后去 Authing 校验 Token 是否有效,有效则可放行,若 Token 校验失败或已过期则返回错误信息。

    6.用户访问 ething.com ,ething 跳转至 Authing 进行认证。

    7.由于用户在 Authing 已经完成认证,创建了 sso_session ,Authing 侧直接下发临时授权码 (code) ,无需二次认证,后续流程同 1 。

    我们发现,用户在 uthing 认证成功的时候,再访问 ething 的时候会向 Authing 跳转一下,才能完成后续流程,这是由于 ething.comuthing.com 并不是同一个站点,无法实现 cookie 共享,如果你的产品地址是 : uthing.xxx.com ething.xxx.com 我们则可以利用相同域下 cookie 共享的方式实现 SSO ,从而避免此问题。

    2.2 SLO 实现

    SLO(Single Logout) 单点登出,即多个应用仅需要登出一次,其他应用也自动登出 。

    则 SLO 流程如下

    1.用户在某个站点登出,我们则需要调用 OIDC 登出端点销毁 Token ,由于是 cookie 共享实现的 SSO ,然后清除 xxx.com 对应会话的 cookie 即可。

    2.ething / uting 应当在每次发起请求前,判断 cookie 中是否存在登录态,若不存在,则需要跳转默认页面提示用户已经登出。

    • 02 场景 2

    如果你的产品地址不是同一个域,例如: uthing.com ething.com

    则 SLO 流程如下

    1.用户在某个站点登出,我们则需要调用 OIDC 登出端点销毁 Token ,在 Authing 的应用配置中,你应当先把应用都添加到 SSO 中,或者 uthing.comething.com 使用 Authing 的同一个自建应用,当用户在某个站点登出后,另外一个站点的 Token 也会失效。 2.用户未登出的站点发起请求,当后台校验 Token 失败后,则下发清除 cookie 的命令并跳转默认页面提示用户已经登出,需要登录。

    03 本章总结

    本章我们介绍了 OIDC 授权码模式的接入流程以及相关接口的调用方式,对于小白来说可能需要整体跑一遍流程才能熟悉,我们也建议你 fork 我们的 postman collection 跑一遍流程,对授权码模式你就基本掌握啦。

    接下来我们还会介绍 OIDC 的授权码+PKCE 流程,以及接入 Authing 的方式,需要你对授权码模式的流程有一定了解哦。

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3256 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 11:48 · PVG 19:48 · LAX 03:48 · JFK 06:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.