OAuth2.0受权详解

学习oauth认证以前先回顾一下经过sessionid的会话过程html

关于session与cookie的请戳:http://www.javashuo.com/article/p-ttnbgalf-gy.html前端

那么这种利用session的会话方式会引起哪些问题呢node

1.安全问题ios

常见保存会话方式:cookie,session以及token等等,这里咱们将这三种方式的安全性能都简单的分析一下嘿嘿~git

cookie:咱们了解cookie的安全问题首先从客户端颁发cookie开始,而后经过set-cookie响应给客户端,客户端保存以后下次通讯会以默认的方式携带cookie,这种东西是程序员不可控的,这时候会发生一个什么问题,当网页中的一段link代码发生XSS攻击时,会获取到本程序员

地cookie。那么问题来了。为啥?由于cookie默认写到http的headers里,无法控制。那么好,咱们退出登陆,这时候服务器对cookie怎么操做的,经过set-cookie的方式清空cookie并返回到客户端。这样致使一个问题,已经被劫持了的cookie还能用,这就是为啥cookie不github

安全的缘由。web

session:首先咱们要知道,session究竟是个啥,个人理解是session就是cookie的另外一种形式,一样session是服务器颁发给客户端的,一样经过响应中的set-cookie,可是与此同时服务器还会保存这个session id,本质上都是经过cookie传递,本质上均可以被上诉攻击方式攻击,可是好处在哪,当退出登陆的时候会服务器对session id会有个删除操做。这样被劫持的session id其实就没用了,可是无论怎样,承担的风险方式与cookie是同样的。数据库

token:session与cookie都存在风险,那么更好的解决方案是什么呢,就是token,放在后面说。express

2.服务器压力过大

session的特色之一就是存在服务器端,请求过多的时候session也会增多,这就会致使服务器的压力过大。

3.分布式session管理困难

如今几乎全部的web应用程序都会采用分布式的处理方案,那么每次一块儿请求不必定发送到哪一个服务器,好比此次请求发送的Server A上而且保存了session,下一个请求我发Server B上了,Server B没有啊,怎么校验,这就会引起另外一个问题,分布式下如何共享session。固然如今有好多的方式好比:Session Replication方式(session复制),缓存集中方式管理(将Session集中放在一个服务器上,咱们也能够称其session服务器),基于Redis进行session共享等等,很明显服务器压力很大,并且并很差管理。

4.跨域问题 

首先啥叫跨域?域名不一样,协议不一样,或者端口号不一样统统称为跨域,跨域产生于浏览器的同源策略,请求发出去了,可是响应被拦截了。携带headers里面的cookie是不能够跨域的,可是authorization能够啊,token存在哪?token就存在authorization里啊,emmmm~好处显而易见。

说了这么多session的缺点,时代老是向前发展的,技术也同样呀,因而乎token诞生了~

什么是token

token能够理解成一个带有User基本信息的令牌,例如每一次会话调用服务器的API时,服务器能够经过token判断是否有权限。

token流程

 

token种类

id token(不知道干啥用的,没用过,见过存session id的)

access token(用来作权限认证,生命周期相对比较短)

refresh token(用来生成新的access token,生命周期相对比较长)

token特色有哪些

1.安全性能更好

以前列举了cookie和session的安全性能问题,那么token为啥就安全了?首先token是程序员本身写入http headers里的,并非像cookie同样自动写入http的headers里的,若是不必的咱们不写入,XSS攻击方式是获取不到token的。

2.无状态(多个服务共享,减轻服务器的鸭梨)

token是无状态的,也就是说token并不存入服务器中(若是想存,请便)当服务器认证事后,会生成一个token返回给用户,而且存入浏览器缓存里(localstorage等),接下来的请求会咱们会获取这个token并放入authorization内,服务器接收到请求,并解析token来判断当前请求是否有权限调用api,这里引出另外一个概念鉴权。

3.跨程序调用(避开同源策略)

当token变成无状态,只要一个token,就能够在任何一个服务器上认证(解析方式必须一致,其实都是代码层面的东西)因而咱们能够采用一种设计方式叫,分离认证服务与业务任务。当咱们能够经过认证服务器来获取token,而后发送给业务服务器的时候校验token,这时会出现两种方式,第一种是在业务服务器校验token,另外一种是毎一次请求经过中间层再发送给认证服务器进行校验,两种设计方式各有优缺点,无论怎样都是实现了跨程序共享token,咦没有跨域问题哦(固然须要服务器配合嘤嘤嘤~)到这里就引出另外一个概念,OAuth认证。

什么是OAuth认证

OAuth是一个关于受权(authorization)的开放网络标准,目前的版本是2.0版,即OAuth2.0

OAuth的应用场景

一个公司每每会有不少系统,好比HR系统,你的请假吧,好比公司的内部员工网站,得有业余活动吧,再好比公司好多产品,可是会有个产品是能够登陆全部网站的吧,总不能好多产品分红好多认证系统吧,能用就一个会节约多少人力物力呢~这里会引出一个概念SSO(单点登陆)SSO实际上是一种解决方案,俺们公司的叫AOS系统。这个经过一个系统登陆定向到各个产品的受权过程就是OAuth认证。

OAuth认证设计方式(这里列两种,高大上的我也不知道):

业务服务器校验token

优势:相对于第二种不用每一次请求都要经过鉴权服务器,能够保证token的新鲜度。

缺点:效率低。

认证服务器校验token

