亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

聊聊鑒權(quán)那些事(推薦)

 更新時間:2019年08月22日 09:47:46   作者:Aaron  
這篇文章主要介紹了聊聊鑒權(quán)那些事(推薦),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

在系統(tǒng)級項目開發(fā)時常常會遇到一個問題就是鑒權(quán),身為一個前端來說可能我們距離鑒權(quán)可能比較遠(yuǎn),一般來說我們也只是去應(yīng)用,并沒有對權(quán)限這一部分進行深入的理解。

什么是鑒權(quán)

鑒權(quán):是指驗證用戶是否擁有訪問系統(tǒng)的權(quán)利。傳統(tǒng)的鑒權(quán)是通過密碼來驗證的。這種方式的前提是,每個獲得密碼的用戶都已經(jīng)被授權(quán)。在建立用戶時,就為此用戶分配一個密碼,用戶的密碼可以由管理員指定,也可以由用戶自行申請。這種方式的弱點十分明顯:一旦密碼被偷或用戶遺失密碼,情況就會十分麻煩,需要管理員對用戶密碼進行重新修改,而修改密碼之前還要人工驗證用戶的合法身份。 -- 節(jié)選自百度百科

上述簡單扼要的說明了一下鑒權(quán)的概念,但是這也只是簡單的鑒權(quán),也是項目中最最常見的及安全形式了,但是對于后端鑒權(quán)又是如何去做的,我們?nèi)允且粺o所知,一般來說對于后端來說,鑒權(quán)最長見的方式分為三種:

  • Session/Cookie
  • Token或Jwt
  • OAuth

這種授權(quán)方式是瀏覽器遵守http協(xié)議實現(xiàn)的基本授權(quán)方式,HTTP協(xié)議進行通信的過程中,HTTP協(xié)議定義了基本認(rèn)證認(rèn)證允許HTTP服務(wù)器對客戶端進行用戶身份證的方法。接下來就一一介紹一下這三種鑒權(quán)方式。

Session/Cookie

Cookie是一個非常具體的東西,指的就是瀏覽器里面能永久存儲的一種數(shù)據(jù),僅僅是瀏覽器實現(xiàn)的一種數(shù)據(jù)存儲功能。Cookie由服務(wù)器生成,發(fā)送給瀏覽器,瀏覽器把CookieKV形式保存到某個目錄下的文本文件內(nèi),下一次請求同一網(wǎng)站時會把該Cookie發(fā)送給服務(wù)器。由于Cookie是存在客戶端上的,所以瀏覽器加入了一些限制確保Cookie不會被惡意使用,同時不會占據(jù)太多磁盤空間,所以每個域的Cookie數(shù)量是有限的。

Cookie.js

const Http = require("http");
const app = Http.createServer((req,res) => {
 if(req.url === "/favicon.ico"){
  return;
 }else{
  res.setHeader("Set-Cookie","cx=Segmentfault");
  res.end("hello cookie");
 };
});
app.listen(3000);

使用node Cookie.js運行上面代碼,等程序啟動后訪問http://localhost:3000/,就可以看到hello cookie字樣,這樣的話就代表該服務(wù)已經(jīng)啟動了。若想查看到到我們所設(shè)置的Cookie,首先觀察一下在NetworkResponse Headers中,可以看到我們所寫的Set-Cookie屬性,當(dāng)我們訪問http://localhost:3000/的時候,當(dāng)瀏覽器接收到Set-Cookie這個屬性的時候,瀏覽器會根據(jù)其內(nèi)部約定,并在其瀏覽器內(nèi)部對其cookie進行存儲,打開瀏覽器控制臺,在Application中找到Cookies中找到相對應(yīng)的域名,就可以看到我們所設(shè)置的cookie值了。當(dāng)在同域的情況下,當(dāng)再次請求數(shù)據(jù)的時候瀏覽器會默認(rèn)發(fā)送cookie在該請求中,一起發(fā)送給后端。為了證實上面的說法,刷新一下http://localhost:3000/頁面,在控制臺Network找到Request Headers中可以看到Cookie: cx=Segmentfault屬性,既然發(fā)送給服務(wù)端之后,相應(yīng)的在后端也是可以接收到該Cookie的,修改一下上面的例子:

