笔记12前后端常用的鉴权方式

前后端常用的鉴权方式



四种鉴权方式


1、Http Basic Authentication
2、session-cookie
3、Token + Jwt
4、OAuth(开放授权)



Http Basic Authentication


介绍:这种授权指浏览器遵守http协议实现的基本授权方式,http协议在通信的过程中,定义了基本认证来允许http服务器对客户端进行鉴权
过程:
1、客户端向服务器请求数据,请求的内容可能是一个网页或者一个异步ajax请求,此时客户端若没有被验证,则客户端提供给服务器:
Get /index.html HTTP/1.0
Host: www.google.com
2、服务器会向客户端发送验证请求的代码401,例如:
HTTP/1.0 401 Unauthorised
Server: SokEvo/1.0
WWW-Authenticate: Basic realm=”google.com” (关键信息)
content-Type: text/html
Content-Length: xxx
3、当符合http1.0或http1.1规范的客户端(如IE,Firefox)收到401未授权时,会自动弹出一个登陆窗口,要求用户输入用户名、密码
4、用户输入用户名和密码后,将用户名和密码通过Base64加密,并将密文放入前一条请求信息中,则客户端发送的第一条信息变为:
Authorization: Basic 密文~~~
5、服务器收到以上信息,将Authorization字段后的用户信息取出,解密,再通过与数据库中用户名密码进行比较,从而进行鉴权。


优点:基本认证支持所有的网页浏览器;基本认证很少在可公开访问的互联网网站上使用,有时会在小的私有系统中使用;容易实现。
缺点:如果没有使用ssl/tls传输层安全协议,以明文传输的口令和密钥很容易被拦截,该方案也同样没有对服务器返回的信息提供保护。
现存的浏览器保存认证信息直到标签页或浏览器被关闭,或者用户清除历史记录,Http没有为服务器提供一种方案去知识客户端丢弃被缓存的密钥,这导致服务器在用户不关闭浏览器的情况下,没有一种有效的方法去注销用户。




session-cookie



cookie:HTTP是一个无状态协议,服务器不知道哪一台浏览器访问了它,所以需要一个标识来让服务器区分不同的client,cookie就是这个管理服务器和客户端之间状态的标识。

cookie原理是:浏览器第一个向服务器发送请求,服务器在response头部设置Set-Cookie字段,浏览器收到响应就会社会cookie并且存储。在下一次浏览器向服务器发送请求的时候,就会在请求头request头部自动带上Cookie字段,服务器收到该cookie就可以区分不同的浏览器。这个cookie与某个用户的对应关系就会存储在服务器端,这时候就要用到session。

session:session是会话的意思,浏览器第一次访问服务器,服务器会创建一次会话,在会话中保存标识该浏览器的信息,它与cookie的区别是session是缓存在服务器端的,cookie是缓存在浏览器端,他们都由服务器端生成,用与弥补http无状态的缺陷。


cookie-session用户登录认证



使用session-cookie登录认证,登录时存储session,退出登录时删除session,所有需要登录后才能操作的接口会提前验证是否存在session,存在才能进行路由跳转,不存在则回到登录页面。


前端代码
async login(){
await axios.post(‘/login’,{
username: this.username,
password: this.password
})
},
async logout(){
await axios.post(‘/logout’)
},
async getUser(){
await axios.get(‘/getUser’)
}

后端代码

//koa中引入中间件auth.js
module.exports = aysnc (ctx,next)=>{
if(!ctx.session.userinfo){
ctx.body={ok:0,message:’用户未登录’};
else{
await next()
}
}
};

//登录接口
router.post(‘/login’,async(ctx)=>{
const {body} = ctx.request
ctx.session.userinfo = body.username //设置session
ctx.body={ message:’login success’ }
})

//登出
router.post(‘/logout’,async(ctx)=>{
delete ctx.session.userinfo
ctx.body = { message:’logout success’ }
})

//需要验证的接口
router.get(‘/getUser’,require(‘auth’),async(ctx)=>{
ctx.body={
message:’获取用户列表成功’,
userinfo:ctx.session.userinfo
}
})




Token


