亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

聊聊鑒權那些事(推薦)

2024-05-06 16:54:25
字體:
來源:轉載
供稿:網友

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

什么是鑒權

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

上述簡單扼要的說明了一下鑒權的概念,但是這也只是簡單的鑒權,也是項目中最最常見的及安全形式了,但是對于后端鑒權又是如何去做的,我們仍是一無所知,一般來說對于后端來說,鑒權最長見的方式分為三種:

  • Session/Cookie
  • Token或Jwt
  • OAuth

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

Session/Cookie

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

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字樣,這樣的話就代表該服務已經啟動了。若想查看到到我們所設置的Cookie,首先觀察一下在NetworkResponse Headers中,可以看到我們所寫的Set-Cookie屬性,當我們訪問http://localhost:3000/的時候,當瀏覽器接收到Set-Cookie這個屬性的時候,瀏覽器會根據其內部約定,并在其瀏覽器內部對其cookie進行存儲,打開瀏覽器控制臺,在Application中找到Cookies中找到相對應的域名,就可以看到我們所設置的cookie值了。當在同域的情況下,當再次請求數據的時候瀏覽器會默認發送cookie在該請求中,一起發送給后端。為了證實上面的說法,刷新一下http://localhost:3000/頁面,在控制臺Network找到Request Headers中可以看到Cookie: cx=Segmentfault屬性,既然發送給服務端之后,相應的在后端也是可以接收到該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,如果說現在這份Cookie是一份加密的數據的話,里面包含一些用戶信息,在通過前后端進行交互之后,當客戶端再次請求服務端的時候,服務端拿到相對應的Cookie并對其進行解密,對其中用戶的信息進行鑒權處理就可以了。

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

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

Session/Cookie認證主要分四步:

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

鑒權

利用服務器端的session和瀏覽器端的cookie來實現前后端的認證,由于http請求時是無狀態的,服務器正常情況下是不知道當前請求之前有沒有來過,這個時候我們如果要記錄狀態,就需要在服務器端創建一個會話(seesion),將同一個客戶端的請求都維護在各自得會會話中,每當請求到達服務器端的時候,先去查一下該客戶端有沒有在服務器端創建seesion,如果有則已經認證成功了,否則就沒有認證。

