前言

nestjs官方文档是英文,太难搞了,摸索了两天 ,把经验记下来。 以后备用

目录结构

|--src  //项目根目录
|--modules // 模块 比如用户模块,商品模块
|--app //入口模块
|--utils //一些工具类,比如生成token
|--decorator //自定义注解
|--guard // 自定义守卫
|--constants.ts //常量
|--main.ts //启动入口

登录

小程序前端传入js_code,后端拿这个请求微信服务端,获得用户信息(openid, session_key)

小程序登录页面的js

async onLogin() {
const { code } = await wx.login();
const url = 'http://localhost:3000/login';
const {data} = await request({method:"POST", url, data:{code} });
// 登录成功之后 将token存入全局 并重定向到首页
wx.setStorageSync('token', data.token);
wx.redirectTo({url: '/pages/index/index'})
}

后端controller 登录成功之后 将token返回给前端 让其存储起来 以后每次请求都要携带 作为身份识别

  @Post('login')
async onLogin(@Body('code') js_code: string): Promise<any> {
const token = await this.utils.genToken(js_code);
return { token };
}

后端 utils.ts 里genToken代码

import { JwtService } from '@nestjs/jwt';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom, map } from 'rxjs';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; @Injectable()
export default class Utils {
constructor(
private readonly httpService: HttpService,
private readonly jwtService: JwtService,
) {}
async genToken(js_code: string) {
// openid是用户在同一个小程序下的唯一表示,
// 即同一个用户在不同的小程序下的openid是不同的
// 所以当你的appid变化之后,用户的openid就会发生变化,只变AppSecret时 openid是不会变的。
const params: any = {
appid: 'xxxxxx', // 管理员在微信公众平台获取
secret: 'xxxxxx', // 管理员在微信公众平台获取
grant_type: 'authorization_code', // 写死
js_code,
};
// 请求微信服务端接口 返回session_key和openid
const res = await firstValueFrom(
this.httpService
.get('https://api.weixin.qq.com/sns/jscode2session', { params })
.pipe(map((response) => response.data)),
); const { openid, session_key, errcode } = res; // 如果微信服务端抛出错误,则将错误直接返回给前端
if (errcode) {
// https://betheme.net/news/txtlist_i90049v.html?action=onClick
throw new HttpException({ ...res }, HttpStatus.INTERNAL_SERVER_ERROR);
} else {
// 根据session_key和openid 组合成一个用户登录唯一标识token 并维护其生命周期(比如会话变更 就需要重新让其登录)
// 之后的小程序端的每一个请求都需要携带此token 让我鉴权
return this.jwtService.sign({ openid, session_key });
}
}
}

获取用户信息

接上步, 如果小程序登录成功 应该跳转到首页。 首页一般都会调用一些接口 比如获取用户信息啥的 这里举例获得用户的openid

后端controller

  @Post('userinfo')
userInfo(@AuthUser() user) {
console.log(user);
return { data: {} };
}

@AuthUser 是自定义的一个注解,用来获取请求参数中的user的,在decorator/index.ts里

当然你也可以不用注解 而通过接受@Request 里获取,只是麻烦些而已。

import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const AuthUser = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);

为啥请求参数里有个user呢 这是因为 我将user注入到全局所有的request里了 通过守卫guard/auth.guard.ts。

接下来讲讲这个守卫是干什么。

守卫,相当于拦截器,比拦截器写起来体验更好。

用来鉴权的,定义那些接口需要token 哪些不需要token 一般处理登录登出接口 其它都需要

并在这里边 将token解码 将解码后的内容塞入request 以便后续的controller 们使用

