1.概述
详细介绍微信小程序登录功能的实现流程,包括前端获取临时登录凭证、用户信息,以及后端通过凭证换取用户唯一标识(openid)、会话密钥(session_key)并处理用户信息的完整过程

2.核心流程

1. 前端通过wx.login()获取临时登录凭证(code)

2. 前端通过wx.getUserinfo( )/wx.getUserProfile()获取用户基础信息(昵称、头像等)

3. 前端将 code 和用户信息发送至后端接口

4. 后端接收 code,调用微信官方code2Session接口换取 openid 和 session_key

5. 后端处理用户信息(如存储到数据库),生成自定义登录态(token)返回给前端

6. 前端保存登录态,完成登录流程

7.登录流时序图

凭证/信息

位置

作用

有效期

code

小程序前端获取

一次性凭证,用于向服务器换取 openid

和 session_key

5分钟

openid

后端服务器

用户在小程序内的唯一标识,用于区分用户

永久

session_key

后端服务器

会话密钥,用于解密微信返回的敏感数据

动态变化

unionid

后端服务器

用户在开放平台账号下的统一标识,用于打通不同应用

永久

3.前端实现

(1)wx.getUserinfo()/wx.getUserProfile()的区别

wx.getUserinfo()只能在用户点击 button 组件(open-type="getUserInfo") 时触发授权

getUserProfile 并不需要像 getUserInfo 依赖 button 组件的 open-type 属性,它可以直在 JavaScript 代码中调用

(2)前端登录

小程序页面(如pages/index/index.vue)中添加一个用于触发登录的按钮。这个按钮应使用<button>标签,并设置open-type="getUserInfo"来触发用户信息的获取。同时,绑定一个处理函数(如getUserInfo)来响应用户的授权行为。

<template>
  <view>
    <button open-type="getUserInfo" @getuserinfo="getUserInfo">微信登录</button>
  </view>
</template>
<button bindtap="getUserInfoHandler" class="login-btn">获取用户信息</button>

编写getUserInfo方法来处理用户的授权信息。如果用户同意授权,则调用uni.login方法获取登录凭证(code),并将该code发送到后端服务器。

export default {
  methods: {
    /**
     * 处理用户信息授权事件
     * @param {Object} e - 事件对象,包含用户授权信息
     */
    getUserInfo(e) {
      // 判断用户是否允许授权
      if (e.detail.userInfo) {
        // 用户允许授权,获取用户信息
        const userInfo = e.detail.userInfo
        console.log('用户授权成功,用户信息:', userInfo)
        //用户信息处理方式,3种
        // 1. 保存到本地存储
        wx.setStorageSync('userInfo', userInfo)
        wx.showToast({
          title: '授权成功',
          icon: 'success',
          duration: 200
        })
        //2 . 可以将用户信息发送到后端结合code获取openId
        this.sendUserInfoToServer(userInfo)
      } else {
        // 用户拒绝授权
        console.log('用户拒绝授权')
        wx.showToast({
          title: '请授权以继续使用',
          icon: 'none',
          duration: 200
        })
      }
    },

    /**
     * 3.将用户信息发送到服务器
     * @param {Object} userInfo - 用户信息对象
     */
    sendUserInfoToServer(userInfo) {
      // 实际项目中,这里需要调用后端接口
      // 通常还需要结合wx.login获取的code一起发送
      wx.login({
        success: (loginRes) => {
          if (loginRes.code) {
            // 调用自己的后端接口,传递code和userInfo
            wx.request({
              url: 'https://你的后端接口地址',
              method: 'POST',
              data: {
                code: loginRes.code,
                userInfo: userInfo
              },
              success: (res) => {
                console.log('用户信息发送成功', res.data)
                // 可以在这里处理后端返回的登录状态等信息
              },
              fail: (err) => {
                console.error('用户信息发送失败', err)
                wx.showToast({
                  title: '服务器连接失败',
                  icon: 'none'
                })
              }
            })
          } else {
            console.error('获取code失败', loginRes.errMsg)
          }
        }
      })
    }
  }
}
Page({
  getUserInfoHandler(e) {
    // 调用 getUserProfile 获取用户信息
    wx.getUserProfile({
      success: (res) =>  ·
        console.log('用户信息获取成功', res.userInfo)
        // 处理用户信息(如保存到本地或发送到后端)
      },
      fail: (err) => {
        console.log('用户拒绝授权', err)
      }
    })
  }
})