const Http = require("http");
const app = Http.createServer((req,res) => {
 if(req.url === "/favicon.ico"){
  return;
 }else{
  console.log("cookie",req.headers.cookie)
  res.setHeader("Set-Cookie","cx=Segmentfault");
  res.end("hello cookie");
 };
});
app.listen(3000);

在接收到訪問的時候,就可以接收到了cx=Segmentfault,如果說現(xiàn)在這份Cookie是一份加密的數(shù)據(jù)的話,里面包含一些用戶信息,在通過前后端進行交互之后,當(dāng)客戶端再次請求服務(wù)端的時候,服務(wù)端拿到相對應(yīng)的Cookie并對其進行解密,對其中用戶的信息進行鑒權(quán)處理就可以了。

服務(wù)端通過Set-CookieResponse Headers設(shè)置了一段加密數(shù)據(jù),客戶端接收到了其相對應(yīng)的數(shù)據(jù)之后,瀏覽器對其進行存儲,當(dāng)可客戶端再次發(fā)送請求的時候,會攜帶已有的CookieRequest Headers中一并發(fā)送給服務(wù)端,服務(wù)端解密數(shù)據(jù)完成鑒權(quán),由此可以得出Cookie是服務(wù)端存儲在客服端的狀態(tài)標(biāo)志,再由客戶端發(fā)送給服務(wù)端,由服務(wù)端解析。Cookie在使用中必須是同域的情況下才可以,一般常用的是在MVC這種開發(fā)形式中很常用。

說了半天Cookie,但是對于Session卻只字未提,接下來就介紹一下Session,Session從字面上講,就是會話。這個就類似于你和一個人交談,你怎么知道當(dāng)前和你交談的是張三而不是李四呢?對方肯定有某種特征(長相等)表明他就是張三。Session也是類似的道理,服務(wù)器要知道當(dāng)前發(fā)請求給自己的是誰。為了做這種區(qū)分,服務(wù)器就要給每個客戶端分配不同的身份標(biāo)識,然后客戶端每次向服務(wù)器發(fā)請求的時候,都帶上這個身份標(biāo)識,服務(wù)器就知道這個請求來自于誰了。至于客戶端怎么保存這個身份標(biāo)識,可以有很多種方式,對于瀏覽器客戶端,大家都默認(rèn)采用Cookie的方式。

const Http = require("http");
let session = {};
const app = Http.createServer((req,res) => {
 const sessionKey = "uId";
 if(req.url === "/favicon.ico"){
  return;
 }else{
  const uId = parseInt(Math.random() * 10e10);
  const cookie = req.headers.cookie;
  if(cookie && cookie.indexOf(sessionKey) !== -1){
   let _uId = cookie.split("=")[1];
   res.end(`${session[_uId].name} Come back`);
  }
  else{
   res.setHeader("Set-Cookie",`${sessionKey}=${uId}`);
   session[uId] = {"name":"Aaron"};
   res.end("hello cookie");
  }
 };
});
app.listen(3000);

代碼中解析cookie只是用了和很簡單的方式,只是為了完成Dome而已,在實際項目中獲取cookie比這個要復(fù)雜很多。

Session/Cookie認(rèn)證主要分四步:

  1. 服務(wù)器在接受客戶端首次訪問時在服務(wù)器端創(chuàng)建seesion,然后保存seesion(我們可以將seesion保存在內(nèi)存中,也可以保存在redis中,推薦使用后者),然后給這個session生成一個唯一的標(biāo)識字符串,然后在響應(yīng)頭中種下這個唯一標(biāo)識字符串。
  2. 簽名。這一步只是對sid進行加密處理,服務(wù)端會根據(jù)這個secret密鑰進行解密。(非必需步驟)
  3. 瀏覽器中收到請求響應(yīng)的時候會解析響應(yīng)頭,然后將sid保存在本地cookie中,瀏覽器在下次http請求的時候,請求頭中會帶上該域名下的cookie信息,
  4. 服務(wù)器在接受客戶端請求時會去解析請求頭cookie中的sid,然后根據(jù)這個sid去找服務(wù)器端保存的該客戶端的session,然后判斷該請求是否合法。