token是一个令牌,浏览器第一次访问服务器的时候会签发一张令牌,之后浏览器每次携带者张令牌访问服务器就会认证这个令牌是否有效,只要服务器端可以解密这个令牌,说明请求是合法的,令牌中包含的用户信息还可以区分不同身份的用户,一般token由用户信息、时间戳和hash算法加密的签名构成


认证流程:
1、客户端使用用户名和密码登陆
2、服务端收到请求,去验证用户名和密码
3、验证成功,服务器端会签发一个token,并发送给客户端
4、客户端收到token可以把它存储起来,例如放在cookie或者webStorage中
5、客户端每次向服务器端请求都需要带上服务器端签发的token
6、服务器受到其你去,去验证客户端请求里面带的token(前端做法是axios请求拦截:request头部添加authorization)如果验证成功则向客户端返回请求的数据,反之则返回401鉴权失败。




token和cookie-session区别
cookie-session缺点
(1)cookie-session认证方式局限于浏览器中使用;cookie无法在app端使用;
(2)为了满足全局一致性,我们最好把session存储在redis中做持久化,而在分布式的环境中,我们需要每个服务器上备份,占用大量存储空间
(3)cookie需要在https下使用,防止CSRF攻击

token缺点:
(1)加密解密是使得token认证比session-cookie更加消耗性能
(2)token比sessionId大,更占带宽

前端代码

  //axios请求拦截器,在每个request请求头上加上认证信息
  axios.interceptors.request.use(
    config =>{
       const token = window.localStorage.getItem('token')
       if(token){
          //判断本地缓存中是否存在token
          config.headers.common["Authorization"]="Bearer" + token;
       }
       return config
    },
    err=>{return Promise.reject(err)}
  )

  //登陆函数--将后端返回的jwt存入localStorage
  async login(){
    const res = await axios.post('/login',{
    username:this.username,
    password:this.password
    })
    localStorage.setItem('toekn',res.data.token)
  }

  //登出函数
  async logout(){
    localStorage.removeItem('token')
  }

  //获取登陆用户列表,需对token的有效性进行判定 
  async getUser(){ 
    await axios.get('/getUser-token')
  }

后端代码
//引入koa模块
const jwt = require(‘jsonwebtoken’)
cont jwtAuth = require(‘koa-jwt’)
//用来签名的密钥
const secret = ‘it is a secret’
//需要权限的接口,jwtAuth是koa自带的鉴权中间件,它用密钥secret来解析jwt是否合法
router.get(‘/getUser-token’,jwtAuth({secret}),async ctx=>{
ctx.body={
message:’获取用户数据成功’,
userinfo:ctx.state.user.data
}
})
//用户登录
router.post(‘/login-token’,async ctx=>{
const {body} = ctx.requset
const userinfo = body.username
//此处进行登陆校验,即查找数据库(略),若用户和密码合法,进行下列生成jwt令牌操作
ctx.body={
message: ‘login success’,
user: userinfo,
token: jwt.sign({ //签发token
data: userinfo, //token由:用户信息、时间戳、密钥结合hash加密构成
exp: Math.floor(Data.now()/1000)+ 60*60
},
secret
)
}
})



Oauth开放授权


OAuth (Open Authorization)是一个开放标准。数据的所有者告诉系统,同意授权的第三方应用进入系统,获取数据。系统从而产生一个短期的令牌token来代替密码,供第三方应用使用。

OAuth授权,第三方应用申请令牌之前,都必须拿到系统备案,说明自己的身份,然后会拿到两个身份识别码:client ID 和client secret;
在前后分离的情景下,我们常使用授权码方式,指第三方应用先申请一个授权码,然后用该码获取令牌

获取GitHub第三方登陆权限

1、在GitHub中备案第三方应用,拿到它的客户端id和客户端密钥;
2、封装一个config = { client_id ‘~’, client_secret: ‘~’ }
3、在ajax请求后配置对应参数,让用户重定向到授权服务器
4、用户跳转到GitHub,输入用户名和密码,此时授权码code会携带用户身份跳回第三方网站
5、第三方收到授权码,可以拿授权码、clientId、clientSecret向GitHub换取access_token
6、GitHub收到请求,向第三方网站颁发令牌,第三方应用具备短时间的权限