tips:node+mysql
用户登录 在服务端可以设计一套用户登录的方法,用户可以使用这套方法来申请登录,服务端验证以后可以给用户签发一个登录凭证,下回这个用户再请求或访问应用的时候可以带着这个凭证,这样服务端就知道这个用户是谁了,用户在登录前先得注册一个账号,服务端会把用户的账号信息放在数据仓库里面保存起来,比如用户名和 hash 之后的用户密码。
创建身份验证模块 auth/auth.controller.ts auth/auth.middleware.ts auth/auth.service.ts auth/auth.router.ts
定义用户登录接口 auth.controller.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import {Request,Response,NextFunction} from 'express'; /** * 用户登录 */ export const login = async ( request:Request, response:Response, next:NextFunction )=>{ // 准备数据 const {name,password} = request.body; //做出响应 response.send({message:`欢迎回来,${name}`}); }
auth.router.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import express, { request } from 'express'; import * as authController from './auth.controller'; const router = express.Router(); /** * 用户登录 */ router.post('/login',authController.login) /** * 导出路由 */ export default router;
验证用户登录数据 auth.middleware.ts:
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 import {Request,Response,NextFunction} from 'express'; import * as userService from '../user/user.service'; /** * 验证用户登录数据 */ export const validateLoginData = async( request:Request, response:Response, next:NextFunction )=>{ console.log('验证用户登录数据'); //准备数据 const {name,password} = request.body; //验证必填数据 if(!name) return next(new Error('NAME_IS_REQUIRED')); if(!password) return next(new Error('PASSWORD_IS_REQUIRED')); //验证用户名 const user = await userService.getUserByName(name); if(!user) return next(new Error("USER_DOES_NOT_EXIST")); //下一步 next(); }
app.middleware.ts:
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 /** * 默认异常处理器 */ export const defaultErrorHandler = ( error: any, request: Request, response: Response, next: NextFunction ) => { if (error.message) { console.log(error.message); } let statusCode: number, message: string; /** * 处理异常 */ switch (error.message) { case "NAME_IS_REQUIRED": statusCode = 400; message = "请提供用户名"; break; case "PASSWORD_IS_REQUIRED": statusCode = 400; message = "请提供用户密码"; break; case "USER_ALREADY_EXIST": statusCode = 409; message = "用户名已被占用"; break; case "USER_DOES_NOT_EXIST": //设置用户不存在 statusCode = 400; message = "用户不存在"; break; default: statusCode = 500; message = "服务暂时出了点问题~"; break; } response.status(statusCode).send({ message }); };
auth.router.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import express, { request } from "express"; import * as authController from "./auth.controller"; import { validateLoginData } from "./auth.middleware"; const router = express.Router(); /** * 用户登录 */ router.post("/login", validateLoginData, authController.login); //这里使用中间件 /** * 导出路由 */ export default router;
重构按用户名查找用户 user.service.ts:
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 /** * 按用户名查找用户 */ interface GetUserOptions { password?: boolean; } export const getUserByName = async ( name: string, options: GetUserOptions = {} ) => { //准备选项 const { password } = options; //准备查询 const statement = ` SELECT id, name ${password ? ",password" : ""} FROM user WHERE name = ? `; //执行查询 const [data] = await connection.promise().query(statement, name); //提供数据 return data[0]; };
验证用户密码是否匹配 auth.middleware.ts:
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 import { Request, Response, NextFunction } from "express"; import * as userService from "../user/user.service"; import bcrypt from "bcrypt"; /** * 验证用户登录数据 */ export const validateLoginData = async ( request: Request, response: Response, next: NextFunction ) => { console.log("验证用户登录数据"); //准备数据 const { name, password } = request.body; //验证必填数据 if (!name) return next(new Error("NAME_IS_REQUIRED")); if (!password) return next(new Error("PASSWORD_IS_REQUIRED")); //验证用户名 const user = await userService.getUserByName(name, { password: true }); if (!user) return next(new Error("USER_DOES_NOT_EXIST")); //验证用户密码 const matched = await bcrypt.compare(password, user.password); if(!matched) return next(new Error('PASSWORD_DOES_NOT_MATCH')); //下一步 next(); };
app.middleware.ts:
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 /** * 默认异常处理器 */ export const defaultErrorHandler = ( error: any, request: Request, response: Response, next: NextFunction ) => { if (error.message) { console.log(error.message); } let statusCode: number, message: string; /** * 处理异常 */ switch (error.message) { case "NAME_IS_REQUIRED": statusCode = 400; message = "请提供用户名"; break; case "PASSWORD_IS_REQUIRED": statusCode = 400; message = "请提供用户密码"; break; case "USER_ALREADY_EXIST": statusCode = 409; message = "用户名已被占用"; break; case "USER_DOES_NOT_EXIST": statusCode = 400; message = "用户不存在"; break; case "PASSWORD_DOES_NOT_MATCH": statusCode = 400; message = "密码不对"; break; default: statusCode = 500; message = "服务暂时出了点问题~"; break; } response.status(statusCode).send({ message }); };