优势:效率高

缺点:若是是个第三方的鉴权服务token信息更新不及时

整个鉴权过程都是经过access token,因为有效时间比较短,若是我想要半个月登陆一次呢,也就说半个月以内不须要从新登陆,怎么办refresh token的做用就产生了。

refresh token作了些什么事儿呢

经过获取access token的有效时间,判断当access token立刻过时的时候,这时候我能够经过refresh token从权限服务器获取新的access token,这均可以偷摸的作了,反正使用者不会知道。

1.客户端发送refresh token请求

2.服务器发送refresh token

token的实现方式

现有的token解析方式其实并不惟一,可是有个很出名的那就是jwt(json web token)

什么是jwt

能够理解jwt是token的一种规则

jwt的组成

1.Header 2.Payload 3.Signature

jwt的特色(来自阮一峰)

JWT 默认是不加密,但也是能够加密的。生成原始 Token 之后,能够用密钥再加密一次。

JWT 不加密的状况下,不能将秘密数据写入 JWT。

JWT 不只能够用于认证,也能够用于交换信息。有效使用 JWT,能够下降服务器查询数据库的次数。

JWT 的最大缺点是,因为服务器不保存 session 状态,所以没法在使用过程当中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期以前就会始终有效,除非服务器部署额外的逻辑。

JWT 自己包含了认证信息,一旦泄露,任何人均可以得到该令牌的全部权限。为了减小盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

为了减小盗用,JWT 不该该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

栗子(github登陆本地站点)

技术栈:nodejs

获取github的token过程

1.注册github应用

找到settings

 

找到OAuths Apps

注册成功

2.获取github受权码

这里咱们须要将注册过得client id跟回调函数当作参数传入

    handleGitHubLogin() {
        let path = `https://github.com/login/oauth/authorize?response_type=code&redirect_uri=${CommonUtil.Config.github.redirect_uri}&scope=user%2Crepo&client_id=${CommonUtil.Config.github.client_id}`;
        location.href = path;
    }

这时候会跳到github的受权页面

受权成功后会返回一个code(受权码)

经过code clientId clientSecret获取accessToken

router.post("/oAuthValidate", (req, res) => {
  let { clientId, clientSecret, code } = req.body;
  axios({
    method: "post",
    url:
      "https://github.com/login/oauth/access_token?" +
      `client_id=${clientId}&` +
      `client_secret=${clientSecret}&` +
      `code=${code}`,
    headers: {
      accept: "application/json"
    }
  })
    .then(tokenResponse => {
      let accessToken = tokenResponse.data.access_token;
      getGitHubToken(accessToken, res);
    })
    .catch(e => {
      console.log(e);
    });
});

因为整个应用程序采用SAP,因此整个流程经过前台获取最合理,但前台获取token必然会出现一个问题就是跨域,那么如何解决前端跨域资源共享问题呢,这里提供一个解决方案就是Gatekeeper,github本身去找吧,使用方式以后补上。

经过accessToken获取User信息

function getGitHubToken(accessToken, res) {
  axios({
    method: "get",
    url: `https://api.github.com/user`,
    headers: {
      accept: "application/json",
      Authorization: `token ${accessToken}`
    }
  })
    .then(result => {
      let token = jwt.sign(result.data, "my_token", { expiresIn: "1h" });
      util.responseClient(res, 200, 0, "获取github token成功", {
        profileInfo: result.data,
        accessToken: token
      });
    })
    .catch(e => {
      util.responseClient(res, 500, 0, "get github token failed.", {
        message: e
      });
    });
}

这里为了使用jwt,我并无使用github的accessToken,而是在本身的应用程序里使用了jwt,能够自行选择。

返回给浏览器而且保存到缓存里

再次请求的时候进行token鉴权

app.use(
  expressjwt({
    secret: "my_token",
    credentialsRequired: true, //若是false  则authoriaztion为空时也经过。
    getToken: function fromHeaderOrQuerystring(req) {
      if (
        req.headers.authorization &&
        req.headers.authorization.split(" ")[0] === "Bearer"
      ) {
        var token = req.headers.authorization.split(" ")[1];
        return token;
      } else if (req.query && req.query.token) {
        return req.query.token;
      }
      return null;
    }
  }).unless({
    path: util.whiteList
  })
);

function checkPromisition(req, res, next) {
  if (1) {
    return next();
  } else {
    util.responseClient(res, 500, 0, "delete github token failed.", {
      log: "delete github token failed with http code 401."
    });
  }
}

app.use(function (err, req, res, next) {
  if (err.name === "UnauthorizedError") {
    util.responseClient(res, 403, 0, "invalid token...", {});
  }
});

app.use("/leavemessage",checkPromisition,require("./leavemessage"));

jwt使用方式

引入jwt中间件

const jwt = require("jsonwebtoken");

jwt生成

let token = jwt.sign(result.data, "my_token", { expiresIn: "1h" });

鉴权部分

引入中间件

const expressjwt = require("express-jwt");

具体细节看上面代码吧

这里有些问题首先github并无给我refresh token,这里是我没找到吗,请知道的大佬指点一二,其次github没有暴露鉴权的接口吗

撤销github的accesstoken方式

1.清缓存

2.手动本身上去清吧

时间不早了,先写到这里吧,若是哪里理解错的欢迎指正,我会很感激涕零的。

你的关注是对我最大的支持~蟹蟹~

相关文章
相关标签/搜索