利用服務(wù)器端的session和瀏覽器端的cookie來實現(xiàn)前后端的認(rèn)證,由于http請求時是無狀態(tài)的,服務(wù)器正常情況下是不知道當(dāng)前請求之前有沒有來過,這個時候我們?nèi)绻涗洜顟B(tài),就需要在服務(wù)器端創(chuàng)建一個會話(seesion),將同一個客戶端的請求都維護在各自得會會話中,每當(dāng)請求到達(dá)服務(wù)器端的時候,先去查一下該客戶端有沒有在服務(wù)器端創(chuàng)建seesion,如果有則已經(jīng)認(rèn)證成功了,否則就沒有認(rèn)證。

redis結(jié)合使用:

const koa = require("koa");
const session = require("koa-session");
const redisStore = require("koa-redis");
const redis = require("redis");
const wrapper = require("co-redis");
const app = new koa();
const redisClient = redis.createClient(6379,"localhost");
const client = wrapper(redisClient);
// 類似于密鑰
app.keys = ["Aaron"];
const SESSION_CONFIG = {
 // 所設(shè)置的session的key
 key:"sId",
 // 最大有效期
 maxAge:8640000,
 // 是否防止js讀取
 httpOnly:true,
 // cookie二次簽名
 signed:true,
 // 存儲方式
 stroe:redisStore({client})
};
app.use(session(SESSION_CONFIG,app));
app.use((ctx) => {
 redisClient.keys("*",(err,keys) => {
  keys.forEach(key => {
   redisClient.get(key,(err,val) => {
    console.log(val);
   });
  })
 })
 if(ctx.path === "/favicon.ico") return;
 let n = ctx.session.count || 0;
 ctx.session.count = ++n;
 ctx.body = `第${n}次訪問`
});
app.listen(3000);

雖然Session/Cookie可以解決鑒權(quán)問題,但是會有很大的問題,對于服務(wù)端來說說是一個巨大的開銷,嚴(yán)重的限制了服務(wù)器擴展能力,比如說我用兩個機器組成了一個集群,小F通過機器A登錄了系統(tǒng),那sessionId會保存在機器A上,假設(shè)小F的下一次請求被轉(zhuǎn)發(fā)到機器B怎么辦?機器B可沒有小F的sessionId,有時候會采用一點小伎倆:session sticky,就是讓小F的請求一直粘連在機器A上,但是這也不管用,要是機器A掛掉了, 還得轉(zhuǎn)到機器B去。那只好做session的復(fù)制了,把sessionId在兩個機器之間搬來搬去,再好的服務(wù)器也經(jīng)不起這樣的折騰。

Token或Jwt

在計算機身份認(rèn)證中是令牌(臨時)的意思,在詞法分析中是標(biāo)記的意思。一般作為邀請、登錄系統(tǒng)使用?,F(xiàn)在前后端分離火熱,Token混的風(fēng)生水起,很多項目開發(fā)過程中都會用到Token,其實Token是一串字符串,通常因為作為鑒權(quán)憑據(jù),最常用的使用場景是API鑒權(quán)。

客戶端使用用戶名跟密碼請求登錄服務(wù)端收到請求,去驗證用戶名與密碼驗證成功后,服務(wù)端會簽發(fā)一個Token,再把這個Token發(fā)送給客戶端客戶端收到Token以后可以把它存儲起來,比如放在Cookie里或者Local Storage里客戶端每次向服務(wù)端請求資源的時候需要帶著服務(wù)端簽發(fā)的Token服務(wù)端收到請求,然后去驗證客戶端請求里面帶著的Token,如果驗證成功,就向客戶端返回請求的數(shù)據(jù)

示例:

前端

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<title>Document</title>
</head>
<body>
<div id="app">
 <div>
  <input type="text" v-model="username">
  <input type="text" v-model="passwrold">
 </div>
 <div>
  <button @click="login">登陸</button>
  <button @click="loginOut">退出</button>
  <button @click="getUserInfo">獲取用戶信息</button>
 </div>
 <div>
  <button @click="logs = []">清空日志</button>
 </div>
 <ul>
  <li v-for="(item,index) of logs" :key="index">{{item}}</li>
 </ul>
</div>
<script>
axios.defaults.baseURL = "http://localhost:3000"
// 請求攔截
axios.interceptors.request.use((config) => {
 const token = localStorage.getItem("token");
 if(token){
  // 判斷是否存在token,如果存在的話
  // 每次發(fā)起HTTP請求時在headers中添加token
  // Bearer是JWT的認(rèn)證頭部信息
  config.headers["Authorization"] = `Bearer ${token}`
 }
 return config;
},error => alert(error));
// 響應(yīng)攔截
axios.interceptors.response.use((res) => {
 app.logs.push(JSON.stringify(res.data))
 return res;
},error => alert(error));
const app = new Vue({
 el:"#app",
 data:{
  username:"",
  passwrold:"",
  logs:[]
 },
 methods:{
  login() {
   let {username,passwrold} = this;
   axios.post("/users/login/token",{
    username,passwrold
   }).then((res) => {
    localStorage.setItem("token",res.data.token)
   })
  },
  loginOut(){
   axios.post("/users/logout").then((res) => {
    localStorage.removeItem("token")
   })
   
  },
  getUserInfo(){
   axios.get("/users/get/user/info").then((res) => {
    console.log(res)
   });
  }
 }
})
</script>
</body>
</html>

后端:

const Koa = require("koa");
const jwt = require("jsonwebtoken");
const jwtAuth = require("koa-jwt");
const Router = require('koa-router'); // koa 路由中間件
const bodyParser = require("koa-bodyparser");
const cors = require("koa2-cors");
const app = new Koa();
const router = new Router();
// 密鑰
const secret = "this is a secret";
app.use(bodyParser());
app.use(cors());
router.post("/users/login/token",(ctx) => {
 const {body} = ctx.request;
 const {username} = body;
 ctx.body = {
  code:1,
  message:"登陸成功",
  body:{
  username
  },
  token:jwt.sign({
   data:body,
   exp:Math.floor(Date.now() / 1000) + 60 * 60,
  },secret)
 }
});
router.post("/users/logout",(ctx) => {
 const {body} = ctx.request;
 ctx.body = {
  code:1,
  message:"退出成功"
 }
})
router.get("/users/get/user/info",jwtAuth({secret}),(ctx) => {
 // jwtAuth token參數(shù)
 console.log(ctx.state.user.data)
 ctx.body = {
  code:1,
  message:"成功",
  data:ctx.state.user.data
 }
})
app.use(router.routes());
app.listen(3000);

上面代碼用到了很多的依賴模塊,最關(guān)鍵的的是jsonwebtokenkoa-jwt,這兩個模塊一個是用來對token進行加密,一個是用來對數(shù)據(jù)進行解密的,同時在每次訪問需要保護的路由的時候需要使用jwtAuth對其進行攔截處理,jwtAuth會根據(jù)其secret進行數(shù)據(jù)解密,把解密的數(shù)據(jù)存放到ctx.state中,供用戶讀取。

有關(guān)jwt相關(guān)請查看深入理解令牌認(rèn)證機制詳細(xì)的解釋了其加密后數(shù)據(jù)token的構(gòu)成。

加密后的數(shù)據(jù)主要分為三個部分機密頭部、載荷、數(shù)據(jù)如果我們想查看其加密前內(nèi)容是什么樣子的,可以通過base64對其沒一部分進行解密。

  • 機密頭部:聲明加密規(guī)則,可反解
  • 載荷:數(shù)據(jù)信息,也就是我們需要加密的信息,可反解
  • 驗證:這部分是對前兩部分使用hash算法的摘要,是不可逆的