4.后端基于SpringBoot、redis实现

处理从小程序前端发送过来的code。该接口应使用code调用微信的jscode2session接口,以换取用户的openId、sessionKey和unionId

//request
public class UserLoginRequest {
    private String code;
    private String nickname;
    private String avatar;
    private String phone


    public String getCode() { return code; }
    public void setCode(String code) { this.code = code; }
    //......

}
//reponse
public class WxCode2SessionResponse {
    private String openid; // 用户唯一标识
    private String session_key; // 会话密钥
    private String unionid; // UnionID(多平台统一标识)
    private Integer errcode; // 错误码
    private String errmsg; // 错误信息

调用微信官方接口换取 openid 和 session_key

@Service
public class WxService {
    @Autowired
    private WxConfig wxConfig;
    
    @Autowired
    private RestTemplate restTemplate; // 用于发送HTTP请求

    /**
     * 调用微信code2Session接口
     * @param code 前端传递的code
     * @return 微信返回的结果
     */
    public WxCode2SessionResponse getSessionInfo(String code) {
        // 1. 获取接口地址
        String url = wxConfig.getCode2SessionUrl(code);
        
        // 2. 发送GET请求
        String response = restTemplate.getForObject(url, String.class);
        
        // 3. 解析JSON响应
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(response, WxCode2SessionResponse.class);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("解析微信接口响应失败", e);
        }
    }
}

处理用户信息并生成 Token(生产环境进行加密返回)返回给前端

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper; // 假设已定义的数据库操作接口
    
    @Autowired
    private StringRedisTemplate redisTemplate; // 用于存储Token

    /**
     * 处理登录逻辑:保存用户信息并生成Token
     * @param openid 用户唯一标识
     * @param userInfo 前端传递的用户信息
     * @return 生成的Token
     */
    public String handleLogin(String openid, UserLoginRequest userInfo) {
        //处理用户信息
        //生成自定义登录态Token
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        //加密()
        
        //存储Token到Redis,设置过期时间(如2小时)
        redisTemplate.opsForValue().set(
            "login:token:" + token, 
            openid, 
            2, 
            TimeUnit.HOURS
        );
        
        return token;
    }
}
@RestController
@RequestMapping("/user")
public class LoginController {
    @Autowired
    private WxService wxService;
    
    @Autowired
    private UserService userService;

    /**
     * 处理微信小程序登录请求
     */
    @PostMapping("/login")
    public Result login(@RequestBody UserLoginRequest request) {
        // 1. 调用微信接口获取openid
        WxCode2SessionResponse sessionResponse = wxService.getSessionInfo(request.getCode());
        
        // 2. 检查微信接口返回是否成功
        if (sessionResponse.getErrcode() != null && sessionResponse.getErrcode() != 0) {
            return Result.fail("微信登录失败:" + sessionResponse.getErrmsg());
        }
        
        // 3. 处理用户信息并生成Token
        String token = userService.handleLogin(sessionResponse.getOpenid(), request);
        
        // 4. 返回Token给前端
        return Result.success("登录成功", token);
    }
}

5.注意事项

安全性:确保在传输过程中保护用户的隐私信息,如openId和sessionKey。

调试:在开发过程中,确保使用正确的AppID和AppSecret,并且服务器域名已正确配置在微信的合法域名列表中。

用户体验:提供清晰的授权提示和错误处理机制,以提升用户体验。

更多推荐