一、单点简述
服务平台基于JWT(Json Web Token)协议的统一认证服务,可实现用户从第三方平台跳转登录至服务平台,即不需要再次登录的效果。官网地址:https://jwt.io
二、接入说明
1、接入流程
(1)对接方向服务平台提交单点申请,平台提供 baseUrl、appKey、appSecret 三组参数。
(2)对接方将用户字段信息签名加密生成 token。
(3)对接方携带 appKey 和 token 参数发起请求。
名词解释
1、公共参数说明:
${baseUrl}:平台提供的请求地址前缀
${appKey}:平台提供的唯一标识
${appSecret}:平台提供的密钥
2、请求地址
| 入口类型 | 访问链接 |
|---|---|
| WEB端/移动端地址 | ${baseUrl}/login/wechatlogincheck.html?appKey={厂商服务,平台提供}&token={鉴权凭证} |
登录示例
根据平台提供的参数:baseUrl,appKey,token进行拼接【token需要进行JWT鉴权加密】
请求地址:${baseUrl}/login/wechatlogincheck.html?appKey={厂商服务,平台提供}&token={鉴权凭证}
请求示例:https://school.nicezhuanye.com/login/wechatlogincheck.html?appKey=xxx&token=xxx
3、请求参数
| 参数名 | 是否必填 | 说明 |
|---|---|---|
| appKey | 是 | 平台提供的对接厂商唯一标识 |
| token | 是 | 鉴权凭证,参考签名方式 |
Payload 用户字段信息说明【Token】
| 参数名 | 是否必填 | 描述 |
|---|---|---|
| userEID | 是 | 用户EID 【平台ID/登录名/第三方厂商ID/自注册手机号/自注册第三方ID】 |
| userType | 是 | 用户类型【1: 学生,2: 老师,3: 家长】 |
| schoolEID | 是 | 学校EID【平台学校ID/第三方学校ID】【userEID使用登录名时,必填】 |
| sysTime | 是 | 当前时间戳,单位是秒 |
1、平台将自动校验userEID的所属类型【平台内设置】。
2、userEID支持五种类型:平台ID/登录名/第三方厂商ID/自注册手机号/自注册第三方ID。
3、userEID使用登录名时,schoolEID值不能为空,需要双方学校建立映射关系。
单点登录跳转失败时,如需跳过服务平台登录页,可在URL添加参数直接跳转至错误页: &failUrl=https://school.nicezhuanye.com/login/error.html
1、双方平台用户确定业务字段(学号,手机号,身份证)对接,由学校管理员进行数据维护即可。
2、双方平台用户对应机制依赖于第三方关键值映射表,该表需使用对应学校管理员账号维护。用户第一次跳转进入本平台访问时,需要在认证界面输入手机号进行关联账号,之后才能直接跳转。
三、JWT签名方式
1、JWT创建步骤
JWT由三部分组成:Header(头部)、Payload(负载) 和 Signature(签名),生成token的具体步骤如下,可参考官网【官网地址:https://jwt.io】:
1、创建Header对象
2、创建Payload对象
3、将Header和Payload进行Base64编码
4、使用Header,Payload,appSecret生成签名
5、拼接Header、Payload和Signature,生成完整JWT的token
2、JWT代码示例【java代码】
/**
* @Description: JWT签名方式
* @author: hzy
* @create: 2026-02-28 17:29
*/
public class JwtUtil {
/**
* 平台提供的密钥
*/
private static String SECRET_KEY = "appSecret";
/**
* 生成token
* @param userEID
* @param userType
* @param schoolEID
* @return Header.Payload.Signature
*/
private static String generateToken(String userEID, String userType, String schoolEID) {
// 创建Header对象,并将算法和类型设置为固定值
JSONObject header = new JSONObject();
header.put("alg", "HS256");
header.put("typ", "JwtUtil");
// 创建Payload对象,设置需要携带的信息
JSONObject payload = new JSONObject();
long timeMillis = System.currentTimeMillis() / 1000;
payload.put("userEID", userEID);
payload.put("userType", userType);
payload.put("schoolEID", schoolEID);
payload.put("sysTime", timeMillis);
// 将Header和Payload进行Base64编码
String encodedHeader = Base64.getEncoder().encodeToString((header.toString().getBytes()));
String encodedPayload = Base64.getEncoder().encodeToString((payload.toString().getBytes()));
// 生成签名
String signature = generateSignature(SECRET_KEY, encodedHeader + "." + encodedPayload);
// 拼接Header、Payload和Signature,生成完整的JWT token
return encodedHeader + "." + encodedPayload + "." + signature;
}
/**
* 生成签名
*
* @param appSecret 平台提供的密钥
* @param data Header.Payload
* @return Signature
*/
private static String generateSignature(String appSecret, String data) {
try {
byte[] secretKeyBytes = appSecret.getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(secretKeySpec);
byte[] signatureBytes = mac.doFinal(data.getBytes());
return Base64.getUrlEncoder().encodeToString(signatureBytes);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
String token = generateToken("13900001234", "1", "25320316");
System.out.println("生成token信息: " + token);
}
}