JWT

最后更新:2021-12-02

1. 应用介绍

1.1. 概述

Json web token ( JWT ), 是一种用于双方之间传递安全信息的简洁的表述性声明规范。JWT作为一个开放的标准(RFC 7519 ),定义了一种简洁的方法用于通信双方之间以 Json 对象的形式安全的传递信息,该 token紧凑且安全,特别适用于分布式站点的单点登录(SSO)场景。

IDaaS平台提供了基于JWT标准协议实现SSO应用模板。JWT应用模板支持IDP发起和SP发起两种单点登录场景:

(1)IDP发起,即从IDaaS平台直接发起单点登录请求,传递JWT令牌至业务系统, 继而在业务系统进行验证,完成登录。

(2)SP发起,即从SP(业务系统)发起单点登录请求,跳转到IDaaS平台,进行登录,再跳转回业务系统完成JWT令牌认证从而实现业务系统的登录。

本文档主要为JWT应用配置人员/开发人员提供JWT应用模板配置和开发对接流程说明。

1.1.1. IDP/SP 发起单点登录的区别

IDP发起和SP发起场景二者主要共同点在于整个JWT的认证流程(后半截)是相同的,都需要业务系统开发JWT令牌验证和解析的接口,并根据解析出来的用户子账户信息,判断用户是否为该业务系统用户。

IDP发起和SP发起场景二者的不同点在于发起入口不同,从IDaaS平台发起单点登录,用户直接通过点击IDaaS平台首页的JWT应用(即业务系统),就能完成JWT令牌认证和业务系统的登录。而从SP(业务系统)发起单点登录,此时业务系统不一定已经完成了IDaaS平台的登录,或者登录信息过期失效,这时候业务系统会跳转到IDaaS登录页面,在用户进行登录后,再继续完成JWT令牌认证和业务系统的登录。

1.2. 实现原理

1.2.1. SSO 认证原理

p208527.png

上述时序图阐述了基于JWT发起SSO登录请求时的基本流程,该流程主要分为以下6个步骤:​

1-2)用户通过浏览器访问业务应用/IDaaS平台(即可以为IDP发起场景/SP发起场景),触发SSO。 3)IDaaS 生成 JWT token 令牌发送到业务系统。

4)业务系统获取到 token 令牌,用提供的插件或方法解析验证 JWT token 令牌,解析成功获取到用户信息并验证用户是否存在于业务系统中。

验证通过:继续接下来步骤。

验证失败:业务系统拒绝登录并页面提示错误信息。​

5)业务应用服务器创建自己系统的请求会话,然后跳转到指定路径。​

6)浏览器显示应用页面,完成SSO登录。

IDP发起场景

用户直接登录IDaaS平台,通过点击对应的业务系统图标触发IDaaS携带token请求业务系统的JWT SSO地址,走JWT SSO认证流程

SP发起场景

用户直接访问业务系统资源页面,如果所访问的业务系统处于未登录状态则需业务系统重定向至IDaaS平台进行登录认证,认证成功后再经IDaaS携带token请求业务系统的JWT SSO地址,走JWT SSO认证流程。

1.3. SLO 实现原理

业务系统 SLO

业务系统需要配置IDaaS平台提供的SLO接口,从而实现业务系统需在自身退出同时调用SLO接口触发IDaaS退出。​

IDaaS平台 SLO

IDaaS平台在退出登录时会触发通过浏览器调用业务系统提供的退出接口,实现业务系统的退出。

2. 对接流程图

下面是开发对接一个新的应用支持JWT协议SSO的过程。 JWT对接流程.png

2.1. 主要流程

该流程主要帮助开发者理解和集成一个SP应用支持JWT单点登录,从而完成整个JWT应用模版的使用。流程主要分为以下6步:

Step1 创建JWT应用

该步骤主要帮助开发者在IDaaS平台创建一个JWT应用,让SP(业务系统)系统能接入IDaaS平台的JWT SSO登录,在该步骤中,主要是一些必要字段的填写,以便于完成后面的整个流程。

Step2 SDK下载

该步骤主要帮助开发者更加便捷的开发JWT token验证接口。使用IDaaS提供的JWT SDK包,便于业务系统开发后续的JWT 解析验证接口。

Step3 业务系统研发

