当前位置:网站首页>3、 Midway interface security certification
3、 Midway interface security certification
2022-07-24 08:31:00 【Code road hero】
Before reading this article , You need to read the pre content in advance :
One 、Midway Additions and deletions
Two 、Midway Add, delete, modify and check the packaging and tool classes
3、 ... and 、Midway Interface security authentication
Four 、Midway Integrate Swagger And support JWT bearer
5、 ... and 、Midway Use of environment variables in
A lot of times , The back-end interface can only be accessed after login , Even some interfaces need to have corresponding permissions to access .
Realize here bearer Verification mode (bearerFormat by JWT).
install JWT Components
>npm i @midwayjs/[email protected] --save
>npm i @types/jsonwebtoken --save-dev
After the installation package.json The following configurations will appear in the file
{
"dependencies": {
"@midwayjs/jwt": "^3.3.11"
},
"devDependencies": {
"@types/jsonwebtoken": "^8.5.8"
}
}
add to JWT To configure
- modify
src/config/config.default.ts, Add the following ;
// src/config/config.default.ts
jwt: {
secret: 'setscrew',
expiresIn: 60 * 60 * 24,
}
- register
JWTComponents ;
// src/configuration.ts
import * as jwt from '@midwayjs/jwt';
@Configuration({
imports: [
jwt,
//...
],
})
export class ContainerLifeCycle {
//...
}
About JWT Detailed use documents of , see :http://www.midwayjs.org/docs/extensions/jwt
install Redis Components
>npm i @midwayjs/[email protected] --save
>npm i @types/ioredis --save-dev
After the installation package.json The following configurations will appear in the file
{
"dependencies": {
"@midwayjs/redis": "^3.0.0"
},
"devDependencies": {
"@types/ioredis": "^4.28.7"
}
}
register Redis Components
// src/configuration.ts
import * as redis from '@midwayjs/redis';
@Configuration({
imports: [
redis,
// ...
],
})
export class ContainerLifeCycle {
// ...
}
Add the configuration
modify src/config/config.default.ts, Add the following :
add to Redis To configure
// src/config/config.default.ts
redis: {
client: {
host: 127.0.0.1,
port: 6379,
db: 0,
},
}
About Redis Detailed use documents of , see :http://www.midwayjs.org/docs/extensions/redis
Add security interception configuration
// src/config/config.default.ts
app: {
security: {
prefix: '/api', # Specified /api The initial interface address needs to be intercepted
ignore: ['/api/login'], # Specify the interface address , No interception required
},
}
Add interface security interception middleware
Add constant definition
// src/common/Constant.ts
export class Constant {
// When logging in to verify , Cache user login status KEY The prefix of
static TOKEM = 'TOKEN';
}
Add user access context class
// src/common/UserContext.ts
/** * Store the status data of the access context after login , There will also be redis In cache */
export class UserContext {
userId: number;
username: string;
phoneNum: string;
constructor(userId: number, username: string, phoneNum: string) {
this.userId = userId;
this.username = username;
this.phoneNum = phoneNum;
}
}
Add or edit src/interface.ts, take UserContext Sign up to ApplecationContext in
// src/interface.ts
import '@midwayjs/core';
import {
UserContext } from './common/UserContext';
declare module '@midwayjs/core' {
interface Context {
userContext: UserContext;
}
}
New Middleware src/middleware/security.middleware.ts
// src/middleware/security.middleware.ts
import {
Config, Inject, Middleware } from '@midwayjs/decorator';
import {
Context, NextFunction } from '@midwayjs/koa';
import {
httpError } from '@midwayjs/core';
import {
JwtService } from '@midwayjs/jwt';
import {
UserContext } from '../common/UserContext';
import {
RedisService } from '@midwayjs/redis';
import {
Constant } from '../common/Constant';
/** * Security verification */
@Middleware()
export class SecurityMiddleware {
@Inject()
jwtUtil: JwtService;
@Inject()
cacheUtil: RedisService;
@Config('app.security')
securityConfig;
resolve() {
return async (ctx: Context, next: NextFunction) => {
if (!ctx.headers['authorization']) {
throw new httpError.UnauthorizedError(' Lack of credentials ');
}
const parts = ctx.get('authorization').trim().split(' ');
if (parts.length !== 2) {
throw new httpError.UnauthorizedError(' Invalid credentials ');
}
const [scheme, token] = parts;
if (!/^Bearer$/i.test(scheme)) {
throw new httpError.UnauthorizedError(' The lack of Bearer');
}
// verification token, The expiration will throw an exception
const jwt = await this.jwtUtil.verify(token, {
complete: true });
// jwt Stored in the user Information
const payload = jwt['payload'];
const key = Constant.TOKEM + ':' + payload.userId + ':' + token;
const ucStr = await this.cacheUtil.get(key);
// Stored in the server-side cache user Information
const uc: UserContext = JSON.parse(ucStr);
if (payload.username !== uc.username) {
throw new httpError.UnauthorizedError(' Invalid credentials ');
}
// Stored in the access context
ctx.userContext = uc;
return next();
};
}
public match(ctx: Context): boolean {
const {
path } = ctx;
const {
prefix, ignore } = this.securityConfig;
const exist = ignore.find((item) => {
return item.match(path);
});
return path.indexOf(prefix) === 0 && !exist;
}
public static getName(): string {
return 'SECURITY';
}
}
@Config('app.security')Decoration , Specify load profilesrc/config/config.**.tsThe corresponding configuration information in ;- Use
JwtServiceConduct JWT Code check ;
jwt tokenEncode the user information in token in , After decoding, the corresponding user data can be obtained , Usually , No need to store in redis in ;
But one drawback is , You can't artificially control the distribution token invalid . therefore , Sometimes people use user information in the cache ;
It's used here JWT+Redis The way , To demonstrate two approaches ;
Register middleware
// src/configuration.ts
this.app.useMiddleware([SecurityMiddleware, FormatMiddleware, ReportMiddleware]);
Add login interface
- add to DTO;
// src/api/dto/CommonDTO.ts
export class LoginDTO {
username: string;
password: string;
}
- add to VO;
// src/api/vo/CommonVO.ts
export class LoginVO {
accessToken: string;
expiresIn: number;
}
- modify
src/service/user.service.ts, Add find user interface by user name ;
import {
Provide } from '@midwayjs/decorator';
import {
User } from '../eneity/user';
import {
InjectEntityModel } from '@midwayjs/orm';
import {
Repository } from 'typeorm';
import {
BaseService } from '../common/BaseService';
@Provide()
export class UserService extends BaseService<User> {
@InjectEntityModel(User)
model: Repository<User>;
getModel(): Repository<User> {
return this.model;
}
async findByUsername(username: string): Promise<User> {
return this.model.findOne({
where: {
username } });
}
}
- add to Controller
src/controller/common.controller.ts;
// src/controller/common.controller.ts
import {
Body, Config, Controller, Inject, Post } from '@midwayjs/decorator';
import {
Context } from '@midwayjs/koa';
import {
UserService } from '../service/user.service';
import {
RedisService } from '@midwayjs/redis';
import {
LoginDTO } from '../api/dto/CommonDTO';
import {
LoginVO } from '../api/vo/CommonVO';
import {
SnowflakeIdGenerate } from '../utils/Snowflake';
import {
JwtService } from '@midwayjs/jwt';
import {
Assert } from '../common/Assert';
import {
ErrorCode } from '../common/ErrorCode';
import {
UserContext } from '../common/UserContext';
import {
Constant } from '../common/Constant';
import {
ILogger } from '@midwayjs/core';
import {
decrypt } from '../utils/PasswordEncoder';
import {
Validate } from '@midwayjs/validate';
import {
ApiResponse, ApiTags } from '@midwayjs/swagger';
@ApiTags(['common'])
@Controller('/api')
export class CommonController {
@Inject()
logger: ILogger;
@Inject()
ctx: Context;
@Inject()
userService: UserService;
@Inject()
cacheUtil: RedisService;
@Inject()
jwtUtil: JwtService;
@Inject()
idGenerate: SnowflakeIdGenerate;
@Config('jwt')
jwtConfig;
@ApiResponse({
type: LoginVO })
@Validate()
@Post('/login', {
description: ' land ' })
async login(@Body() body: LoginDTO): Promise<LoginVO> {
const user = await this.userService.findByUsername(body.username);
Assert.notNull(user, ErrorCode.UN_ERROR, ' Wrong username or password ');
const flag = decrypt(body.password, user.password);
Assert.isTrue(flag, ErrorCode.UN_ERROR, ' Wrong username or password ');
const uc: UserContext = new UserContext(user.id, user.username, user.phoneNum);
const at = await this.jwtUtil.sign({
...uc });
const key = Constant.TOKEM + ':' + user.id + ':' + at;
const expiresIn = this.jwtConfig.expiresIn;
this.cacheUtil.set(key, JSON.stringify(uc), 'EX', expiresIn);
const vo = new LoginVO();
vo.accessToken = at;
vo.expiresIn = expiresIn;
return vo;
}
}
Use Postman verification
- Call interface ( Voucher is not set );

