UniApp微信小程序开发实战:微信授权登录功能实现

内容分享3周前发布
0 0 0

在微信小程序开发中,授权登录是连接用户与服务的重大环节。本文基于前文的 VSCode+UniApp 开发环境,详细讲解如何在 Hello World 项目基础上快速集成微信授权登录功能,让你的小程序具备用户身份识别能力。

一、授权登录核心原理

微信小程序的授权登录遵循 OAuth 2.0 授权流程,核心步骤为:

  1. 获取用户授权(获取昵称、头像等基础信息)
  2. 获取微信登录凭证(code)
  3. 后端服务器通过 code 换取用户唯一标识(openid)
  4. 生成自定义登录态(Token)返回给前端

注意:微信官方要求,获取用户信息需用户主动触发(如点击按钮),不能自动弹出授权框

二、前端授权界面开发

在src/pages/index/index.vue中添加授权登录按钮和用户信息展示区域:

<template>
  <view class="container">
    <!-- 已登录状态展示 -->
    <view v-if="hasLogin" class="user-info">
      <image :src="userInfo.avatarUrl" class="avatar"></image>
      <text class="nickname">{{ userInfo.nickName }}</text>
      <button class="logout-btn" @click="logout">退出登录</button>
    </view>
    
    <!-- 未登录状态 -->
    <view v-else class="login-view">
      <text class="title">{{ message }}</text>
      <button 
        class="login-btn" 
        open-type="getUserInfo" 
        @getuserinfo="onGetUserInfo"
        withCredentials="true"
      >
        微信授权登录
      </button>
    </view>
  </view>
</template>

添加对应的样式:

/* 用户信息样式 */
.user-info {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 100rpx;
}
.avatar {
  width: 200rpx;
  height: 200rpx;
  border-radius: 50%;
  margin-bottom: 30rpx;
}
.nickname {
  font-size: 36rpx;
  margin-bottom: 40rpx;
}
.logout-btn {
  background-color: #ff4d4f;
  color: white;
}

/* 登录按钮样式 */
.login-btn {
  background-color: #07c160;
  color: white;
  padding: 15rpx 60rpx;
  margin-top: 40rpx;
}

三、实现授权登录逻辑

在<script>部分添加登录相关逻辑,完整代码如下:

<script setup>
import { ref, onLoad } from 'vue'

// 响应式数据
const message = ref('Hello World! ')
const hasLogin = ref(false)
const userInfo = ref({})
const token = ref('')

// 页面加载时检查登录状态
onLoad(() => {
  checkLoginStatus()
})

// 检查本地是否有登录状态
const checkLoginStatus = () => {
  const savedToken = uni.getStorageSync('token')
  const savedUserInfo = uni.getStorageSync('userInfo')
  
  if (savedToken && savedUserInfo) {
    token.value = savedToken
    userInfo.value = savedUserInfo
    hasLogin.value = true
  }
}

// 处理用户授权
const onGetUserInfo = async (e) => {
  // 用户拒绝授权
  if (!e.detail.userInfo) {
    uni.showToast({
      title: '请授权后使用',
      icon: 'none'
    })
    return
  }
  
  try {
    // 显示加载中
    uni.showLoading({ title: '登录中...' })
    
    // 1. 获取用户信息
    userInfo.value = e.detail.userInfo
    
    // 2. 获取登录凭证code
    const loginRes = await uni.login()
    if (loginRes.errMsg !== 'login:ok') {
      throw new Error('获取登录凭证失败')
    }
    const code = loginRes.code
    
    // 3. 调用后端接口换取token(实际项目替换为你的后端接口)
    // 这里使用模拟数据,实际开发中需要对接真实后端
    const mockToken = 'mock_' + Date.now()
    token.value = mockToken
    
    // 4. 保存登录状态到本地存储
    uni.setStorageSync('token', token.value)
    uni.setStorageSync('userInfo', userInfo.value)
    
    // 5. 更新登录状态
    hasLogin.value = true
    uni.showToast({ title: '登录成功' })
    
  } catch (err) {
    console.error('登录失败:', err)
    uni.showToast({
      title: '登录失败,请重试',
      icon: 'none'
    })
  } finally {
    uni.hideLoading()
  }
}