该步骤主要帮助开发者开发自己业务系统的JWT 接收、解析接口,完成业务系统的用户验证和登录。

Step4 模板SSO等信息更新

该步骤主要帮助开发者在完成JWT接收、解析等接口开发工作后,进行必要的接口验证工作。如果第一次在IDaaS平台创建JWT应用时,填写的JWT 验签接口不准确(redirect_uri),可以再次更新该地址。

Step5 单点登录效果验证

该步骤主要帮助开发者验证JWT应用配置的完整性和自己开发的JWT接收、解析接口是否正确,验证SSO登录流程是否能正确完成。

Step6 完成

3. 操作步骤

3.1. Step1 创建JWT应用

3.1.1. 登录 IDaaS 管理员平台

使用 IT 管理员账号登录云盾 IDaaS 管理平台。

3.1.2. 添加 JWT 应用

在【应用】-【添加应用】中,找到应用名称为: JWT,点击右边【添加应用】按钮。

image.png

3.1.3. 填写信息并保存

根据需要填写如下信息:

image.png

IDaaS平台提供的参数, 具体如下:

  1. 图标:业务应用的 logo 图片。

  2. 应用 ID: IDaaS自动生成的应用 ID,不允许修改,且唯一。

  3. 应用名称: 填写创建应用的名称。

  4. 应用类型: 代表该服务支持的设备类型,标记使用。

  5. SSO Binding:IDaaS调用业务系统提供的JWT SSO地址,REDIRECT 为 GET 类型,也可选择 POST

  6. ID_Token有效期:单位秒,一般使用默认值即可。

  7. 是否显示应用:授权给用户后,是否在用户的IDaaS平台首页显示,默认开启。若关闭,用户登录IDaaS平台首页,将看不到该应用。

  8. SP支持退出开关:用于开启IDaaS退出时调用业务系统退出地址实现业务系统同步退出功能(需要搭配SP退出地址进行使用),默认关闭

  9. 账户关联方式:

    a.账户关联(需用户进行手工添加关联,用户添加后需要管理员审批)

    b.账户映射(系统自动将主账户名称或指定的字段映射为应用的子账户)

SP(业务系统)需要考虑的参数: 一个全新的应用从不支持JWT, 到支持, 需要开发几个URL,以下为两个重要参数:

  1. redirect_uri:业务系统提供(或 PC 程序)的 JWT SSO 地址,在单点登录时 IDaaS 将向该地址用[GET]/[POST]方式发送 ID_Token 信息,参数名为id_Token,业务系统通过 ID_Token 与 Public Key 可获取JWT token中的用户信息。

  2. target_url: 业务系统中在通过JWT系统完成身份认证成功后,重定向的 URI。一般是一个http开头的URI,用于跳转到二级页面等。若设置了该 URI,在IDaaS平台在完成JWT协议身份认证成功时,会以参数 target_url传递该值,若未设置该值,若此时SP发起的SSO请求中有参数target_url,则会按照请求参数传递该值,此项可选。如果target_url为空,由SP决定跳转到哪个页面, 一般是默认的门户页面。

  3. SP退出地址:业务系统提供的登出地址,需支持Get方式调用

3.1.4. 导出公钥

基于JWT的非对称签名/验签机制,在完成上面应用创建后,私钥会被保存在IDaaS 后台,作为签名使用, 而公钥需要导出传递给SP(业务系统)验签使用。

在【应用列表】中,找到新创建的应用。点击【详情】按钮,点击【查看详情】。

image.png

找到 JWT PublicKey,复制粘贴到文本txt,或者使用下方导出,都可以将 JWT PublicKey 导出。将其交给需要接入JWT协议认证的SP业务系统,用作 ID_Token 的验签解析。

image.png

3.1.5. SLO地址获取

应用创建完成会,会生成对应应用的SLO地址。此地址将被提供给业务系统用于实现业务系统退出同时联动IDaaS退出场景。

在【应用列表】中,找到新创建的应用。点击【详情】按钮,点击【查看详情】,可获取该地址。

image.png

3.1.6. 获取SP发起地址

完成应用创建后,会生成对应应用的IDaaS登录地址即SP发起地址。此地址用于业务系统实现SP发起登录场景实现。

在【应用列表】中,找到新创建的应用。点击【详情】按钮,接着点击【SP发起地址】即可进行复制获取。

image.png