- Use the login interface to get token;

- Call interface ( Using credentials );

copyright , Reprint please indicate the source [ Code track success ]
边栏推荐
- Overseas media, domestic we media, media publicity
- [multithreading] five communication modes between multithreads
- WordPress free theme: document, making reading more convenient
- "Problem solution" with score
- WXS syntax reference -wxs module
- Dynamic programming & backtracking various deformation problems
- Database | simple hospital patient appointment system based on opengauss
- 基于thinkphp将execle表格上传并插入数据库
- Vscode code style notes (vetur)
- Golang implements sanggi diagram and analyzes user behavior trajectory
猜你喜欢
![[MySQL] installation tutorial and master-slave configuration](/img/79/0ad3f68b69a0a03a62422d4cc70035.png)
[MySQL] installation tutorial and master-slave configuration

Crypto giants all in metauniverse, and platofarm may break through

From starfish OS' continued deflationary consumption of SFO, the value of SFO in the long run

Is gamefi in decline or in the future?
![[interview] Why do you need foreach with the for cycle?](/img/f1/3e2b933b91436849eaeb3812c41679.png)
[interview] Why do you need foreach with the for cycle?

Draw a circular radar chart with canvas
![[Game Collection] mobile phones are about to burst, and a collection of six high-quality pyGame games is coming ~ (source code attached)](/img/9e/b237bfa891bd2beb9c1b8a612e9090.png)
[Game Collection] mobile phones are about to burst, and a collection of six high-quality pyGame games is coming ~ (source code attached)

M-dao creates a one-stop Dao platform, allowing hundreds of millions of players to join Dao space

Hack the box - Introduction to networking module detailed Chinese tutorial

「题解」带分数
随机推荐
P1305 new binary tree solution
Recognition and storage of Graphs
[Google play access] payment server token acquisition
In the next bull market, can platofarm, the leading project in the Web3 world, set foot on the top of the mountain
Alibaba cloud deploys SSL certificates
Will Plato become the risk target of the meta universe? Platofarm has great opportunities
Is it safe to open an account online in Beijing
Go: Gin basicauth Middleware
Golang implements sanggi diagram and analyzes user behavior trajectory
Grpc learning notes
Several development frameworks based on openresty
[wechat applet development] (I) development environment and applet official account application
Read and understand move2earn project - move
Local warehouse associated with remote warehouse
Hack the box - File Inclusion module detailed Chinese tutorial
Svg from entry to regret, why not learn it earlier (graphic version)
【一起上水硕系列】EE feedback 详解
G1 (garbage first) collector
Assembly | screen display numbers
Limited and unlimited Games: crypto