所謂認證就是如何證實你是你本身
的方式,通常來講證實你是你本身的方式就是經過身份證;而互聯網中的認證一般用用戶名和密碼來證實你是你本身。
經常使用的身份認證的方式通常有:javascript
所謂受權舉個例子就是:你在安裝手機應用的時候,應用會申請權限,你贊成這個權限申請的過程就叫作受權
。同理,在oauth中,被受權方會收穫必定的權限。一般使用oauth的廠商有:java
受權並不必定須要認證。好比:當你有鑰匙的時候,你就能夠開門,你並不必定是這個屋子的主人。
在互聯網中的oauth
受權一般來講是經過token進行權限的授予的。ios
OAuth是互聯網行業一種標準的受權方式。各個公司根據這一套標準實現本身的OAuth認證和受權流程,而第三方想要接入這個流程,就須要使用OAuth這套方案。
OAuth目前有兩個版本:git
OAuth第三方認證和受權流程中通常會有幾個角色:github
另一種說法說的是客戶端和服務端能夠合併稱爲被受權方,若是你作的是個純客戶端的OAuth接入的話,那麼你也能夠不須要服務端,不過這個接入方式安全性不高。redis
目前業界的OAuth受權方式有多種,其中最主要的是如下幾種:數據庫
經過認證碼的認證受權方式進行OAuth的接入時,主要流程分別是如下幾步:json
redirect
到OAuth接入方並附帶上client_id
redirect
以後的網站上輸入用戶名和密碼code
。code
以後,拿着client_secret
和code
向OAuth接入方申請得到Token
url:https://github.com/settings/apps
axios
注意:HomePage URL在項目未上線以前填本地項目根路徑地址,在項目上線以後填上線以後的域名地址;同理Authorization callback URL
在上線以前填寫http://localhost:3000/auth
,在上線以後填寫域名+/auth
。
註冊成功以後,會出現一個client_id和client_secret,這個兩個值很是重要。須要保存在項目文件之中api
url: https://github.com/login/oauth/authorize
param:
redirect uri
相同url: https://github.com/login/oauth/access_token
param:
url: https://api.github.com/user
header:
token +access_token
Authorization callback URL
不一樣時,就會報錯。當用戶進行完了OAuth流程以後,將token保存於cookie和session中,這樣用戶就不須要每次切換頁面時都去進行一次OAuth認證和受權。
koa框架存儲cookie的方式:
server.use(async (ctx, next) => {
ctx.cookies.set('id', id, {
httpOnly: true
});
await next()
})
複製代碼
const session = require('koa-session');
// 給cookie加密,加密以後的密文是jwt
server.keys = ['ainuo develop github apps'];
const SESSION_CONFIG = {
// key爲存儲的字段名
key: 'jid',
// 當沒有配置store時,session是以jwt存儲在cookie中的
// store:
};
// 使用session中間件
server.use(session(SESSION_CONFIG, server));
// 通常來講咱們會單獨暴露一個接口用於設置session。
router.get('/set/user', async ctx => {
// 設置session
ctx.session.user = {
name: 'ainuo',
age: 18
};
ctx.body = 'set session success'
});
複製代碼
建立這個對象的目的是集成redis到kos-session,並簡化redis的相關操做
function getRedisSessionId(sessionId) {
return `ssid:${sessionId}`
}
module.exports = class RedisSessionStore {
constructor(client) {
this.client = client
}
// 根據sessionId獲取redis中存儲的session數據
async get(sessionId) {
console.log('get session', sessionId);
const id = getRedisSessionId(sessionId);
const data = await this.client.get(id);
if (!data) {
return null
}
try {
return JSON.parse(data);
} catch (e) {
console.log(e)
}
}
// 存儲session數據到redis
async set(sessionId, sessionValue, lifetime) {
console.log('set session', sessionId);
const id = getRedisSessionId(sessionId);
if (typeof lifetime === "number") {
lifetime = Math.ceil(lifetime / 1000);
}
try {
const sessionStr = JSON.stringify(sessionValue);
if (lifetime) {
await this.client.setex(id, lifetime, sessionStr)
} else {
await this.client.set(id, sessionStr)
}
} catch (e) {
console.log(e)
}
}
// 從redis中刪除某個session
async destroy(sessionId) {
console.log('destroy session', sessionId);
const id = getRedisSessionId(sessionId);
await this.client.del(id)
}
}
複製代碼
const Redis = require('ioredis');
// 能夠傳入一些配置
const client = new Redis({});
server.keys = ['ainuo develop github apps'];
const SESSION_CONFIG = {
key: 'jid',
// 當沒有配置store時,session是以jwt存儲在cookie中的
store: new RedisSessionStore(client),
// maxAge: 10 * 1000,
};
// 對服務端的session進行加密
server.use(session(SESSION_CONFIG, server));
// 刪除session時刪除redis數據庫中的ssid:xxx的數據
router.get('/del/user', async ctx => {
// 設置session
ctx.session = null;
ctx.body = 'del session success'
});
// 設置session時添加session到redis數據庫
router.get('/set/user', async ctx => {
// 設置session
ctx.session.user = {
name: 'ainuo',
age: 18
};
ctx.body = 'set session success'
});
複製代碼
//config,js
module.exports = {
github: {
client_id: 'xxxx',
client_secret: 'xxxx',
request_token_url: 'https://github.com/login/oauth/access_token',
auth_url: 'https://github.com/login/oauth/authorize',
scope: 'user',
user_info_url: 'https://api.github.com/user'
}
};
// auth.js
const axios = require('axios');
const {github} = require('../config');
const {client_id, client_secret, request_token_url} = github;
module.exports = function (server) {
server.use(async (ctx, next) => {
if (ctx.path === '/auth') {
const code = ctx.query.code;
if (code) {
// 發起對access_token的請求
const res = await axios({
method: 'POST',
url: request_token_url,
data: {
client_id,
client_secret,
code
},
headers: {
Accept: 'application/json',
}
});
if (res.status === 200 && !(res.data && res.data.error)) {
ctx.session.githubAuth = res.data;
const {access_token, token_type} = res.data;
// 請求獲得用戶信息
const userInfoRes = await axios({
method: 'GET',
url: github.user_info_url,
headers: {
Authorization: `token ${access_token}`
}
});
// 存儲用戶信息到session和redis
ctx.session.userInfo = userInfoRes.data;
// 受權等流程結束以後,重定向到首頁
ctx.redirect('/');
} else {
const errorMsg = res.data && res.data.error;
ctx.body = `request token failed ${errorMsg}`
}
} else {
ctx.body = 'code not exist';
}
} else {
await next()
}
})
};
// server.js
// 對服務端的session進行加密
server.use(session(SESSION_CONFIG, server));
// 配置處理github oauth登錄
auth(server);
複製代碼