SP发起地址示例:
https://<idaas>/enduser/sp/sso/{应用ID}?enterpriseId={公司ID}&target_url=XXX

3.2. Step2 SDK下载

3.2.1. JAVA 相关下载

Java JWT Demo 下载
Java JWT SDK 下载

3.2.2. PHP 相关下载

PHP-JWT 资料下载

3.2.3. .NET 相关下载

.NET JWT 资料下载

3.2.4. Python 相关下载

Python-JWT 资料下载

3.3. Step3 业务系统研发

如上所述, SP研发核心需要考虑的:

  1. 能够接收到令牌 即 JWT SSO地址

  2. 能够成功验签解析令牌,拿到用户Sub信息

  3. 匹配用户信息是否与当前自己的子账号一致,完成匹配之后,创建业务系统自己的会话

  4. 跳转至用户首页

其次考虑(可选):

  1. 业务系统未登录需跳转至SP发起地址进行IDaaS登录认证

  2. 退出登录时需要调用IDaaS SLO实现IDaaS 同步退出

  3. 提供支持GET调用的登出接口供IDaaS退出时调用

注意使用jwt SSO时需要考虑令牌的防重放攻击。业务系统获取到令牌后,需要判断该令牌是否已经被使用过了,防止非法获取令牌后再次重复 一般可以存储jwt令牌中的jti来实现该功能。

3.3.1. SSO认证研发(IDP发起)

3.3.1.1. JAVA 集成

3.3.1.1.1. 配置环境

JDK 1.6 以上

SDK 和对接示例可以通过 【Step2 SDK下载】 下载参考。

3.3.1.1.2. 接收令牌
/**
 * id_token是IDaaS请求时带来的,参数名为 "id_token" , 支持使用GET/POST两种方式放入;
 * PublicKey是在IDaaS里注册应用时生成的,可在应用详情页中JWT PublicKey查看;
 * target_url是IDaaS里注册应用时设置的target_url,此示例代码是通过id_token和PublicKey解析用户信息并完成单点登录。
 */
@RequestMapping(value = "/public/sso/{id}", method = {RequestMethod.GET, RequestMethod.POST})
public String ssoUrl(@RequestParam String id_token, @PathVariable("id") String id, String target_url, Model model, HttpServletRequest request) {
    //1.接收方法,GET和POST均支持
    //2.<解析令牌>为解析id_token并验证用户信息
    SSOConfigDto config = ssoConfigService.findSSOConfigById(id);
    if (null == config) {
        model.addAttribute("error", "system config publicKey do not EXIST");
        return "error";
    }
    try {
        //使用方法1:校验并获取id_token中的所有信息,json格式
        //checkAndGetPayload(id_token, publicKey);
        //使用方法2:校验并获取id_token中的用户名
        return checkAndGetUsername(id_token, target_url, model, request, config.getPublicKey());
    } catch (Exception e) {
        LOG.warn("id_token verifySignature failed", e);
        model.addAttribute("error", "wrong request,not found Username from id_token or id_token has expired");
        return "error";
    }
}
3.3.1.1.3. 解析令牌

PublicKey: 解析令牌的过程中,我们会使用到应用的 PublicKey。请在 JWT 应用 -> 详细 中将PublicKey字段对应的内容拷贝并存储起来。