// 退出登录
const logout = () => {
  // 清除本地存储
  uni.removeStorageSync('token')
  uni.removeStorageSync('userInfo')
  
  // 更新状态
  hasLogin.value = false
  userInfo.value = {}
  token.value = ''
  
  uni.showToast({ title: '已退出登录' })
}
</script>

四、核心代码示例(Java)

前端获取到 code 后,需要后端配合完成登录流程,以下是 Java 版本的核心实现(基于 Spring Boot 框架):

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@RestController
public class LoginController {

    // 小程序AppID和AppSecret(实际项目中提议放在配置文件)
    private static final String APP_ID = "你的小程序AppID";
    private static final String APP_SECRET = "你的小程序AppSecret";
    // JWT密钥(实际项目中使用更复杂的密钥)
    private static final String JWT_SECRET = "你的密钥";

    @GetMapping("/api/login")
    public Result login(@RequestParam String code) {
        try {
            // 1. 调用微信接口换取openid和session_key
            String url = String.format(
                "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                APP_ID, APP_SECRET, code
            );
            
            RestTemplate restTemplate = new RestTemplate();
            String response = restTemplate.getForObject(url, String.class);
            JSONObject jsonObject = JSONObject.parseObject(response);
            
            // 检查是否获取成功
            if (jsonObject.containsKey("errcode")) {
                return Result.error("登录失败:" + jsonObject.getString("errmsg"));
            }
            
            String openid = jsonObject.getString("openid");
            String sessionKey = jsonObject.getString("session_key");
            
            // 2. 生成JWT token(有效期7天)
            Date expiration = new Date(System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000);
            String token = Jwts.builder()
                .setSubject(openid)
                .setExpiration(expiration)
                .signWith(SignatureAlgorithm.HS256, JWT_SECRET)
                .compact();
            
            // 3. 查询或创建用户(根据openid,此处省略数据库操作)
            // User user = userService.findByOpenid(openid);
            // if (user == null) {
            //     user = new User();
            //     user.setOpenid(openid);
            //     userService.save(user);
            // }
            
            // 4. 返回token给前端
            Map<String, String> data = new HashMap<>();
            data.put("token", token);
            return Result.success(data, "登录成功");
            
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("服务器异常,登录失败");
        }
    }
    
    // 响应结果封装类
    static class Result {
        private int code;
        private String message;
        private Object data;
        
        public static Result success(Object data, String message) {
            Result result = new Result();
            result.code = 0;
            result.data = data;
            result.message = message;
            return result;
        }
        
        public static Result error(String message) {
            Result result = new Result();
            result.code = -1;
            result.message = message;
            return result;
        }
        
        // getter和setter省略
    }
}

注意:实际项目中需要添加以下依赖(Maven):

<!-- Spring Web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- JSON处理 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.76</version>
</dependency>
<!-- JWT -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

五、调试与上线注意事项

  1. 本地调试配置
  • 在微信开发者工具中,进入「详情→本地设置」
  • 勾选「不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书」

2.上线前配置

  • 在微信公众平台配置合法域名(「开发→开发设置→服务器域名」)
  • 确保后端接口使用 HTTPS 协议
  • 完善用户隐私保护说明

3.用户体验优化

  • 登录失败时提供重试按钮
  • 加载状态显示清晰的提示
  • 首次登录时说明授权用途

通过本文的步骤,你实现微信授权登录功能。这一功能是大多数小程序的基础,掌握后可以进一步开发用户中心功能。

如果在开发中遇到授权相关问题,欢迎在评论区留言讨论~

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...