import {
Injectable,
Inject,
CanActivate,
HttpException,
HttpStatus,
ExecutionContext,
UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt'; @Injectable()
export class AuthGuard implements CanActivate {
@Inject()
private readonly jwtService: JwtService; // context 请求的(Response/Request)的引用
async canActivate(context: ExecutionContext): Promise<boolean> {
// console.log('进入全局权限守卫...');
// 获取请求对象
const request = context.switchToHttp().getRequest();
// 获取请求头中的token字段
const token = context.switchToRpc().getData().headers.token;
// 如果白名单内的路由就不拦截直接通过
if (this.hasUrl(this.urlList, request.url)) {
return true;
}
// 验证token的合理性以及根据token做出相应的操作
if (token) {
try {
// 这里可以添加验证逻辑
const payload = this.jwtService.verify(token);
request.user = payload; // 注入到请求中 这样每个控制器直接拿到用户信息 不用每个都需要去解码了
return true;
} catch (e) {
throw new HttpException(
'没有授权访问,请先登录',
HttpStatus.UNAUTHORIZED,
);
}
} else {
throw new HttpException('没有授权访问,请先登录', HttpStatus.UNAUTHORIZED);
}
} // 白名单数组
private urlList: string[] = ['/login']; // 验证该次请求是否为白名单内的路由
private hasUrl(urlList: string[], url: string): boolean {
let flag: boolean = false;
if (urlList.indexOf(url) >= 0) {
flag = true;
}
return flag;
}
}

最后注意语法

app.module.ts 里需要提前注入这些依赖 方可在上遍中 使用一些服务和工具

import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { JwtModule } from '@nestjs/jwt';
import Utils from '../../utils';
import { APP_GUARD } from '@nestjs/core';
import { AuthGuard } from 'src/guard/auth.guard'; @Module({
imports: [
HttpModule,
JwtModule.register({ // 注入jwt模块
secret: 'dsh',
signOptions: { expiresIn: '60s' },
}),
],
controllers: [AppController],
providers: [
AppService,
Utils,
{ // 注将自定义守卫入全局
provide: APP_GUARD,
useClass: AuthGuard,
},
],
})
export class AppModule {}

nestjs微信小程序登录授权的更多相关文章

  1. uni-app微信小程序登录授权

    微信小程序授权是非常简单和常用的功能,但为了方便,还是在此记录一下要点: 首先是需要用到一个授权按钮来触发获取用户信息授权: 关键在于 open-type 为 getUserInfo , 然后有个@g ...

  2. 关于微信小程序登录授权

    小程序的API接口文档写的很清晰,现在理一遍思路. 前端通过wx.login()获取code ,把code发给后台,后台返回openid,再获取用户的授权信息(这里先判断是否授权,授权过的就直接进入小 ...

  3. 微信小程序登录授权并获取手机号

    一.请求发送 携带 code 到后台换取 openid var that = this; wx.login({ success(res) { console.log(res); var code = ...

  4. spring mvc+redis实现微信小程序登录

    本文将详细的介绍微信小程序的登录流程以及在ssm框架下如何实现小程序用户登录 登录流程概要 主要的登录流程可以参考官方提供的一张流程图: 1.微信前台页面: 在微信版本更新之后,提高了安全机制,我们需 ...

  5. 基于Shiro,JWT实现微信小程序登录完整例子

    小程序官方流程图如下,官方地址 : https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html ...

  6. 微信小程序登录JAVA后台

    代码地址如下:http://www.demodashi.com/demo/12736.html 登录流程时序登录流程时序 具体的登录说明查看 小程序官方API 项目的结构图: springboot项目 ...

  7. 微信小程序登录对接Django后端实现JWT方式验证登录

    先上效果图 点击授权按钮后可以显示部分资料和头像,点击修改资料可以修改部分资料. 流程 1.使用微信小程序登录和获取用户信息Api接口 2.把Api获取的用户资料和code发送给django后端 3. ...

  8. 全栈项目|小书架|微信小程序-登录及token鉴权

    小程序登录 之前也写过微信小程序登录的相关文章: 微信小程序~新版授权用户登录例子 微信小程序-携带Token无感知登录的网络请求方案 微信小程序开通云开发并利用云函数获取Openid 也可以通过官方 ...

  9. Flask与微信小程序登录(后端)

    开发微信小程序时,接入小程序的授权登录可以快速实现用户注册登录的步骤,是快速建立用户体系的重要一步.这篇文章将介绍 python + flask + 微信小程序实现用户快速注册登录方案(本文主要进行后 ...

  10. Spring Security 整合 微信小程序登录的思路探讨

    1. 前言 原本打算把Spring Security中OAuth 2.0的机制讲完后,用小程序登录来实战一下,发现小程序登录流程和Spring Security中OAuth 2.0登录的流程有点不一样 ...

随机推荐

  1. JVM 新生代垃圾回收如何避免全堆扫描?

    JVM 新生代垃圾回收如何避免全堆扫描? 在 JVM 新生代的垃圾回收(Minor GC)过程中,为了提高效率并减少回收时间,垃圾收集器会避免对整个堆(包括新生代和老年代)进行扫描.以下是 JVM 如 ...

  2. JVM 的内存区域是如何划分的?

    JVM 的内存区域划分 JVM 在运行时会将内存划分为多个区域,用于管理程序运行时的不同类型数据.以下是 JVM 内存的主要划分: 1. 方法区(Method Area) 定义: 方法区是运行时数据区 ...

  3. 学习nodejs的一点笔记

    >>1.模块:一个文件即为一个模块 1)global可以声明全局变量 (跨模块) 例如:global a = 100; console.log(global.a);   //输出100 2 ...

  4. access vba实现OLE对象保存到本地

    参考oletodisk的实现方法,更新为在64位office上野可以运行,函数模块代码如下: 1 Option Compare Database 2 Option Explicit 3 4 5 'DE ...

  5. IP、端口相关

    Windows端口被占用 按住[Windows+R]键输入cmd回车 输入命令[netstat -aon|findstr "端口号"]后按回车,找对最后一列对应的数字,即为这个端口 ...

  6. ElasticSearch学习——帮助类

    ElasticSearch第五步-.net平台下c#操作ElasticSearch详解 - 梦亦晓 - 博客园 (cnblogs.com) C# 如何使用 Elasticsearch (ES) - 领 ...

  7. 1K star!这个开源项目让短信集成简单到离谱,开发效率直接翻倍!

    嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 "让简单的事情回归简单的本质" -- SMS4J 项目宣言 SMS4J ...

  8. 【神兵利器】Windows平台shellcode免杀加载器

    项目介绍 免杀,bypassav,免杀框架,nim,shellcode,使用nim编写的shellcode加载器,可快速生成免杀可执行文件 下载地址 Windows平台shellcode免杀加载器下载 ...

  9. IT/互联网行业突围之路:ChatGPT驱动下的未来

    @charset "UTF-8"; .markdown-body { line-height: 1.75; font-weight: 400; font-size: 15px; o ...

  10. K8s进阶之外部访问Pod的几种方式

    概述 K8s集群内部的Pod默认是不对外提供访问,只能在集群内部进行访问.这样做是为什么呢? 安全性考虑 Kubernetes设计时遵循最小权限原则,即组件仅获得完成其任务所需的最少权限.直接暴露Po ...