private String checkAndGetUsername(String id_token, String target_url, Model model, HttpServletRequest request, String publickey) throws Exception {

        //1. 初始化
        JsonWebSignature jws = new JsonWebSignature();
        jws.setCompactSerialization(id_token);
        jws.setKey(JsonWebKey.Factory.newJwk(publickey).getKey());
        //2. 校验id_token是否合法
        final boolean verifySignature = jws.verifySignature();
        if (!verifySignature) {
            LOG.warn("id_token verifySignature failed");
            //校验失败,报错,返回
            model.addAttribute("error", "Retrieve Username error: id_token verifySignature failed");
            return "error";
        }
        //3. 获取jwt中的payload信息,json格式,这里可以自由转换为需要的实体类
        final String payload = jws.getPayload();

        //4. 校验id_token是否过期
        JwtClaims claims = JwtClaims.parse(payload);
        NumericDate expirationTime = claims.getExpirationTime();
        if (expirationTime != null && expirationTime.isBefore(NumericDate.now())) {
            LOG.warn("id_token expired");
            //校验失败,报错,返回
            model.addAttribute("error", "Retrieve Username error: id_token expired");
            return "error";
        }
        //5. 注意校验id_token是否已经登陆过,防重放攻击
        //业务系统自己实现,需要校验有效期内,是否有相同的id_token已经登录
        final String jti = claims.getJwtId();//获取token唯一标识
        //从自身缓存系统判断jti是否已经登录过
        //if(exit(jti)){
        //    model.addAttribute("error", "id_token verifySignature failed");
        //    return error;
        //}
        //save(jti);

        //6.获取到用户信息,检测用户名是否存在自己的业务系统中,isExistedUsername方法为示例实现
        String username = claims.getSubject();
        if (userService.isExistedUsername(username)) {
            //7.如果存在,登录成功,返回登录成功后的界面
            User sysUser = userService.updateLoginTimes(username);
            HttpSession session = request.getSession();
            session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, saveSecurity(sysUser));

            //8.如果注册应用时添加了target_url,那么返回此自定义url页面
            if (StringUtils.isNotEmpty(target_url)) {
                return "redirect:" + target_url;
            }
            //9.否则返回系统默认操作页面
            return "redirect:../../index";
        } else {
            //10.如果不存在,返回登录失败页面,提示用户不存在
            model.addAttribute("error", "username { " + username + " } not exist");
            return "error";
        }
}

3.3.1.2. PHP 集成

3.3.1.2.1. 配置环境

在本例中,我们使用 composer管理第三方库(可选)

公钥:开发前需要在IT管理员权限下前往应用->详细->导出PKCS8公钥来获取解密 JWT用的公钥,并安全地放置在能访问到的目录内。

3.3.1.2.2. 接收令牌

JWT的 id_token 将会以url参数的方式传进callback页面,我们直接将其读取出来:

/* 使用composer 载入 php-JWT第三方库
 * 命令行 composer require firebase/php-JWT
 * 库链接:https://github.com/firebase/php-JWT
 * 我们使用Firebase的这个第三方库来实现对JWT的解密,如果不用composer的话,请自行添加源文件
 * 你也可以使用其他能对 JWT   token 进行RS256解码的工具或库
 */
// 在这里将 JWT 库引入,在这里为了便捷demo直接使用
// 推荐使用
require 'vendor/autoload.php';
use \Firebase\ JWT \ JWT ;
// 本地存储public key公钥的位置
$public_key_location = "LOCATION/TO/YOUR/PUBLIC-KEY/XXX.pem";
// 读取公钥信息,公钥在这里存储在一个.pem文件内
$public_key = file_get_contents($public_key_location);
// 从url的参数中读取 id_token ,即令牌
if (!empty($_GET[" id_token "])) {
    $JWT = $_GET[" id_token "];
    // 这里继续第二步:解析令牌
}
3.3.1.2.3. 解析令牌

通过第三方库 php-JWT,使用公钥对收到的 JWT token (即 id_token )进行解密,获取到用户信息并错误码为0的话,验证通过跳转到登录页面,失败则拒绝:

try {
    /**
     * You can add a leeway to account for when there is a clock skew times between
     * the signing and verifying servers. It is recommended that this leeway should
     * not be bigger than a few minutes.
     *
     * Source: http://self-issued.info/docs/draft-ietf-oauth-json-web- token .html#nbfDef
     */
    // Firebase的 JWT 库的一个参数,不出问题的话可以忽略
    // (可选)当服务器时间与本地时间不符时,可以通过这个leeway参数来调整容错
    JWT::$leeway = 60; // $leeway in seconds
    // 使用公钥、使用RS256算法对 JWT (即第一步传进来的 id_token )进行解密进行解密
    $decoded = JWT::decode($JWT, $public_key, array('RS256'));
    // 将解密的结果从class转化成PHP array
    $decoded_array = (array) $decoded;
    // 打印出解密的结果,成功!
    print("解密结果:<br>");
    foreach ($decoded_array as $key => $value) {
        print $key . ": " . $value . "<br>";
    }
    //注意
    // 获取到用户信息后,判断该用户是否存在于你的系统内
    if (userExistsInSystem()) {
        // 如果存在,那么登录成功,跳转到登录后页面
    } else {
        // 如果不存在,那么登录失败,跳转到显示错误页面
    }
} catch(Exception $e) {
    print "错误:" . $e->getMessage();
}

