【2023最新】微信小程序中微信授权登录功能和退出登录功能实现讲解

一、讲解视频

教学视频地址: 视频地址

二、小程序前端代码

// pages/profile/profile.js
import api from "../../utils/api";
import { myRequest } from "../../utils/request";
import Notify from "@vant/weapp/notify/notify";
import Cache from "../../utils/cache";
import Tool from "../../utils/tool";


Page({

    /**
     * 页面的初始数据
     */
    data: {
        isLogin: false,
        userInfo: {
            username: "还未登录,请先登录!",
            headPic: api.BASE_URL + "/photo/view?filename=common/mine_normal.jpg"
        },
        basePhotoUrl: api.BASE_URL + "/photo/view?filename=",
        editUser: {},
        profileDialogVisible: false
    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
       this.validateLoginState();
    },

    /**
     * 生命周期函数--监听页面初次渲染完成
     */
    onReady: function () {

    },

    /**
     * 生命周期函数--监听页面显示
     */
    onShow: function () {

    },

    /**
     * 生命周期函数--监听页面隐藏
     */
    onHide: function () {

    },

    /**
     * 生命周期函数--监听页面卸载
     */
    onUnload: function () {

    },

    /**
     * 页面相关事件处理函数--监听用户下拉动作
     */
    onPullDownRefresh: function () {
        this.validateLoginState();
    },

    /**
     * 页面上拉触底事件的处理函数
     */
    onReachBottom: function () {

    },

    /**
     * 用户点击右上角分享
     */
    onShareAppMessage: function () {

    },

    // 预览图片
    previewHead: function () {
        let userInfo = this.data.userInfo;
        let basePhotoUrl = this.data.basePhotoUrl;
        wx.previewImage({
             current: userInfo.headPic === userInfo.wxHeadPic ? userInfo.wxHeadPic : basePhotoUrl + userInfo.headPic,
             urls: [userInfo.headPic === userInfo.wxHeadPic ? userInfo.wxHeadPic : basePhotoUrl + userInfo.headPic]
        })
    },
    // 验证登录状态
    validateLoginState: async function() {
        wx.showLoading({
            title: "获取登录信息...",
            mask: true
        })
        const loginUser = Cache.getCache(getApp().globalData.SESSION_KEY_LOGIN_USER);
        if(Tool.isEmpty(loginUser)) {
            wx.hideLoading();
            return;
        }
        const res = await myRequest({
            url: api.BASE_URL + "/app/user/get_login_user",
            method: "POST",
            data: {
                token: loginUser
            }
        });
        if(res.data.code === 0) {
            this.setData({
                userInfo: res.data.data,
                isLogin: true,
                editUser: res.data.data
            })
        }
        wx.hideLoading();
        wx.stopPullDownRefresh();
    },
    // 登录操作
    getLoginUser: function() {
        wx.showLoading({
            title: "正在登录...",
            mask: true
        })
        wx.getUserProfile({
            desc: "获取用户相关信息",
            success: res => {
                if(res.errMsg === "getUserProfile:ok") {
                    let username = res.userInfo.nickName;
                    let headPic = res.userInfo.avatarUrl;
                    wx.login({
                        success: async res => {
                            if (res.errMsg === "login:ok") {
                                // 调用后端接口,验证用户数据
                                const response = await myRequest({
                                    url: api.BASE_URL + "/app/user/wx_login",
                                    method: "POST",
                                    data: {
                                        wxHeadPic: headPic,
                                        wxUsername: username,
                                        code: res.code
                                    }
                                });
                                if(response.data.code === 0) {
                                    Notify({ type: "success", message: response.data.msg, duration: 1000 });
                                    Cache.setCache(getApp().globalData.SESSION_KEY_LOGIN_USER, response.data.data.token, 3600);
                                    this.setData({
                                        userInfo: response.data.data,
                                        editUser: response.data.data,
                                        isLogin: true
                                    });
                                } else {
                                    Notify({ type: "danger", message: response.data.msg, duration: 2000 });
                                }
                            } else {
                                wx.showToast({
                                    icon: "error",
                                    title: "登录失败"
                                });
                            }
                            wx.hideLoading();
                        },
                        fail: res => {
                            wx.showToast({
                                icon: "error",
                                title: "登录失败"
                            });
                            wx.hideLoading();
                        }
                    })
                } else {
                    wx.showToast({
                        icon: "error",
                        title: "获取用户失败"
                    });
                    wx.hideLoading();
                }
            },
            fail: res => {
                wx.showToast({
                    icon: "error",
                    title: "获取用户失败"
                });
                wx.hideLoading();
            }
        })
    },    
    // 登录验证
    authUser: function() {
        const loginUser = Cache.getCache(getApp().globalData.SESSION_KEY_LOGIN_USER);
        if(Tool.isEmpty(loginUser)) {
            Notify({ type: "danger", message: "请先登录!", duration: 2000 });
            return true;
        } else {
            return false;
        }
    },
    // 退出登录
    logout: async function() {
        const loginUser = Cache.getCache(getApp().globalData.SESSION_KEY_LOGIN_USER);
        const res = await myRequest({
            url: api.BASE_URL + "/app/user/logout",
            method: "POST",
            data: {
                token: loginUser
            }
        });
        if(res.data.code === 0) {
            Notify({ type: "success", message: res.data.msg, duration: 1000 });
        }
        Cache.removeCache(getApp().globalData.SESSION_KEY_LOGIN_USER);    
        this.setData({isLogin: false, userInfo: {
            username: "还未登录,请先登录!",
            headPic: api.BASE_URL + "/photo/view?filename=common/mine_normal.jpg"
        }});
    },
  
 
  
})