在使用jsonwebtoken時需要注意的是,由于加密信息是可以反解的所以,盡量不要在加密數(shù)據(jù)中存放敏感信息,比如用戶的密碼,用戶私密信息等等(千萬不要效仿Dome,這是不對的O(∩_∩)O)。同過上面所述,所傳遞給前端的token一旦發(fā)生變化,僅僅是一個字母大小寫發(fā)生變化也是不行的,當(dāng)服務(wù)端接收到token解密時,是無法正確解密的,這種token可以是發(fā)篡改的。如果想要篡改token必須要有其secret才可以對其進行篡改和偽造。

OAuth

OAuth(開放授權(quán))是一個開放標(biāo)準(zhǔn),允許用戶授權(quán)第三方網(wǎng)站訪問他們存儲在另外的服務(wù)提供者上的信息,而不需要將用戶名和密碼提供給第三方網(wǎng)站或分享他們數(shù)據(jù)的所有內(nèi)容,為了保護用戶數(shù)據(jù)的安全和隱私,第三方網(wǎng)站訪問用戶數(shù)據(jù)前都需要顯式的向用戶征求授權(quán)。我們常見的提供OAuth認(rèn)證服務(wù)的廠商有支付寶,QQ,微信

OAuth協(xié)議又有1.02.0兩個版本。相比較1.0版,2.0版整個授權(quán)驗證流程更簡單更安全,也是目前最主要的用戶身份驗證和授權(quán)方式。

OAuth認(rèn)證主要經(jīng)歷了如下幾步:

  • 需要第三方應(yīng)用存儲資源所有者的憑據(jù),以供將來使用,通常是明文密碼。
  • 需要服務(wù)器支持密碼身份認(rèn)證,盡管密碼認(rèn)證天生就有安全缺陷。
  • 第三方應(yīng)用獲得的資源所有者的受保護資源的訪問權(quán)限過于寬泛,從而導(dǎo)致資源所有者失去對資源使用時限或使用范圍的控制。
  • 資源所有者不能僅撤銷某個第三方的訪問權(quán)限而不影響其它,并且,資源所有者只有通過改變第三方的密碼,才能單獨撤銷這第三方的訪問權(quán)限。
  • 與任何第三方應(yīng)用的讓步導(dǎo)致對終端用戶的密碼及該密碼所保護的所有數(shù)據(jù)的讓步。

簡單概括,就是用于第三方在用戶授權(quán)下調(diào)取平臺對外開放接口獲取用戶相關(guān)信息。OAuth引入了一個授權(quán)環(huán)節(jié)來解決上述問題。第三方應(yīng)用請求訪問受保護資源時,資源服務(wù)器在獲準(zhǔn)資源用戶授權(quán)后,會向第三方應(yīng)用頒發(fā)一個訪問令牌(AccessToken)。該訪問令牌包含資源用戶的授權(quán)訪問范圍、授權(quán)有效期等關(guān)鍵屬性。第三方應(yīng)用在后續(xù)資源訪問過程中需要一直持有該令牌,直到用戶主動結(jié)束該次授權(quán)或者令牌自動過期。

總結(jié)

授權(quán)方式多種多樣,主要還是要取決于我們對于產(chǎn)品的定位。如果我們的產(chǎn)品只是在企業(yè)內(nèi)部使用,tokensession就可以滿足我們的需求,現(xiàn)在前后端分離如此火熱jwt認(rèn)證方式更加適合。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解JavaScript中的Object.is()與

    詳解JavaScript中的Object.is()與"==="運算符總結(jié)

    這篇文章主要介紹了詳解JavaScript中的Object.is()與"==="運算符總結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • 本地存儲localStorage用法詳解

    本地存儲localStorage用法詳解

    這篇文章主要為大家詳細(xì)介紹了本地存儲localStorage的用法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • js取消單選按鈕選中示例代碼

    js取消單選按鈕選中示例代碼

    取消單選按鈕選中的方法有很多,下面為大家詳細(xì)介紹下使用js是如何實現(xiàn)的,感興趣的朋友不要錯過
    2013-11-11
  • 最新評論