3.3.1.3. .NET 集成

3.3.1.3.1. 配置环境

.NET Framework 4及以上

SDK 和对接示例可以通过 【单点登录 - 相关下载】 下载参考。

3.3.1.3.2. 接收令牌
// id_token  是 IDaaS 请求时带来的,在body里获取,PublicKey是在 IDaaS 里注册应用时生成的,注册完可见,此示例代码是获取用户信息。
// JWT   SSO
[Route("jwt/sso/login")]
public ActionResult ssoUrl(String id_token )
{
    //1.接收方法为GET方式,参数名为 id_token
    //2.<解析令牌>为解析 id_token 并验证代码
}
3.3.1.3.3. 解析令牌

PublicKey: 解析令牌的过程中,我们会使用到应用的PublicKey。请在 JWT 应用->详细 中将PublicKey字段对应的内容拷贝并存储起来。

//1. 使用公钥,解析 id_token
string username;
DingdangSDK.DingdangUserRetriever retriever = new DingdangSDK.DingdangUserRetriever( id_token, PublicKey);
DingdangSDK.User user = null;

//2. 获取用户信息
user = retriever.retrieve();
username = user.sub;

//3. 判断用户名是否在自己系统存在
//4. 如果存在,登录成功,返回登录成功后的页面
//5. 如果注册时添加target_url,那么返回此自定义url页面
//6. 否则返回系统默认操作页面
//7. 如果不存在,返回登录失败页面,提示用户不存在

3.3.1.4. Python 集成

3.3.1.4.1. 下载资源库

本Python JWT 示例使用PyJWT 库来进行 JWT 的解密 官方文档请参考:https://pyjwt.readthedocs.io/en/stable/ 公钥:开发前需要在IT管理员权限下前往应用->详细->导出 PKCS8 公钥来获取解密 JWT用的公钥,并安全地放置在能访问到的目录内。

JWTtoken 将会以url参数的方式传进来,解密后进行认证判断

// 库的 github 链接 https://github.com/jpadilla/pyJWT
pip install PyJWT

// 注:CentOS系统如果使用时无法导入算法 RSAAlgorthm时需要下载pyJWT的2个依赖包
yum install ibffi-devel
pip install cryptography
3.3.1.4.2. 接收令牌
 ## 1.接收token
def get_idToken(token):
    if not token.strip():
        print('token信息不能为空')
    else:
        get_user_info(token)
3.3.1.4.3. 解析令牌
 #通过JWT解密库,使用公钥对传入的 id_token 进行解密。将公钥以字符串的形式从文件中读取出来,并作为key进行解密:

// 引入用到的包文件
import JWT
import json
from JWT.algorithms import RSAAlgorithm
from JWT.utils import force_bytes
from utils import key_path // 本例中key_path辅助方法是写在utils工具类中的
def get_user_info(id_token):
    try:
        algo = RSAAlgorithm(RSAAlgorithm.SHA256)
        pem_key = open(key_path('jwt_public_key_pkc8.pem'), 'r')
        public_key = algo.prepare_key(pem_key.read())
        token_info = jwt.decode(force_bytes(id_token), key=public_key, algorithms="RS256",
                                options={"verify_aud": False})
        # algorithms 签名算法,默认RS256
        # aud : audience 受众,在JWT应用详情中获取,这里指定不校验aud,如需校验,请传入audience,如下
        # token_info = jwt.decode(force_bytes(id_token), key=public_key, algorithms="RS256", audience='testplugin_jwt')
        # 注意防重放攻击,需要判断id_token是否已经使用过了,可以存放jti来达到该效果
        user_info = json.loads(json.dumps(token_info))
        username = user_info['sub']
        # 获取username,如需其它信息,请从user_info中获取
        print(username)
        # 3.判断用户名是否在自己系统存在
        # 4.如果存在, 登录成功,返回登录成功后的页面
        # 5.如果注册时添加redirect_url,那么返回此自定义url页面
        # 6.否则返回系统默认操作页面
        # 7.如果不存在, 返回登录失败页面, 提示用户不存在
    except Exception as e:
        print(e)

上面用到的key_path方法是用来获取public key位置的辅助方法,具体如下:

def key_path(key_name):
    return os.path.join(os.path.dirname(os.path.realpath(__file__)), 'keys', key_name)

