Session

session是服务器为每个用户的浏览器创建的一个会话对象

session会被记录到浏览器的cookie中,用来区分用户

Nestjs Session

如果将Nestjs的默认框架指定为express,意味着项目支持express的插件,所以可以安装express的session

1
npm i express-session --save

需要智能提示可以安装声明依赖

1
npm i @types/express-session -D

然后在main.ts引入,通过app.use注册session

1
2
3
import * as session from 'express-session'

app.use(session())

配置项:

键名含义
secret生成服务端session签名,可以理解为加盐
name生成客户端cookie的名字,默认为connect.sid
cookie设置返回到前端key的属性,默认值为{ path: ‘/’, httpOnly: true, secure: false, maxAge: null }
rolling在每次请求时强行设置cookie,这将重置cookie过期时间,默认值为false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { NestFactory } from '@nestjs/core';
import { VersioningType } from '@nestjs/common';
import { AppModule } from './app.module';
import * as session from 'express-session';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableVersioning({
type: VersioningType.URI,
});
app.use(
session({
secret: 'yajue',
name: 'yjsp.session',
rolling: true,
cookie: { maxAge: null },
}),
);
await app.listen(3000);
}
bootstrap();

验证码案例

前端

安装element-plus:

1
npm install element-plus -S

页面(App.vue):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<template>
<div class="wraps">
<el-form :label-position="labelPosition" label-width="100px" :model="formLabelAlign" style="max-width: 460px">
<el-form-item label="账号">
<el-input v-model="formLabelAlign.name" />
</el-form-item>
<el-form-item label="密码">
<el-input type="password" v-model="formLabelAlign.password" />
</el-form-item>
<el-form-item label="验证码">
<div style="display:flex">
<el-input v-model="formLabelAlign.code" />
<img @click="resetCode" :src="codeUrl" alt="">
</div>
</el-form-item>
<el-form-item>
<el-button @click="submit">登录</el-button>
</el-form-item>
</el-form>
</div>
</template>

<script setup lang='ts'>
import { reactive, ref } from 'vue';

const codeUrl = ref<string>('/api/user/code')

const resetCode = () => codeUrl.value = codeUrl.value + '?' + Math.random()

const labelPosition = ref<string>('right')

const formLabelAlign = reactive({
name: "",
password: "",
code: ""
})

const submit = async () => {
// 如果使用axios,请求时默认不携带cookie
// 可以使用axios.defaults.withCredentials=true使其携带
await fetch('/api/user/create', {
method: "POST",
body: JSON.stringify(formLabelAlign),
headers: {
'content-type': 'application/json'
}
}).then(res => res.json())
}
</script>

<style>
* {
padding: 0;
margin: 0;
}

.wraps {
display: flex;
justify-content: center;
align-items: center;
height: inherit;
}

html,
body,
#app {
height: 100%;
}
</style>

跨域设置:

1
2
3
4
5
6
7
proxy:{
'/api':{
target:'http://localhost:3000/',
changeOrigin:true,
rewrite: path => path.replace(/^\/api/, ''),
}
}

后端

安装验证码插件svg-captcha:

1
npm install svg-captcha -S

controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import {
Controller,
Get,
Post,
Body,
Request,
Response,
Session,
} from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import * as svgCaptcha from 'svg-captcha';

@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}

@Get('code')
createCode(@Request() req, @Response() res, @Session() session) {
const Captcha = svgCaptcha.create({
size: 4, // 字符数
fontSize: 50, // 字符大小
width: 100, // 图片宽度
height: 34, // 图片高度
background: '#cc9966', // 图片背景颜色
});
session.code = Captcha.text;
res.type('image/svg+xml');
res.send(Captcha.data);
}

@Post('create')
createUser(@Body() body, @Session() session) {
console.log(body, session.code);
if (session.code?.toLocaleLowerCase() === body?.code?.toLocaleLowerCase()) {
return {
code: 200,
message: '验证码正确',
};
} else {
return {
code: 200,
message: '验证码错误',
};
}
}
}