所谓认证就是如何证实你是你本身
的方式,通常来讲证实你是你本身的方式就是经过身份证;而互联网中的认证一般用用户名和密码来证实你是你本身。
经常使用的身份认证的方式通常有: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);
复制代码