智能提醒助理系列-小程序静默登录

        本系列文章记录“智能提醒助理”wx公众号 建设历程。

本文介绍,如何让用户进入小程序之后就锁定用户,开始使用功能,去掉繁琐的登录认证流程。

一、需求出发点

用户进入小程序之后就开始使用功能,去掉繁琐的登录流程。拿来即用。

二、实现路径分析

方案一、小程序初始化之后,获取code,在服务端通过code获取openid作为用户标识。

方案二、在用户触发请求时,进行拦截,判断是否没有登录,则获取code,在服务端通过code获取openid作为用户标识。

三、最终方案

选择 方案二

四、实施路径

1、请求拦截设计

// 引入 uni-ajax 模块
import ajax from '@/uni_modules/u-ajax'
import {getAccessToken, xcxlogin} from '@/common/auth'
import {toast} from '@/common/common'
import config from '@/config'
import store from '@/store/index'

const baseUrl = config.baseUrl + config.baseApi;
const appId = config.appId;

// 创建请求实例
const instance = ajax.create({
    // 初始配置
    baseURL: baseUrl,
    // needAuth: true
})

// 添加请求拦截器
instance.interceptors.request.use(async config => {
    let token = getAccessToken();
    console.log("请求拦截器 config:",token, config.url)
    console.log("请求拦截器 member:",store.state.member.id)
    if (token ==="" && config.url !=="/auth/loginByXcx" ) {
        if(uni.getStorageSync("xcxlogin")==="1"){
            console.log("重复请求")
            return config;
        }
        uni.setStorageSync("xcxlogin","1")
        await xcxlogin();//登录
        uni.setStorageSync("xcxlogin","0")
        token = getAccessToken();
    }
    config.header['token'] = token;
    config.header['appId'] = appId;
    return config;
})

// 添加响应拦截器
instance.interceptors.response.use(
    response => {
        console.log("响应拦截器:response.data.msg==>",response)
        console.log("响应拦截器:response.data.msg==>",response.data.msg)
        let statusCode = response.statusCode;
        if (statusCode === 200) {
            let code = response.data.code || 0;
            switch (code) {
                case '400':
                    uni.showToast({title: response.data.msg, icon: 'none', duration: 2000})
                    break;
                case '401':
                    // token 自动续期
                    xcxlogin();
                    //toast(response.data.msg)
                    break;
                case '500':
                    uni.showToast({title: response.data.msg, icon: 'none', duration: 2000})
                    break;
            }
        } else {
            toast("请求失败")
        }
        // 对响应数据做些什么
        return response.data
    },
    error => {
        // 对响应错误做些什么
        return Promise.reject(error)
    }
)

// 导出 create 创建后的实例
export default instance

2、用户登录设计

import store from '@/store/index'
import request from '@/api/config/request';


const AccessTokenKey = 'ACCESS_TOKEN'
const RefreshTokenKey = 'REFRESH_TOKEN'

// ========== Token 相关 ==========

export function getAccessToken() {
    return uni.getStorageSync(AccessTokenKey)
}

export function getRefreshToken() {
    return uni.getStorageSync(RefreshTokenKey)
}

export function setToken(token) {
    uni.setStorageSync(AccessTokenKey, token)
    uni.setStorageSync(RefreshTokenKey, token)
}

export function removeToken() {
    uni.removeStorageSync(AccessTokenKey)
    uni.removeStorageSync(RefreshTokenKey)
}

export async function loginByXcx(code) {
    let res = await request.post({
        url: '/auth/loginByXcx',
        data: {'code': code}
    });
    const loginRes = res.data;
    setToken(loginRes["token"]);
    // 设置用户信息
    store.commit('SET_MEMBER', loginRes["userInfo"]);
    return res;
}

// 用户静默登录
export async function xcxlogin() {
    let res = await uni.login({
        provider: 'weixin', // 使用微信登录
    });
    return await loginByXcx(res[1]["code"])
}

3、服务端静默登录设计

/** 微信小程序登录 */
  @RequestMapping("loginByXcx")
  public Object loginByXcx(@RequestBody String data) throws IOException {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start("获取 登陆凭证");
    // 获取 登陆凭证code
    log.info("loginByXcx,code:{}",data);

    String loginIp = IpUtils.getIpAddr(request);
    // ip黑名单 校验
//    String login_black_ip_list = paramDictService.getKey(CacheConstant.XCX_LOGIN_BLACK_IP_LIST);

//    if (loginIp.matches(login_black_ip_list)) {
//      return R.failure("登录失败,疑似机器人注册!");
//    }
    // 获取 登陆凭证code
    HashMap<String, Object> jsonParam = JsonUtil.toObj(data, HashMap.class);
    String code = "";
    if (!StringUtils.isEmpty(jsonParam.get("code"))) {
      code = (String) jsonParam.get("code");
    }
    if(StringUtils.isEmpty(code)){
      return R.failure("登录失败,code缺失");
    }
    stopWatch.stop();

    stopWatch.start("jscode2session 获取openid unionid");
    // jscode2session 获取openid unionid
    String resData = null;
    try {
      resData = wechatUtil.code2session(code);
    } catch (Exception e) {
      return R.failure("登录失败,获取openid失败");
    }
    stopWatch.stop();

    stopWatch.start("jscode2session 解析响应结果");
    HashMap<String, String> sessionData = JsonUtil.toObj(resData, HashMap.class);
    log.info("loginByXcx,sessionData:{}",sessionData);

    String xcxOpenId = sessionData.get("openid");
    String unionid = sessionData.get("unionid");

    // 解析响应结果
    if (StringUtils.isEmpty(xcxOpenId)) {
      return R.failure("登录失败");
    }
    stopWatch.stop();

    stopWatch.start("静默注册");
    // 静默注册
    UserInfo userInfo = userInfoService.silenceRegister(unionid,loginIp,xcxOpenId,"");
    log.info("loginByXcx,静默注册完成:{}",userInfo.getId());
    stopWatch.stop();

    stopWatch.start("创建token");
    // 创建token
    Map<String, Object> tokenMap = tokenService.createToken(userInfo.getId(), userInfo.getNickName());
    String token = MapUtils.getString(tokenMap, "token");
    log.info("创建token:" + token);
    stopWatch.stop();

    stopWatch.start("获取整合后的用户信息");
    // 获取整合后的用户信息
    UserInfoVo resUserInfo = userInfoService.getUserInfo(userInfo.getId());
    stopWatch.stop();
    log.info("stopWatch 总耗时:{}",stopWatch.getTotalTimeMillis());
    log.info("stopWatch 详细信息:{}",stopWatch.prettyPrint());

    HashMap resultObj = new HashMap();
    resultObj.put("token", token);
    resultObj.put("userInfo", resUserInfo);

    return R.success(resultObj);
  }

五、总结

静默登录的好处在于,使用既注册,减少用户操作、降低犹豫期,先识别用户,后续再引导用户完善资料,最小化设计。比如:设置头像、昵称等用户信息。

从使用上来讲,只要有用户标识,就可以使用功能做交易了,如果用户需要展示个性化信息,可以再设置。

后续 在设计分享推荐功能的时候,就可以让用户分享即可关联推荐人。

欢迎大家来体验这款新上线的 智能提醒工具,感兴趣的在公众号 留言交流哈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值