木灵鱼儿
阅读:1798
koa教程2 用户登录
登录类型
用户注册之后,自然是用户登录,登录的时候我们需要考虑到登录的方式,往往在正式的项目里面,登录的方式可能会有很多种:
- 账号密码登录
- 手机号登录
- 小程序一键登录
那么我们登录的时候就要进行判断,设置一个type的属性,用于在登录时判断用户是什么类型的登录,这个由前端那边设定参数。
type:1为账号密码登录,2为手机号登录,3为小程序一键登录
作为判断,我们可以写一个查询表(枚举),在项目根目录创建一个lib
目录,在里面创建一个enum.js
文件。
enum.js:
//通用判断是否存在该类型
function isThisType(val) {
let flag = false;
Object.keys(this).find(key => {
if (this[key] === val) {
return flag = true;
}
});
return flag;
};
//登录类型
const LoginType = {
USER_MINI_PROGRAM: 1, //小程序
USER_EMAIL: 2, //邮箱
USER_MOBILE: 3, //手机
isThisType,
};
module.exports = {
LoginType
}
这样判断起来也很简单。
const { LoginType } = require("@/lib/enum");
LoginType.isThisType(value); //true&false
这样我们在登录校验参数的时候就可以判断是不是存在对应的登录类型,如果不存在,我们就可以报错。
const { LoginType } = require("@/lib/enum");
if(!LoginType.isThisType(value)){
new ValidateError("登录类型不存在!");
}
至此登录类型就完事了。
登录校验-邮箱密码
登录的时候,一般需要账号和密码,但我们有可能只有账号,不一定需要密码,比如手机短信登录,那么密码就不一定是必填项了,所以这里也没由用required表示密码必填。
const Joi = require("joi");
const { ValidateError } = require("@/core/http-error");
const { User } = require("@/models/user");
const { LoginType } = require("@/lib/enum");
//判断登录类型是否存在
const loginTypeExist = (value, helpers) => {
if (!LoginType.isThisType(value)) {
return helpers.error(9999);
}
return value;
};
//登录账号
const loginValidate = (data, helpers) => {
const joiObject = Joi.object({
// 账号 必填
account: Joi.string().email({ minDomainSegments: 2 })
.required().error(new ValidateError("邮箱不合法!")),
// 密码 非必填-多种登录类型
password: Joi.string().min(6).max(32)
.error(new ValidateError("密码必须是1-32位!")),
// 登录类型 必填
type: Joi.number().custom(loginTypeExist, "判断类型是否存在")
.error(([errors]) => {
if (errors.code === 9999) {
return new ValidateError("登录类型不存在!");
}
return new ValidateError("登录类型错误")
})
});
return joiObject.validateAsync(data);
};
module.exports = {
loginValidate
}
在joi中,custom自定义校验里面,如果throw抛出错误,依旧会被error方法覆盖,也就是说在custom里即便你抛出错误,最终用的也是error里面的,所以我们需要做个判断。
通过helpers.error(9999)
我们自定义一个错误code,它本身会根据传入的值创建一个joi错误对象,我们在error中可以接收到这个错误对象,然后判断,如果code值为9999说明type类型不存在,我们new出一个
"登录类型不存在!"的错误对象。
简单校验通过后,我们就需要进行登录。
登录-邮箱密码
//登录
router.post("/login", async (ctx) => {
const { account, password, type } =
await loginValidate(ctx.request.body);
//根据登录类型进行登录
switch (type) {
case LoginType.USER_EMAIL:
// 邮箱+密码
break;
case LoginType.USER_MINI_PROGRAM:
// 小程序
break;
case LoginType.USER_MOBILE:
// 手机
break;
default:
throw new NotFound("没有相应的处理函数!")
}
//成功
// throw new Success("登录成功!");
});
这么我们针对不同的登录类型都有对应的方法,当然我们也要考虑到,有时候登录类型存在,但是我们没有写对应的登录处理方法,所以要在switch中加default,然后抛出一个错误用于提示。
那么我们怎么处理邮箱密码登录呢?
我们有几点需要处理:
- 邮箱是否存在
- 密码是否正确
- 以上都正确,我们需要返回token
邮箱密码的校验,我们需要访问数据库,所以邮箱和密码的校验我们写在user模型里面。
const bcrypt = require("bcryptjs");
const { Sequelize, Model, DataTypes } = require("sequelize");
const { AuthFailed } = require("@core/http-error");
class User extends Model {
static async verifyEmailPassword(email, password) {
//查找对应email用户
const user = await User.findOne({
where: { email }
});
if (!user) throw new AuthFailed("账号不存在!");
//判断密码是否正确
const correct = bcrypt.compareSync(password, user.password);
if (!correct) throw new AuthFailed("密码不正确!");
//存在
return user;
}
};
由于我们之前注册时,密码已经加密了,所以我们需要通过bcrypt.compareSync方法进行比较,它有两个参数,登录时用户的密码和数据库里面的加密后的密码。
最后会返回布尔值,如果false则表示密码不正确。
如果账号和密码都严重通过了,我们就将user返回出去,因为我们还需要创建token,还要用到用户的信息。
创建token
在core目录我们创建一个token.js
文件。
token.js:
const jwt = require("jsonwebtoken");
const { tokenConfig } = require("@config/config");
//创建token
const createToken = function (uid, scope) {
console.log(uid, scope)
return jwt.sign({ uid, scope }, tokenConfig.key, {
expiresIn: tokenConfig.expiresIn
});
};
module.exports = {
createToken
}
这里jwt有三个参数,第一个是一个对象,用于我们在token中存入的信息,这里我们存放了一个uid,一个scope,uid其实就是用户的自增的id,scope则是用户的权限级别,这个待会再说。
第二个参数是加密用的key,这个key一般都是随机生成的
第三个参数是一些其他设置,这里我们使用的是过期时间,jwt的过期时间有几种写法:
- 纯数字 单位默认为s
200
200秒 - 字符:
"2d"
2天 - 字符:
"2h"
2小时 - 字符:
"2"
2ms
jwt的key和其他数据都是经常需要用到的,我们将它存在config文件中。
config.js:
module.exports = {
//dev、prod
env: "dev",
//数据库配置
database: {
dbName: "koa-test", //数据库名
host: "localhost", //数据库地址
port: 3306, //数据库端口
user: "root", //数据库用户名
password: "123456", //数据库密码
},
//token配置
tokenConfig: {
key: "askdhjasgdhjasghgu&^%^^%&**2164.as21s8", //加密用的key
//token过期时间,数字为s,字符则需要加上d(天),h(小时),否则默认为ms
expiresIn: "2h",
}
};
这样我们邮箱密码也校验了,token创建方法也有了,我们可以写邮箱密码的登录方法了。
const { User } = require("@models/user");
const { createToken } = require("@core/token");
//邮箱+密码登录
async function emailLogin(account, password) {
const user =
await User.verifyEmailPassword(account, password);
//生成token
return createToken(user.id, 8);
};
这里我们scope传入了一个数字8,也就是他的权限。权限一般建议是有间隔的。
比如:
- 普通用户 8
- 管理员 16
- 站长 32
这样,如果我们在普通用户增加一个vip用户,权限的调整范围就有盈余了,设置为9,10都行。
//登录
router.post("/login", async (ctx) => {
const { account, password, type } =
await loginValidate(ctx.request.body);
//根据登录类型进行登录
switch (type) {
case LoginType.USER_EMAIL:
// 邮箱+密码
const token = await emailLogin(account, password);
ctx.body = { token }
break;
case LoginType.USER_MINI_PROGRAM:
// 小程序
break;
case LoginType.USER_MOBILE:
// 手机
break;
default:
throw new NotFound("没有相应的处理函数!")
}
//成功
// throw new Success("登录成功!");
});
//邮箱+密码登录
async function emailLogin(account, password) {
const user =
await User.verifyEmailPassword(account, password);
//生成token
return createToken(user.id, 8);
};
这样一个简单的登录就有了,我们直接设置的body,当然,按照以往的方式,我们这里就应该new出一个成功的错误对象。
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。
相关推荐
centos 安装最新版 node.js
[hide]先用yum 安装一次node先升级yum update 提示下载程序,回复y安装nodeyum install nodejsyum安装的node一般都不是最新的,所以我们还需要升级node的版本npm i n -g全局安装一个n插件n lts表示安装最新的稳定版!一些常用命令n ls查看已安装的node版本n rm 16.0.3删除16.0.3版本更多功能阅读插件文档:n等待安装完毕后,此时其实版本已经安装好了,但是输入node -v还是低版本,是因为centos的用户缓存问题。我们退出登录再登录就会刷新缓存了,此时的node -v输出的就是最新版本exit 退...
node npm yarn 如何同时运行多个指令
node的bash命令其实是有对应的指令字符的,但是,这个指令只能再linux,mac上才有生效,再windows是无效的,所以了解一下就行。命令说明&&顺序执行多条命令,当碰到执行出错的命令后将不执行后面的命令&并行执行多条命令||顺序执行多条命令,当碰到执行正确的命令后将不执行后面的命令|管道符windows上进行多命令"scripts": { "dev": "cross-env NODE_ENV=development webpack --env development --progress -...
koa教程2 HttpBearerAuth 传递token
前端发送token到后端,一般有三种方式:链接中携带token,query参数post这种请求body中携带token头信息携带token但是事实上http已经为我们提供了传token的方式,是一个相对来说比较安全的方式,就是HttpBearerAuth 其实他也是一个头信息来着,只是相对来说多了一点操作,在apipost软件中,我们可以直接可视化设置如果是axios,则是需要添加一个头信息:axios({ method: 'get', url: url, responseType: 'blob', headers: { 'Authoriz...

koa教程2 微信openid登录
微信的openid,前端登录时,会发送一个code码到后端,后端接收到这个code,然后配合appid、appsecret参数,像wx发送一个get请求。wx的请求地址:GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code具体查看文档:微信官方文档-服务端可以看到这段get请求有四个参数:属性类型默认值必填说明appidstring 是小程序 appIdsecretstring 是...
koa教程2 权限分级控制
在之前的代码中,我们使用了一个scope属性来表示用户的权限,但是scope是一个数字,他的阅读性是非常差的,当其他人开发的时候,可能并不知道你这个数字是什么意思?所以,我们需要将它转义成文本。为了方便判断,我们在enum.js中增加一个用户等级的对象enum.js://通用判断是否存在该类型 function isThisType(val) { let flag = false; Object.keys(this).find(key => { if (this[key] === val) { return flag = true; } })...
koa教程2 token鉴权
之前我们在token中传入我们的自定义参数,现在我们要做一个token鉴权,很简单,如果他的token合法,就可以访问这个路由,如果不合法,就打回。这个也不能说是真正意义上的鉴权,因为他还没有判断scope值,所以只能说是简单判断。做这个判断我们就可以通过中间件的形式,于是我们在middlewares目录下创建一个auth.js文件auth.js:const parseBearerToken = require("@utils/paresBearerToken"); const jwt = require("jsonwebtoken"); cons...
node 自定义路径别名
用过vue cli的话,对路径中的@应该不陌生,他表示根目录,但是在node的环境里面,我们编写模块并引入时,并没有这种方便的写法。在node环境中,我们可以通过process.cwd()来表示根目录,但是这样的话,每次使用绝对路径引入,路径总是需要写一大堆拼接。const db = require(`${process.cwd()}/config/config`).database;这样略显麻烦,于是我们可以在全局写一个引入插件的方法:global.myRequire = function (path) { return require(`${process.cwd()}/${pa...
koa教程2 密码加密
默认情况下,我们通过User.create({ email, password, nickname });模型传入的数据,是无加密的,也就是说,在数据库中密码是明文显示的,这样肯定是不行,我们需要使用bcrypt插件进行加密yarn add bcryptjs --dev打开models/user.jsuser.js:const bcrypt = require("bcryptjs"); const { sequelize } = require(`${process.cwd()}/core/db`); const { Sequelize, Model, DataTy...

koa教程2 使用sequelize连接数据库,创建用户模型
数据库的连接处理,我们需要使用sequelize插件。这个插件还有对应的数据库驱动,如果是使用mysql,那么驱动是mysql2,具体可以查看中文版的入门教程:入门yarn add sequelize mysql2 --dev安装完成后我们先需要创建数据库连接。连接数据库在根目录/core目录**下创建一个db.js文件用于连接数据库。在连接数据库之前,我们需要一些数据库的参数,如账号,密码,端口,数据库名字,数据库地址,为了方便管理配置,我们在根目录创建一个config目录,里面存放一config.js文件 ,这个之前的教程我们就已经创建好了。config.js:module.expo...
koa教程2 用户注册及Joi校验、成功信息返回
用户注册用户数据表搭建完毕后,我们肯定是需要注册用户的,那么首先我们需要创建一个路由api了。在根目录:/app/router/v1目录下创建一个user.js文件。user.js:const Router = require("koa-router"); const router = new Router({ prefix: "/v1/user" }); const { User } = require(`${process.cwd()}/models/user`); //注册用户 router.post("/register&q...