redis結合使用:

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 = { // 所設置的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可以解決鑒權問題,但是會有很大的問題,對于服務端來說說是一個巨大的開銷,嚴重的限制了服務器擴展能力,比如說我用兩個機器組成了一個集群,小F通過機器A登錄了系統,那sessionId會保存在機器A上,假設小F的下一次請求被轉發到機器B怎么辦?機器B可沒有小F的sessionId,有時候會采用一點小伎倆:session sticky,就是讓小F的請求一直粘連在機器A上,但是這也不管用,要是機器A掛掉了, 還得轉到機器B去。那只好做session的復制了,把sessionId在兩個機器之間搬來搬去,再好的服務器也經不起這樣的折騰。

Token或Jwt

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

鑒權

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

示例:

前端

<!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,如果存在的話  // 每次發起HTTP請求時在headers中添加token  // Bearer是JWT的認證頭部信息  config.headers["Authorization"] = `Bearer ${token}` } return config;},error => alert(error));// 響應攔截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參數 console.log(ctx.state.user.data) ctx.body = {  code:1,  message:"成功",  data:ctx.state.user.data }})app.use(router.routes());app.listen(3000);

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

有關jwt相關請查看深入理解令牌認證機制詳細的解釋了其加密后數據token的構成。

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

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

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

OAuth

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

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

鑒權

OAuth認證主要經歷了如下幾步:

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

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

總結

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲乱码av中文一区二区| 欧美激情视频一区二区三区不卡| 深夜成人在线观看| 亚洲激情成人网| 亚洲天堂久久av| 色悠久久久久综合先锋影音下载| 亚洲视频日韩精品| 精品在线小视频| 亚洲人成电影在线播放| 亚洲欧美日韩国产中文| 日韩在线观看精品| 国产精品精品视频一区二区三区| 午夜精品国产精品大乳美女| 亚洲丝袜一区在线| 亚洲91av视频| 国产精品久久久久久久美男| 中文字幕亚洲欧美| 亚洲色图五月天| 国产美女高潮久久白浆| 欧美老女人性视频| 欧美丰满少妇xxxx| 96精品视频在线| 亚洲欧美日韩一区二区三区在线| 久久亚洲欧美日韩精品专区| 自拍偷拍亚洲欧美| 国产精品高潮呻吟久久av无限| 亚洲乱码国产乱码精品精天堂| 日韩视频在线观看免费| 国产精品黄色影片导航在线观看| 3344国产精品免费看| 国产精品极品美女在线观看免费| 国产精品扒开腿做爽爽爽的视频| 97人人爽人人喊人人模波多| 亚洲精品色婷婷福利天堂| 久久69精品久久久久久久电影好| 日韩电影免费在线观看| 久久视频在线视频| 午夜精品久久久久久久99热| 欧美性感美女h网站在线观看免费| 亚洲第一天堂无码专区| 欧美最顶级的aⅴ艳星| 精品动漫一区二区三区| 国产精品露脸av在线| 日韩一区二区久久久| 国产精品丝袜一区二区三区| 国产免费久久av| 久久久精品中文字幕| 中文字幕亚洲天堂| 欧美精品videos性欧美| 98精品国产自产在线观看| 欧美日本高清一区| 欧美国产中文字幕| 日韩精品福利网站| 91夜夜未满十八勿入爽爽影院| 黑人巨大精品欧美一区二区一视频| 中文字幕在线成人| 亚洲第一中文字幕| 亚洲天堂第一页| 国产精品网站大全| 国产亚洲一级高清| 日本亚洲精品在线观看| 欧美极品欧美精品欧美视频| 国产日韩精品视频| 日韩精品免费电影| 亚洲韩国青草视频| 中文字幕一区二区精品| 欧美激情手机在线视频| 国产精欧美一区二区三区| 国产精品第七十二页| 国内精品小视频在线观看| 人体精品一二三区| 亚洲精品一区二三区不卡| 日韩少妇与小伙激情| 欧美日韩亚洲成人| 欧美中文在线观看国产| 亚洲高清久久久久久| 91精品在线国产| 亚洲成人精品久久久| 国产精品视频一区国模私拍| 日本欧美在线视频| 国产精品999| 欧美在线视频一区| 欧洲美女7788成人免费视频| 狠狠久久亚洲欧美专区| 欧美亚洲午夜视频在线观看| 欧美专区第一页| 亚洲欧洲国产一区| 国产日韩欧美91| 91国产美女在线观看| 亚洲午夜女主播在线直播| 久久免费视频网站| 亚洲激情在线视频| 国产精品美女久久久免费| 亚洲综合在线小说| 精品国产乱码久久久久久虫虫漫画| 亚洲色图激情小说| 色偷偷av亚洲男人的天堂| 日韩精品免费观看| 亚洲欧美日韩精品久久| 国产女人精品视频| 成人精品一区二区三区电影黑人| 91高清在线免费观看| 亚洲香蕉成人av网站在线观看| 色综合伊人色综合网| 国产精品视频久久久| 亚洲精品成人久久久| 91av在线免费观看| 欧美电影院免费观看| 亚洲综合色av| 97人人做人人爱| 国产欧美在线看| 国产成人精品日本亚洲专区61| 9.1国产丝袜在线观看| 国产成人高潮免费观看精品| 欧美精品videos性欧美| 国产在线观看精品一区二区三区| 欧美一级片一区| 日本一本a高清免费不卡| 欧美国产激情18| 国产精品久久久一区| 亚洲www在线| 热久久99这里有精品| 欧美一级视频一区二区| 国产精品∨欧美精品v日韩精品| 色综合色综合网色综合| 国产日韩视频在线观看| 欧美日韩国产精品一区二区三区四区| 亚洲色图狂野欧美| 成人免费xxxxx在线观看| 国产精品久久久久久av福利| 亚洲直播在线一区| 日韩在线视频线视频免费网站| 国产精品6699| 亚洲成人久久一区| 91在线中文字幕| 日韩一区二区三区在线播放| 欧美做受高潮电影o| 欧美日韩国产精品专区| 国产精品专区h在线观看| 奇米一区二区三区四区久久| 久久99精品久久久久久噜噜| 91丨九色丨国产在线| 国产精品狠色婷| 中文字幕日韩在线视频| 91精品啪在线观看麻豆免费| 久久影院中文字幕| 国产亚洲欧洲高清一区| 91亚洲人电影| 久久青草福利网站| 日韩精品福利在线| 欧美成aaa人片免费看| 久久久久久久久久久免费精品| 国产成人精品综合久久久| 久久视频在线免费观看| 亚洲成人aaa| 国模叶桐国产精品一区| 日韩av免费在线| 青青青国产精品一区二区| 大荫蒂欧美视频另类xxxx| 亚洲人成电影网站| 亚洲国产精品推荐| 国产精品一区久久| 日韩欧美一区二区三区久久| 亚洲人成网7777777国产|