用户中心统一身份认证平台

版本编号 *变化状态 变更内容和范围 变更日期 变更人 批准日期 批准人
1.0.0 A 新增 2023-11-15 李海东 程揭章

*变化状态:A——增加,M——修改,D——删除,N——正式发布

1 引言

1.1 执行摘要

  • 为智慧时空大数据平台建立统一的用户中心,实现各个子系统模块实现系统集成,一处登陆处处访问的需求。

2 用户中心接入

2.1 前提

接口中的clientId和clientSecret由统一用户授权中心(用户中心)下发,根据接入的应用不同进行不同的授权,clientId不可混用。
文档中的大部分接口均受到签名保护,受保护的接口在被调用时,调用者需要在HTTP请求头中增加clientId、sign和timestamp字段。接口请求有时效性校验,调用者不可使用同一组签名来重复发起HTTP请求。签名计算方法见附录。
接入方(子系统)应有自身的用户权限系统,用于控制用户在各自系统的具体使用权限,用户中心仅控制用户在应用级别的访问权限。

2.2 接入流程

登录流程图:

登录流程说明

1.用户访问子系统页面,子系统校验当前自身的用户登录状态。如果用户仍处于登录状态,则允许用户继续在子系统中进行操作,无需执行后续流程;

2.如果子系统非用户登录状态,则发起重定向请求至用户中心授权页面,URL为:BaseUrl?client_id=***&redirect=***;

3.跳转至用户中心授权页面后,用户中心将判断用户中心系统当前是否有登录用户。如果无登录用户,则展示登录页,用户在成功登录用户中心后,用户中心此时将存在登录状态的用户;

4.当用户中心存在登录状态的用户后,用户中心判断当前的用户是否有访问client_id=***的应用权限,如果无权限或者client_id=***的应用状态异常,用户中心会提示对应的错误异常。此时页面将无法成功跳转至子系统;

5.当用户访问子系统的权限校验通过后,用户中心将重定向页面至redirect=***的***页面,并在URL后附带?ticket=***参数,子系统后端根据ticket,调用用户中心的校验ticket接口,校验通过后,根据接口返回的用户中心用户信息,关联子系统用户进行无感登录,此时子系统将成功登录系统。(如果子系统根据自定义的逻辑无法关联到用户,需要自行提示用户或进行其它操作。用户中心生成的ticket有效期为60秒,验证一次后失效)

建议的用户关联逻辑:
新系统:成功登录后,根据用户中心返回的用户userId,关联子系统的用户。如果关联不到,则根据用户中心返回的用户信息自行提示创建新用户,用户的昵称和登录账号尽量保持一致,同时对应保存用户中心的userId到子系统。
已有系统:根据子系统用户体系的实际情况可通过手机号、邮箱、userId或userName进行关联系统用户。在用户中心中,上述四个属性均为唯一值。

注销流程说明

1.用户在子系统点击注销后,页面重定向至用户中心的注销页面,URL为:BaseUrl/sso-logout?client_id=xxx&redirect=xxx&immediate=1。其中:immediate为选填参数,如果重定向URL携带了immediate=1,则用户中心注销完成后将重定向到redirect指定的地址,否则用户中心将停留在用户中心的登录页面。

  • 注意:调用流程必须是子系统点击注销时调用,子系统登陆过期(例如:token过期)不能调用用户中心注销接口

2.3 接口列表

2.3.1 获取用户信息


接口定义

  • 接口名称:获取用户信息
  • 接入地址:/ums/ext/user/getUserInfo?umsUserId=***
  • 请求方法:GET
  • 功能描述:获取用户信息
  • 签名验证:

输入参数

参数名 类型 位置 必填 说明
umsUserId String Path 用户中心userId

请求样例

  • 接入地址:http://192.168.131.21:48081/ums/ext/user/getUserInfo?umsUserId=1699495958399

  • 请求方法:GET

  • 请求头:

    1
    2
    3
    4
    5
    6
    7
    Connection: keep-alive
    clientId: 94c39dd307e7ce7aa3e4c5c38f9f171da39d3
    sequenceId: 20161020153428000015
    sign: da55be21096d188394c39dd307e7ce7aa3e4c5c38f9f171da39d3a151d0595bb
    timestamp: 1533882163013
    Content-type: application/json
    version: 1.0
  • 请求体:

    1

  • 返回结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {
    "code": 200,
    "msg": "操作成功",
    "data": {
    "userId": 1699495958399,
    "userName": "user1",
    "nickName": "用户1",
    "email": "123456789@qq.com",
    "phonenumber": "17686868686",
    "sex": "0", //0男1女2未知
    "avatar": "***/img/***.png",
    "status": "0" //0状态正常1禁用
    }
    }

2.3.2 验证ticket


接口定义

  • 接口名称:验证ticket
  • 接入地址:/ums/ticket/check
  • 请求方法:POST
  • 功能描述:验证ticket
  • 签名验证:

输入参数

参数名 类型 位置 必填 说明
clientId String Body 用户中心颁发的应用id
ticket String Body 用户中心下发的授权凭据

请求样例

  • 接入地址:http://192.168.131.21:48081/ums/ticket/check

  • 请求方法:POST

  • 请求头:

    1
    2
    3
    4
    5
    6
    7
    Connection: keep-alive
    clientId: 94c39dd307e7ce7aa3e4c5c38f9f171da39d3
    sequenceId: 20161020153428000015
    sign: da55be21096d188394c39dd307e7ce7aa3e4c5c38f9f171da39d3a151d0595bb
    timestamp: 1533882163013
    Content-type: application/json
    version: 1.0
  • 请求体:

    1
    2
    3
    4
    {
    "clientId": "94c39dd307e7ce7aa3e4c5c38f9f171da39d3",
    "ticket": "88a7248cfbaa49369f98bfd960d01ee8"
    }
  • 返回结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {
    "code": 200,
    "msg": "操作成功",
    "data": {
    "userId": 1699495958399,
    "userName": "user1",
    "nickName": "用户1",
    "email": "123456789@qq.com",
    "phonenumber": "17686868686",
    "sex": "0", //0男1女2未知
    "avatar": "***/img/***.png",
    "status": "0" //0状态正常1禁用
    }
    }

3 附录

3.1 Java签名计算方法


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

/**
* @param url 用户中心完整的接口路径
* @param clientId 用户中心下发的clientId
* @param clientSecret
* @param timestamp
* @return
*/
public static String generate(String url, String clientId, String clientSecret, String timestamp) {
String sign = "";
try {
URL urlObj = new URL(url);
url = urlObj.getPath();
log.info("url:" + url);
log.info("appId:" + appId);
log.info("appKey:" + appKey);
log.info("timestamp:" + timestamp);
appKey = appKey.trim();
appKey = appKey.replaceAll("\"", "");
StringBuilder sb = new StringBuilder();
sb.append(url);
sb.append(appId).append(appKey).append(timestamp);
sign = Hex.encodeHexString(MessageDigest.getInstance("SHA-256").digest(sb.toString().getBytes(StandardCharsets.UTF_8)));
} catch (MalformedURLException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
return sign;
}