登录态维持
- 在小程序中,业务服务端返回的session_id存在本地
- 请求时手动添加到请求头的cookie上
用到的微信mp api
- wx.getSetting() 获取用户是否授权过某个权限scope.xxxx
- wx.login() 获取临时登录凭证code,
- 内部调用wx.checkSession(),
- 如果过期会重新生成code,小程序请求微信服务接口,返回新的code
- 没过期,返回本地的code
- 这个code在微信服务端对应一个session_key和一个过期时间
- 业务方拿到code,调用微信服务接口,微信服务查表拿到session_key,返回给业务服务端
- 内部调用wx.checkSession(),
- wx.checkSession() 检查小程序登录态是否过期
- wx.getUserInfo() 获取微信用户信息,如果用户没有授权过或者没有登录(wx.checkSession()失败)过,会报错。
微信手机号、用户信息获取
<button open-type="getPhoneNumber">微信登录</button>- 只能通过这种方式获取手机加密数据
- 返回手机号加密数据
<button open-type="getUserInfo">获取信息</button>
业务方服务端接口
- /oauth/login 三方登录
- /self/login 手机号、验证码、密码登录
- /login/code 获取验证码
- /user/info 获取用户信息
- /user/update 更新用户信息
微信服务端接口
- auth.code2Session
- 参数 appid、appsecret、code(调用wx.login()拿到的)
- 获取 openid、unionid(如果这个appid绑定过unionid)、session_key(用来解密数据用的)
- auth.getAccessToken
- 参数 appid、appsecret
- 获取 access_token,接口调用凭证,在登录环节用不到
登录场景梳理
- 本地storage获取session_token
- 如果没有session_token,跳转到登录页,一般有两个操作按钮
- 获取微信手机号登录
- 用户点击
<button open-type="getPhoneNumber">按钮跳出授权提示,必须用按钮交互才拿到手机号加密信息 - 用户同意
- 回调函数拿到用户的加密数据
- 调用wx.checksession()接口,这一步可以跳过,但是可能会出现服务端调用微信服务异常情况。
- 如果过期,调用wx.login()接口,拿到code,类似用验证码功能
- 如果没有过期继续以下步骤
- 调用服务端/oauth/login接口
- 服务端拿到请求中的code和手机号加密数据
- 用code、小程序appid和appsecret,调用微信服务auth.code2Session接口,拿到微信登录态session_key、openid、unionid
- 服务端解密手机加密数据
- 通过上面微信返回的session_key和手机号加密数据,服务端解密拿到真实手机号
- 如果这个手机号不在用户表中,注册一个新用户,
- 如果存在,获取这个用户的信息,user_id等,
- 检查用户没有绑定过,有unionid,则用去查unionid,没有用openid查
- 建立关联,user_id、phone、openid或unionid
- 在session表中生成一条记录,
- 包含微信信息:session_key、openid、unionid(如果有的话)
- 包含自定义信息:用户id、手机号、过期时间
- 响应头设置set-cookie: <session_key>=<session_token>,这个session_token就是session记录id
- 返回失败
- 有可能是本地session过期,需要在调用/oauth/login接口前,
- 先调用wx.login()接口,刷新本地session,并修改本地的加密数据
- 有可能是本地session过期,需要在调用/oauth/login接口前,
- 返回成功
- 拿到response header cookies中业务方的session_token值,存到global,
- 调用获取用户信息/user/info接口,存到全局
- 跳到指定的页面
- 用户不同意,跳转到手动输入手机、密码或验证码登录页
- 拿到用户输入的手机号、密码或验证码
- 如果是验证码模式,点击获取验证码,
- 调用服务端/login/code获取验证码接口,
- 服务端拿到手机号,调用三方发送短信服务,
- 三方短信服务,给用户发验证码,并也给服务端返回验证码
- 服务在session表中生成一条记录,包含(验证码、过期时间)
- 如果是验证码模式,点击获取验证码,
- 调用服务端/self/login接口
- 拿到手机号,查用户表
- 如果不存在这个用户,注册一个新用户(用户表生成一条记录),session表生成一条新记录,set-cookie设置为新生成的sessionid。
- 如果存在这个用户,用户表中查到这个用户数据
- 如果是密码登录,对比两个密码是否一致,
- 如果不一致返回错误,
- 如果一致
- 在session中生成一条记录,包含(用户id、过期时间)
- 设置response header写入cookie,值为新生成的sessionid
- 如果是验证码登录
- 拿到验证码code,查验证码表,拿到验证码数据(id,code)
- 如果存在,并且两者匹配
- 在表中删除这条记录
- 在session中生成一条记录,包含(用户id、过期时间)
- 设置response header写入cookie,值为新生成的sessionid
- 设置response header写入cookie,并返回
- 不存在、不匹配,返回错误
- 如果存在,并且两者匹配
- 拿到验证码code,查验证码表,拿到验证码数据(id,code)
- 如果是密码登录,对比两个密码是否一致,
- 获取response_header上cookie信息,拿到session_key对应的值(session_token),手动调用api存入local_storage中(因为不是浏览器环境)
- 如果这个/oauth/login接口返回了用户信息
- 设置到global上,并且跳转到对应页面(默认是首页)
- 如果这个/oauth/login接口没有返回用户信息接口
- 在调用获取用户信息接口/user/info,拿到信息写入global,跳到指定页面
- 拿到用户输入的手机号、密码或验证码
- 用户点击
- 手动输入手机号密码登录
- 用户点击这个按钮,直接跳转到手机号、密码或验证码登录页
- 获取微信手机号登录
- 如果有session_token
- 把session_token,手动设置到请求头上,因为小程序环境不像浏览器环境会自动添加cookie到请求头,调用业务方用户信息接口/user/info
- 服务端获取请求头session_key对应的session_id,
- 如果session_id不存在,或者不存在于session表中,返回登录失败
- 如果能查到,拿到user_id,和过期时间expire_time
- 如果已过期(new Date() >= expire_time),返回失败
- 用user_id查用户表,
- 若不存在,返回失败
- 存在,响应中返回用户信息
- 成功返回用户数据
- 如果这个用户数据只有手机号,说明没有绑定过用户的微信账号数据
- 通过wx.getSettting()接口查看用户有没有授权scope.userInfo,
- 如果用户已经授权过获取用户详情,
- 直接调用获取详情,
- 调用服务端/user/update接口,写入昵称等微信数据
- 用户数据写入global,跳转首页
- 如果没有授权,页面展示
<button open-type="getUserInfo">接口,用户点击- 如果同意,
- 拿到数据,调用服务端/user/update接口,写入昵称等微信数据
- 用户数据写入global,跳转首页
- 如果不同意,用户数据写入global,跳转首页
- 如果同意,
- 如果用户已经授权过获取用户详情,
- 通过wx.getSettting()接口查看用户有没有授权scope.userInfo,
- 如果用户数据是完整的
- 把用户信息写入global上,或者是vuex上(用uniapp开发的话)
- 如果这个用户数据只有手机号,说明没有绑定过用户的微信账号数据
- 如果服务端返回异常(session_token过期),需要跳回到登录页
- 把session_token,手动设置到请求头上,因为小程序环境不像浏览器环境会自动添加cookie到请求头,调用业务方用户信息接口/user/info
- 如果没有session_token,跳转到登录页,一般有两个操作按钮