OAuth
使用 github OAuth 实现用户登录
前端页面 index.html
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<button @click='oauth()'>Login with Github</button>
<div v-if="userInfo">
Hello {{userInfo.name}}
<img style="width: 50px;height: 50px;" :src="userInfo.avatar_url" />
</div>
<ul>
<li v-for="(log, idx) in logs" :key="idx">{{log}}</li>
</ul>
</div>
<script>
</script>
<script>
axios.interceptors.request.use(
config => {
const token = window.localStorage.getItem("token");
if (token) {
// 判断是否存在 token,如果存在的话,则每个 http header 都加上 token
config.headers.common["Authorization"] = "Bearer " + token;
}
return config;
},
err => {
return Promise.reject(err);
}
);
axios.interceptors.response.use(
response => {
app.logs.push(JSON.stringify(response.data));
return response;
},
err => {
app.logs.push(JSON.stringify(err));
return Promise.reject(err);
}
);
const app = new Vue({
el: "#app",
data: {
logs: [],
userInfo: null
},
methods: {
async oauth() {
window.open('/auth/github/login', '_blank')
const intervalId = setInterval(() => {
console.log("等待认证中..");
if (window.localStorage.getItem("authSuccess")) {
clearInterval(intervalId);
window.localStorage.removeItem("authSuccess");
this.getUser();
}
}, 500);
},
async getUser() {
const res = await axios.get("/auth/github/userinfo");
console.log('res:', res.data);
this.userInfo = res.data;
}
}
});
</script>
</body>
</html>
服务端 index.js
const Koa = require('koa')
const router = require('koa-router')()
const static = require('koa-static')
const app = new Koa();
const axios = require('axios')
const querystring = require('querystring')
const jwt = require("jsonwebtoken");
const jwtAuth = require("koa-jwt");
const accessTokens = {}
const secret = "my secret";
app.use(static(__dirname + '/'));
// 从 github 注册 Oauth application 后获取 client_id 和 client_secret
const config = {
client_id: '73a4f730f2e8cf7d5fcf',
client_secret: '74bde1aec977bd93ac4eb8f7ab63352dbe03ce48',
}
router.get('/auth/github/login', async (ctx) => {
// 重定向到认证接口,并配置参数
const path = `https://github.com/login/oauth/authorize?${querystring.stringify({ client_id: config.client_id })}`;
// 转发到 github 授权服务器
ctx.redirect(path);
})
// Authorization callback URL
router.get('/auth/github/callback', async (ctx) => {
console.log('callback..')
const code = ctx.query.code;
const params = {
client_id: config.client_id,
client_secret: config.client_secret,
code: code
}
let res = await axios.post('https://github.com/login/oauth/access_token', params)
const access_token = querystring.parse(res.data).access_token
const uid = Math.random() * 99999
accessTokens[uid] = access_token
const token = jwt.sign(
{
data: uid,
// 设置 token 过期时间,一小时后,秒为单位
exp: Math.floor(Date.now() / 1000) + 60 * 60
},
secret
)
ctx.response.type = 'html';
console.log('token:', token)
ctx.response.body = ` <script>window.localStorage.setItem("authSuccess","true");window.localStorage.setItem("token","${token}");window.close();</script>`;
})
router.get('/auth/github/userinfo', jwtAuth({
secret
}), async (ctx) => {
// 验证通过,state.user
console.log('jwt playload:', ctx.state.user)
const access_token = accessTokens[ctx.state.user.data]
res = await axios.get('https://api.github.com/user?access_token=' + access_token)
console.log('userAccess:', res.data)
ctx.body = res.data
})
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(7001);