​ 使用Java后台作为微信小程序开发的时候,我们通常需要前后端分离开发。这时候,我们通常编写开发的RESTful风格的后端接口,从而使得微信小程序可以进行远程调用、获取数据。这时候就涉及到一个问题,我们的接口任何人都可以调用,怎么知道调用该接口的是谁呢?这时候我们便需要使用到了认证机制。接下来我们来简要介绍常用的认证机制

微信小程序认证

1. 问题引入

​ 使用Java后台作为微信小程序开发的时候,我们通常需要前后端分离开发。这时候,我们通常编写开发的RESTful风格的后端接口,从而使得微信小程序可以进行远程调用、获取数据。这时候就涉及到一个问题,我们的接口任何人都可以调用,怎么知道调用该接口的是谁呢?这时候我们便需要使用到了认证机制。接下来我们来简要介绍常用的认证机制。

2. 常见认证机制简介

2.1 HTTP Basic Auth

​ HTTP Basic Auth,每次请求API时都提供用户uername和password,简而言之,Basic Auth是配合restFul PAPI使用最简单的认证方式,只提供用户名密码即可,但这种情况容易将用户名密码暴露给第三方客户端,在生产环境中越来越少。因此,开发对外开发的RESTful API时,尽量避免HTTP Basic Auth。

​ Cookie认证机制就是为了一次请求认证在服务端建立一个Session对象,同时在客户端的浏览器创建一个Cookie对象;通过客户端带上Cookie对象,通过客户端带上Cookie对象来与服务器端的Session对象匹配状态管理。默认情况下,当我们关闭浏览器的时候,Cookie对象会被删除,但可以通过修改Cookie的expire time指定Cookie的生存时间。

2.3 OAuth

​ OAuth(开放授权)是一个开放的授权标准,允许用户让第三方应用访问该用户在某一个web服务上存储的私密资源,而无需用户名和密码提供第三方应用。

​ OAuth运行用户提供一个令牌,而不是用户名密码来访问他们的数据。每个令牌授权一个特定的第三方系统在特定的时段(例如,接下来2小时)内访问特定资源(例如仅仅是某一个相册的视频)。这样,OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+--------+                               +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+
Figure 1: Abstract Protocol Flow

这种基于OAuth的认证机制适用于个人消费者类的互联网产品,然后社交类APP等应用,但不适合拥有自认证权限管理的企业应用。

2.4 Token Auth

2.4.1大概流程
  1. 客户端使用用户名等请求登录
  2. 服务器端收到请求,验证用户名
  3. 验证成功后,服务器端签发token,再把token返回给客户端
  4. 客户端收到Token以后可以把它存储起来,比如放在Cookie里面
  5. 客户端每次收到服务端请求资源的时候需要带着客户端签发的token
  6. 服务器端收到请求,然后去验证客户端请求携带的token,验证成功,则取数据并返回。
2.4.2 与cookie对比
Token Cookie
支持跨域 不支持跨域
无状态 有状态
更加适合CDN
去耦合
不行考虑CSRF
性能高

CSRF:跨站请求仿造,基于Cookie的弱点

无状态登录:服务器端不保存登录信息;有状态(比如cookie)服务器端要存储信息。

3. JWT

​ JSON WEB Token ,是一种非常轻巧的规范。运行我们在用户与服务器间传输安全可靠的信息。

JWT组成

头部:用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以被表示成一个JSON对象。

载荷:载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包 含三个部分

签证:这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的签证。

4. 微信小程序实战

​ 基于以上的介绍,结合微信小程序的特色,我们选择了token来进行认证。下图展示了微信小程序的认证流程。

​ 结合微信小程序的认证过程,我们大致的执行流程如下:

  1. 微信小程序启动,调用wx.login获取code,wx.request携带code访问个人服务器
  2. 个人服务器发送HTTP请求调用微信接口,拿到openid等信息。
  3. 个人服务器拿到签发的openid,生产token,返回给小程序。
  4. 小程序存储token,每次访问接口时携带上。
  5. 服务器端接受到小程序的调用,校验小程序的token,校验成功则返回数据。

小程序端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 登录
wx.login({
success: res => {
wx.request({
url: 'http://localhost:9002/user/login',
method: "POST",
data: {
code: res.code
},
success: d => {
// 拿到token并存储
}
})
}
})

服务器端获取openid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private WXResponse getWxuserOpenId(String code) {
// 拼接请求参数
String url = "https://api.weixin.qq.com/sns/jscode2session?appid="
+ wxMsg.getAppId() + "&secret="
+ wxMsg.getAppSecret() + "&js_code="
+ code + "&grant_type=authorization_code";
// 使用restTemplate发送httpGet请求
String response = restTemplate.getForObject(url, String.class);
WXResponse wxResponse = null;
try {
wxResponse = JSON.parseObject(response, WXResponse.class);
} catch (Exception e) {
e.printStackTrace();
}
return wxResponse;
}

服务器端签发token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@PostMapping("/login")
public Result login(@RequestBody Map msg) {
// 获取携带的code
String code = (String) msg.get("code");
if (code == null) {
return new Result(false, StatusCode.ERROR, "参数异常");
}
// 根据code获取openid、sessionKey
WXResponse wxResponse = getWxuserOpenId(code);
if (wxResponse == null) {
return new Result(false, StatusCode.ERROR, "openid获取失败");
}
String sessionKey = wxResponse.getSession_key();
String openid = wxResponse.getOpenid();
if (openid == null) {
return new Result(false, StatusCode.ERROR, "openid获取失败");
}
// 生产token,并返回
String token = jwtUtil.createJWT(loginUser.getId(), loginUser.getNickname(), "user");
Map map = new HashMap();
map.put("token", token);
return new Result(true, StatusCode.OK, "登录成功", map);
}

5. 补充

理解OAuth 2.0:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

RESTful API 设计指南:www.ruanyifeng.com/blog/2014/05/restful_api.html

JSON Web Token 入门教程:www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

评论