微信一键登录
微信小程序不需要用户下载安装,可以直接在微信内部使用,方便快捷。使用微信一键登录可以快速登录小程序,无需再进行注册或者输入账号密码登录,大大节省了时间和精力。
小程序登录
小程序可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系。
登录流程时序
文章介绍
本文采用Uniapp进行微信小程序的开发,后端使用.NET开发的WebAPI
获取开发者ID和密钥
前往微信公众平台使用微信扫码登录
后端
创建一条登录api,接收微信获取到的code
我的LoginResult类实现
public class MessageResult
{
public int Code { get; set; } = 200;
public string Message { get; set; } = "";
public bool Successed { get; protected set; }
public bool Failed { get; protected set; }
public MessageResult(int code, string message, bool b)
{
Code = code;
Message = message;
if (b)
{
Successed = true;
}
else
{
Failed = true;
}
}
public MessageResult(string message)
{
Message = message;
Successed = true;
}
public MessageResult() { }
}
public class LoginResult: MessageResult
{
public string? Token { get; set; }
public LoginResult(int code,string message)
{
base.Code = code;
base.Message = message;
base.Failed = true;
}
public LoginResult(string token)
{
Token = token;
base.Message = "登录成功";
base.Successed = true;
}
public LoginResult(int code,string message,bool b):base(code,message,b) { }
}
通过code去请求微信登录接口返回openid。
在表里查找有没有这个openid
有的话返回userId找到这个user然后获取token,没有就新建个user进数据库然后获取token。
可以根据你喜欢的方法去实现,表达的是我个人思路
private async Task<string> BuildTokenAsync(AppUser user)
{
var roles = await repository.GetRolesAsync(user);
List<Claim> claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
foreach (string role in roles)
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
return tokenService.BuildToken(claims, optJWT.Value);
}
public async Task<LoginResult> loginByWeChatOpenIdAsync(string code)
{
string authUrl = "https://api.weixin.qq.com/sns/jscode2session?grant_type=authorization_code";
//这里通过环境变量获取Id和密钥,你也可以改成明文
string appId = Environment.GetEnvironmentVariable("AppID");
string appSecret = Environment.GetEnvironmentVariable("AppSecret");
//最后的url拼接
authUrl = authUrl + "&appid=" + appId + "&secret=" + appSecret + "&js_code=" + code;
var httpClient = new HttpClient();
//发起get请求
using HttpResponseMessage response = await httpClient.GetAsync(authUrl);
var jsonString = await response.Content.ReadAsStringAsync();
//反序列化成对象
WechatOptions? wechatOptions = JsonSerializer.Deserialize<WechatOptions>(jsonString);
//没获取到openid就登录失败了
if(wechatOptions.openid != null)
{
var user = new AppUser();
var token = "";
//查找数据库里有没有这个openid
var chetWeChat = await weChatRepository.FindByOpenIdAsync(wechatOptions.openid);
if(chetWeChat != null)
{
//有的话通过userid查找这个用户
user = await repository.FindByIdAsync(chetWeChat.AppUserId);
}
else
{
//创建用户需要userName和password,为了不重复我就通过时间戳了
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
var pwd = Convert.ToInt64(ts.TotalSeconds).ToString();
user.UserName = "ChatGPT_" + pwd;
await repository.CreateAsync(user, pwd);
user = await repository.FindByNameAsync(user.UserName);
//用新建的用户id和openid添加一条数据
var newUser = new WeChatUser(user.Id, wechatOptions.openid);
var res = await weChatRepository.CreateWechatUserAsync(newUser);
}
//获取token
token = await BuildTokenAsync(user);
return new LoginResult(token);
}
return new LoginResult(404,"登录失败");
}
WechatOptions请求后反序列化的类
public class WechatOptions
{
public string session_key { get; set; }
public string openid { get; set; }
}
WeChatUser实体类
public class WeChatUser
{
public int Id { get; set; }
public string OpenId { get; set; }
public Guid AppUserId { get; set; }
public WeChatUser(Guid appUserId,string openId)
{
AppUserId= appUserId;
OpenId= openId;
}
}
还有什么遗漏记得评论留言
前端
登录界面
在项目文件夹下的manifest.json文件输入获取到的AppId
封装请求
const baseURL = 'https://localhost:3010';
function get(url){
return new Promise((resolve) => {
uni.request({
url: baseURL+url,
data: {},
method: "GET",
success(res) {
resolve(res.data)
}
});
});
}
export default{
async LoginByWeChat(code){
return await get("/IdentityServer/Login/LoginByWeChat?code="+code)
}
}
页面代码,我用了UviewUI框架,所以u-toast,u--image,u-button会报错,你可以换成你用的或者你也尝试一下UviewUI,虽然有时候会有许多烦恼
<template>
<view class="body" :style="{height:screenHeight}">
<u-toast ref="uToast"></u-toast>
<view style="height: 40%;">
<view class="logo">
<u--image :src="logoSrc" width="120px" height="120px"></u--image>
</view>
<view class="title">登录 TC Message</view>
<u-button text="微信一键登录" type="success" :hairline="false" throttleTime="2000" shape="circle"
@click="getUserProfile"></u-button>
</view>
</view>
</template>
<script>
import api from '../api.js'
export default {
data() {
return {
//屏幕高度
screenHeight: "",
logoSrc: "/static/logo.png"
};
},
onLoad() {
//获取屏幕高度,我的项目再store里已经取到了
uni.getSystemInfo({
success: (res) => {
this.screenHeight = res.windowHeight + "px"
}
})
},
methods: {
// 登录方法
async login(code) {
let that = this
//调用自己封装的方法
var res = await api.LoginByWeChat(code)
//登录成功跳转页面
if (res.successed) {
this.$refs.uToast.show({
type: 'success',
message: res.message,
complete() {
that.$store.state.token = res.token
//为了用动画所以用了navigateTo
uni.navigateTo({
url: '/pages/home/home'
})
}
})
} else {
this.$refs.uToast.show({
type: 'error',
message: res.message
})
}
},
getChatCode() {
//因为作用域先提前赋值
var that = this
//使用uni封装的一键登录方法
uni.login({
provider: 'weixin',
success(res) {
//成功后带着微信登录返回的code去请求我们的后端
that.login(res.code)
}
})
},
getUserProfile() {
var that = this
uni.getUserProfile({
desc: "获取你的昵称、头像",
success(res) {
if (res.errMsg == "getUserProfile:ok" && res.userInfo != undefined) {
//我用store来存储一些数据,你可以放到你要放的地方
that.$store.state.userInfo.nickName = res.userInfo.nickName,
that.$store.state.userInfo.avatarUrl = res.userInfo.avatarUrl
that.getChatCode()
}
},
complete(res) {
console.log(res);
}
})
}
}
}
</script>
<style lang="scss">
.body {
// width: 100%;
background: linear-gradient(#415169, #1e2d43);
.logo {
padding-top: 200rpx;
margin: auto;
width: 120px;
height: 120px;
}
.title {
width: 100%;
margin: 30px 0;
text-align: center;
font-size: 18px;
color: white;
}
.u-button {
width: 60% !important;
}
}
</style>
微信开发者工具需要微信登录,id也要对应
总结
- 在前端获取用户code
- 到后端通过code请求微信官方接口获得openid
- 在数据库里查找这个openid的用户,可以在用户类添加一条openid的属性或者新建个关联表,我新建多一个表
- 找到用户就获取token,没有就先创建再获取token返回,有关联表的话是添加两个表的数据了
- 返回token前端保存
仓库地址:gitee