3.3.1.5. 常见问题

3.3.1.5.1. Q:JDK 版本问题,导致 jar 包无法使用?

A:根据 JDK 的版本提供了 3 个版本的 jar 包,1.8 版本的可以直接导入 jar ,并且添加依赖。JDK1.6 或者 JDK1.7 需要手动导入相关的依赖 jar 包。请根据自己的 jdk 版本选择相对应的 jar 包。

3.3.2. SP发起流程研发

  • 前提

已经实现了 SSO 认证研发(IDP发起)

  • 实现流程

一般情况下,SP的开发者需要开发相应的代码来完成整个SP发起的 SSO流程。

首先,开发者需要在业务系统开发中,添加SP发起地址(如业务系统登录页面的第三方登录按钮,或者在业务系统的登录拦截器),当用户需要登录业务系统时,页面需要重定向到SP发起地址, 同时SP系统应该把当前的URL, 生成一个随机数关联保存在本地, 把这个随机数作为target_url 传递给IDaaS。

SP发起地址示例:
https://<idaas>/enduser/sp/sso/{应用ID}?enterpriseId={公司ID}&target_url=XXX

注意:

target_url:该参数为SP系统开发者可选参数,如果添加了该参数,IDaaS在完成登录后,会优先使用该值,覆盖在创建JWT应用时页面所填写的target_url,并把该值返回给SP。

3.3.3. SLO实现研发(可选)

3.3.3.1. 业务系统SLO开发集成

  • 调用IDaaS SLO 实现

业务系统需要结合自身退出机制实现,在退出自身同时时 调用IDaaS SLO 实现 IDaaS 平台登出。

IDaaS SLO 地址支持前端 GET、POST调用。使用POST时redirect_url和access_token可使用表单提交。

IDaaS SLO 地址示例:

http://<idaas>/public/sp/slo/{应用ID}?redirect_url={redirect_url}&access_token={access_token}

redirect_url :为登出后跳转地址,可选,若有值,则登出后重定向到该地址,若没值,则重定向到IDaaS登录页(在该登录页登录后会进入 IDaaS 主页)。

access_token:为 IDaaS 签发的 assess_token,可选,若有值,则会将该access_token失效。 业务系统前端调用IDaaS SLO接口时序图:

image.png

3.3.3.2. IDaaS SLO开发集成

业务系统需对外提供SP退出地址 供IDaaS 平台调用使用。退出URL请求方式为GET,IDaaS调用时会传递参数 state ,可用于判断是否为IDaaS发起的退出(若安全需要)。

  • 接口开发

所提供的SP退出地址的实现具体要根据应用的退出逻辑来。一般会清空会话(session)中的登录用户信息,记录退出日志或一些其他逻辑。​

且IDaaS调用该SP退出地址时会传递state参数,业务系统可以根据需要解析state进行安全检查。当IDaaS退出时,会在浏览器打开应用处填写的SP退出地址(应用开启支持SP退出),并带上state参数,如:https://sp.oa.xxx.com/logout?state=eyJhbGciOiJSUzI1NiIsImtpZCI6I…

state参数值是JWT格式的数据,SP应用可使用JWT的 publicKey 进行校验(verify)以证明其为IDaaS发起(这与SSO时校验id_token处理一致,有效时间5分钟),目的为防止别人篡改。verify的结果payload中包含信息示例如下:

{jti=HYPoIdYqOX8OYbhp3d-Pfw, iat=1610433203, exp=1610433503, iss={idphost}, aud=100wplugin_jwt6, sub={username}}

下面是实现的示例,可供参考。

接口开发完成后,即可配置到IDaaS平台对应的JWT应用处进行调试对接。

3.4. Step4 IDaaS上更新SSO地址

由于在第一步创建应用时,SSO 单点登录地址(即redirect_uri)不一定是SP开发完成后正确的URL。 所以,当业务系统开发工作结束后,有可能需要再返回 IDaaS 平台,以IT管理员身份,将这个地址进行更新,后续才能进行下一步的联调测试工作。同理,其它参数比如SP退出地址、target_url等也需要填写,如果需要的话。

image.png

3.5. Step5 单点登录效果验证

3.5.1. 从IDaaS发起单点登录