三、后端Java代码

<!--引入http连接依赖-->
<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>4.5.3</version>
</dependency>
package com.yjq.programmer.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yjq.programmer.bean.CodeMsg;
import com.yjq.programmer.dao.UserMapper;
import com.yjq.programmer.domain.User;
import com.yjq.programmer.domain.UserExample;
import com.yjq.programmer.dto.LoginDTO;
import com.yjq.programmer.dto.PageDTO;
import com.yjq.programmer.dto.ResponseDTO;
import com.yjq.programmer.dto.UserDTO;
import com.yjq.programmer.enums.RoleEnum;
import com.yjq.programmer.service.IUserService;
import com.yjq.programmer.utils.CommonUtil;
import com.yjq.programmer.utils.CopyUtil;
import com.yjq.programmer.utils.UuidUtil;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author 杨杨吖
 * @QQ 823208782
 * @WX yjqi12345678
 * @create 2023-09-25 17:08
 */
@Service
@Transactional
public class UserServiceImpl implements IUserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    // 填写上你的AppID,如何获取AppID自行百度,这步骤很简单
    private final static String APP_ID = "wxc41c88e07f3f1bd7";
    // 填写上你的AppSecret,如何获取AppSecret自行百度,这步骤很简单
    private final static String APP_SECRET = "99a06dc0d1e21d797a9915baca08c872";
    // 微信小程序登录校验请求地址
    private final static String LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";

    /**
     * 小程序授权登录验证
     * @param userDTO
     * @return
     */
    @Override
    public ResponseDTO<UserDTO> appWxLogin(UserDTO userDTO) {
        String url = LOGIN_URL + "?appid=" + APP_ID + "&secret="+ APP_SECRET + "&grant_type=authorization_code&js_code=" + userDTO.getCode();
        HttpClient client = HttpClients.createDefault(); // 创建默认http连接
        HttpGet getRequest = new HttpGet(url);// 创建一个get请求
        LoginDTO loginDTO = new LoginDTO(); // 存储下面http请求返回的结果
        try {
            // 用http连接去执行get请求并且获得http响应
            HttpResponse response = client.execute(getRequest);
            // 从response中取到响实体
            HttpEntity entity = response.getEntity();
            // 把响应实体转成文本
            String html = EntityUtils.toString(entity);
            loginDTO = JSON.parseObject(html, LoginDTO.class);
            if(null == loginDTO.getErrcode()) {
                userDTO.setWxId(loginDTO.getOpenid()); // 拿到openId,存入userDTO实体
            } else {
                return ResponseDTO.errorByMsg(CodeMsg.USER_WX_LOGIN_ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseDTO.errorByMsg(CodeMsg.USER_WX_LOGIN_ERROR);
        }
        // 使用微信openId查询是否有此用户
        UserExample userExample = new UserExample();
        userExample.createCriteria().andWxIdEqualTo(userDTO.getWxId());
        List<User> userList = userMapper.selectByExample(userExample);
        if(null != userList && userList.size() > 0) {
            // 已经存在用户信息,读取数据库中用户信息
            User user = userList.get(0);
            userDTO = CopyUtil.copy(user, UserDTO.class);
        } else {
            // 数据库中不存在,注册用户信息
            User user = CopyUtil.copy(userDTO, User.class);
            // 自定义工具类,生成8位uuid
            user.setId(UuidUtil.getShortUuid());
            user.setUsername(user.getWxUsername());
            user.setHeadPic(user.getWxHeadPic());
            user.setRoleId(RoleEnum.USER.getCode());
            if(userMapper.insertSelective(user) == 0) {
                return ResponseDTO.errorByMsg(CodeMsg.USER_REGISTER_ERROR);
            }
            // domain转dto 这步不是必须的,我项目中需要这步
            userDTO = CopyUtil.copy(user, UserDTO.class);
        }
        // 生成8位uuid作为登录的token,标识用户的登录信息
        userDTO.setToken(UuidUtil.getShortUuid());
        // 把用户登录信息存入redis中,定时1小时
        stringRedisTemplate.opsForValue().set("USER_" + userDTO.getToken(), JSON.toJSONString(userMapper.selectByPrimaryKey(userDTO.getId())), 3600, TimeUnit.SECONDS);
        return ResponseDTO.successByMsg(userDTO, "登录成功!");
    }

    
    /**
     * 获取当前登录用户
     * @param token
     * @return
     */
    @Override
    public ResponseDTO<UserDTO> getLoginUser(String token) {
        if(CommonUtil.isEmpty(token)){
            return ResponseDTO.errorByMsg(CodeMsg.USER_SESSION_EXPIRED);
        }
        String value = stringRedisTemplate.opsForValue().get("USER_" + token);
        if(CommonUtil.isEmpty(value)){
            return ResponseDTO.errorByMsg(CodeMsg.USER_SESSION_EXPIRED);
        }
        UserDTO selectedUserDTO = JSON.parseObject(value, UserDTO.class);
        return ResponseDTO.success(CopyUtil.copy(userMapper.selectByPrimaryKey(selectedUserDTO.getId()), UserDTO.class));
    }

    /**
     * 退出登录操作
     * @param userDTO
     * @return
     */
    @Override
    public ResponseDTO<Boolean> logout(UserDTO userDTO) {
        if(!CommonUtil.isEmpty(userDTO.getToken())){
            // token不为空  清除redis中数据
            stringRedisTemplate.delete("USER_" + userDTO.getToken());
        }
        return ResponseDTO.successByMsg(true, "退出登录成功!");
    }

   
}

四、备注

完整的配套代码资料获取请关注公众号:杨杨吖知识库,回复关键词:配套代码资料

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这里是杨杨吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值