首先看完整的目录结构
image.png
主要实现的功能是通过账号密码登录获取token,再通过token来获取用户信息,一共两个接口:登陆接口和获取用户信息接口。
上一篇文章已经写到了如何写一个最简单的获取mysql用户信息的接口,现在直接在上一篇文章的基础上做token验证登陆。

mysql数据库准备好数据
image.png

1、安装jwt依赖和解决跨域、白名单egg-cors

  1. $ npm i egg-jwt --save
  2. $ npm i egg-cors --save

2、config/config.default.js

  1. module.exports = {
  2. // 配置需要的中间件,数组顺序即为中间件的加载顺序
  3. // middleware: [ 'jwt' ],
  4. keys: '123456790',
  5. mysql: {
  6. // 单数据库信息配置
  7. client: {
  8. // host
  9. host: '38.130.21.169',
  10. // 端口号
  11. port: '3306',
  12. // 用户名
  13. user: 'root',
  14. // 密码
  15. password: 'yourpassword',
  16. // 数据库名
  17. database: 'database',
  18. },
  19. // 是否加载到 app 上,默认开启
  20. app: true,
  21. // 是否加载到 agent 上,默认关闭
  22. agent: false,
  23. },
  24. jwt: {
  25. secret: "123456"
  26. },
  27. security: {
  28. csrf: {
  29. enable: false,
  30. ignoreJSON: true
  31. },
  32. domainWhiteList: ['http://localhost:7001'],//允许访问接口的白名单
  33. },
  34. cors: {
  35. origin:'*', // 解决跨域问题
  36. allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'
  37. },
  38. cluster: {
  39. listen: {
  40. port: 7001, // 监听端口
  41. // hostname: '127.0.0.1', // 不建议设置 hostname 为 '0.0.0.0',它将允许来自外部网络和来源的连接,请在知晓风险的情况下使用
  42. // path: '/var/run/egg.sock',
  43. }
  44. }
  45. };

3、config/plugin.js

  1. module.exports = {
  2. mysql: {
  3. enable: true,
  4. package: 'egg-mysql',
  5. },
  6. jwt: {
  7. enable: true,
  8. package: 'egg-jwt',
  9. },
  10. cors: {
  11. enable: true,
  12. package: 'egg-cors',
  13. },
  14. };

4、app/router.js 定义登陆路由

  1. module.exports = app => {
  2. const { router, controller, middleware} = app;
  3. const jwtErr = middleware.jwtErr(app.config.jwt)
  4. router.get('/api/getUser', jwtErr, controller.user.getUser);
  5. router.post('/api/login', controller.login.login);
  6. };

在获取用户信息接口上使用中间件

5、middleware/jwtErr.js 定义一个jwt中间件 访问路由的时候会通过这个中间件来处理

  1. module.exports = (options, app) => {
  2. return async function jwtErr(ctx, next) {
  3. const token = ctx.request.header.token;
  4. if(token){
  5. try {
  6. ctx.app.jwt.verify(token, options.secret); // 验证token
  7. await next();
  8. } catch (error) {
  9. ctx.status = 401;
  10. ctx.body = {
  11. massage: 'token已过期,请重新登录',
  12. code: -1,
  13. }
  14. return;
  15. }
  16. } else {
  17. ctx.status = 401;
  18. ctx.body = {
  19. message: 'token不存在',
  20. };
  21. return;
  22. }
  23. }
  24. }

接口先去header判断是否存在token,存在就验证,不存在就返回信息。

6、controller/login.js 登陆控制器

  1. const Controller = require('egg').Controller;
  2. class LoginController extends Controller {
  3. async login() {
  4. const { ctx, app } = this;
  5. const { userName, password } = ctx.request.body;
  6. const { result } = await ctx.service.login.login(userName, password);
  7. if(result.length>0){
  8. const token = app.jwt.sign({
  9. 'userName': userName, //需要存储的 token 数据
  10. }, app.config.jwt.secret, { expiresIn: '2m' }); // 2分钟token过期
  11. ctx.set({'token':token})//设置headers
  12. ctx.body = {
  13. code: '200',
  14. data: [{
  15. token: token,
  16. userName: result[0].userName,
  17. userId: result[0].userId
  18. }],
  19. message: 'success'
  20. };
  21. }else{
  22. ctx.body = {
  23. code: '401',
  24. data: result,
  25. message: '账号或密码错误'
  26. };
  27. }
  28. }
  29. }
  30. module.exports = LoginController;

将用户名信息存储在token数据中,并且设置2分钟token过期。当token和用户名密码验证成功,返回token和用户信息。

7、service/login.js

  1. const Service = require('egg').Service;
  2. const crypto = require('crypto');
  3. class LoginService extends Service {
  4. getMd5Data(data) {
  5. return crypto.createHash('md5').update(data).digest('hex');
  6. }
  7. async login(username,password) {
  8. const psd = this.getMd5Data(password)
  9. const data = await this.app.mysql.query(`SELECT * FROM user WHERE userName='${username}' and password='${psd}'`);
  10. const result = JSON.parse( JSON.stringify(data)); // 去除node中mysql查询数据产生的RowDataPacket
  11. return { result };
  12. }
  13. }
  14. module.exports = LoginService;

md5加密后查询匹配数据库密码。

验证

postman调用 post请求 填写用户名和密码获取token
image.png
通过拿到的token放入header请求用户信息
image.png
token不存在的情况
image.png

token过期的情况
image.png

账号密码错误的情况
image.png