在完成IDaaS平台的redirect_uri更新之后,开发者可以新建一个测试账号进行单点登录效果验证,以确保JWT的应用接入成功。

4.5.1.1 新建一个普通账号

image.png

4.5.1.2 账号授权

使用【授权】-【应用授权】- 【应用授权主体】功能,给要测试的 JWT 应用授权账户。

image.png

3.5.1.1. 使用测试账号登录

使用测试账号登录后,即可看到创建的JWT测试应用 logo图标。

image.png

注:若此时无法看到图标,请检查

(1)应用是否开启?(【应用列表】查看及开启)

(2)账号是否被授予应用权限?(【应用授权】查看及授权)

3.5.1.2. 业务系统检查是否能获取到 id_Token

下一步, 点击这个图标后,会触发一个SSO URL, 通过检查IDaaS系统发送的id_token 和业务系统(SP)收到的id_token是否一致,从而确保业务系统能正确获取id_token。

SSO URL 示例:
https://www.example.com/sso/login?id_token=xxxx

(1)首先登录IDaaS系统

(2)点击应用 logo

(3)可以在浏览器地址栏中看到 id_token ,例如:
image.png (4)也可以使用浏览器的 [开发者工具] 看到 id_token 信息及SP二级页面的target_url信息

image.png

(5)如果id_token 正常,此时业务系统就需要检查是否能够收到 IDaaS 发送的 id_token 并且成功解析验签,获取用户信息。

3.5.1.3. 检查是否能正确跳转到业务系统指定页面

如业务系统成功获取并解析 id_token 正常,就应该能成功创建业务系统自己的会话(如session更新,生成cookie等),然后跳转到业务系统指定的页面。

3.5.2. 从业务系统(SP)发起单点登录

上面介绍完了IDP发起, 下面介绍SP发起的SSO过程。

3.5.2.1. 业务系统配置SP发起地址

业务系统已经实现整个SP发起SSO流程,并配置好对应的IDaaS 平台的SP发起地址。

3.5.2.2. 从业务系统(SP)发起登录

在浏览器输入业务系统(SP)的地址,比如用户现在需要登录邮箱,此时用户首先点击的就是邮箱地址(如 htttps://www.example.com/?email=xxxx ),然后邮箱服务需要把浏览器重定向到业务系统配置好的SP发起地址。

SP发起地址示例:
https://<idaas>/enduser/sp/sso/{应用ID}?enterpriseId={公司ID}&target_url=XXX

如果用户未登录,会跳转到IDaaS统一登录页面,进行登录。登录完成后,IDaaS系统会将浏览器重定向到redirect_uri地址(redirect_uri地址请在IDaaS平台 ->应用列表->应用信息里面查看)。并且带上id_token及target_url参数。当业务系统没有在SP发起地址里拼接具体的target_url参数时,IDaaS系统会采用在创建JWT应用时,填写默认的target_url。

redirect_uri地址示例:

https://www.example.com/sso/login?id_token=xxxx&target_url=yyyy

最后业务系统(SP)完成JWT令牌的验签和用户信息匹配的工作。验签成功后,业务系统将创建本系统的请求会话,然后把浏览器重定向到target_url地址。

3.5.3. 业务系统SLO

(1)在已经实现单点登录前提下,SSO进业务系统,然后点击业务系统的退出操作,根据实际实现退出到指定页面。

(2)此时在同一个浏览器下访问IDaaS平台任一资源页面都需要重新认证才可登录。

3.5.4. IDaaS平台SLO

3.5.4.1. IDaaS配置JWT 登出地址

业务系统要提供支持GET方式调用的登出地址给IDaaS,同时需要IDaaS将该地址配置并开启 SP退出功能

image.png

3.5.4.2. IDaaS登出检查

(1)登录IDaaS 平台,点击JWT应用进行单点登录

(2)此时点击IDaaS 登出按钮,浏览器新起tab页面访问 JWT的 登出地址 。一个应用对应一个tab。

注意:需要将浏览器的拦截弹出窗口功能关闭,否则将无法实现业务系统登出

3.6. Step6 完成

当所有测试工作结束后,就在 IDaaS 上完成了 SSO 单点登录的对接工作。如果IDaaS系统和SP(业务系统)都是使用的测试环境,那么在正式上线切换时,需要再次将 JWT 模板中的相关参数地址修改为正式生产环境的参数地址。