我想大家都知道oauth2是通过access_token去限制访问api的接口,通过时间过期规则要重新登录才能访问接口,但是oauth2里面有提供一个叫refresh access_token的方法,这样就保证能自动获取最新的access_token以免过期,具体原理我也不多讲了,下面是要做的步骤: 首先大家先要在index.js中定义一些配置:
global.__basename = __dirname; #定义文件夹的目录
require('coffee-script'); #加载coffeescript的语法,如果不需要可以不用写
process.env.TZ = 'PRC'; #设置时间
app.coffee要添加以下代码:
cors = require './middlewares/cors'
oauth = require './middlewares/oauth'
app.use cors
app.use oauth.oauth()
app.use oauth.login()
我们然后我们要新建一个oauth.coffee放在middlewares中,里面要用第三方的oauth2-provider npm install oauth2-provider
,然后还要依次加载一些必要的包
OAuth2Provider = require('oauth2-provider').OAuth2Provider
config = require __basename + '/config/config'
mysql = require __basename + '/connections/mysql/test' #此处为你的mysql链接句柄
mohair = require 'mohair'
async = require 'async'
_ = require 'underscore'
makeExtraData = require __basename + '/helpers/oauth/extra_data'
makeExtraData require的实际上是oauth的用户验证. 在’/helpers/oauth/中新建立一个extra_data.coffee在里面写下以下代码
mhoair = require 'mohair'
mysql = require __basename + '/connections/mysql/test' #此处为你的mysql链接句柄
#链接users表,拿到该users所属的群主
module.exports = (userId, fn) ->
mohair
.connect(mysql)
.table('users')
.select('group_id')
.where(id: userId)
.findOne (err, result) ->
fn err, groupId: result.group_id
然后回到middlewares/oauth.coffee中开始认证
module.exports = oauth = new OAuth2Provider
crypt_key: config.oauth.cryptKey
sign_key: config.oauth.signKey
在此需要检查用户登录状态,并且实现页面跳转
oauth.on 'enforce_login', (req, res, authorizeUrl, next) ->
return next req.session.userId if req.session.userId
res.redirect '/oauth/login?next=' + encodeURIComponent authorizeUrl
现在应该实现验证了.
oauth.on 'authorize_form', (req, res, clientId, authorizeUrl) ->
async.auto
permission: (fn) ->
mohair
.connect(mysql)
.table('user_role_relations urr')
.join('left join roles r on urr.role_id = r.id')
.where('urr.user_id': req.session.userId)
.where('r.product_id': clientId)
.exists fn
,
(err, results) ->
res.locals.authorizeUrl = authorizeUrl
if results.permission
#res.render 至成功页面
else
#res.render 至失败页面
在创建access_token的时候检查用户是否存在
oauth.on 'create_access_token', (userId, clientId, next) ->
makeExtraData userId, (err, result) ->
next result
oauth.on 'save_access_token', (userId, clientId, accessToken) ->
#然后保存access_token,在此你可以进行其他操作
最后,开始创建access_token啦.config.oauth.accessTokenTTL 为access_token的过期时间
oauth.on 'access_token', (req, info, next) ->
#在此判断access_token是否过期
if info.grant_date.getTime() + config.oauth.accessTokenTTL > Date.now()
req.session.userId = info.user_id
req.session.groupId = info.extra_data?.groupId
async.auto
role: (callback) ->
mohair
.connect(mysql)
.table('user_role_relations urr')
.join('left join roles r on urr.role_id = r.id')
.select('urr.role_id as role_id')
.where('urr.user_id': info.user_id)
.findOne callback
permission: ['role', (callback, results) ->
return callback null, [] unless results.role
mohair
.connect(mysql)
.table('role_permission_relations rpr')
.join('left join permissions p on rpr.permission_id = p.id')
.select('p.constant')
.where('rpr.role_id': results.role.role_id)
.exec callback
]
,
(err, results) ->
next err if err
req.session.permissions = _.pluck results.permission, 'constant'
next()
else
req.session.error = 'access_token timeout'
next()
我想上面的代码大家应该都能看懂吧,先判断access_token是否过期,然后将【用户、群主、及用户权限存入至session中,如果权限不存在,返回就是空,也就是该用户没有权限】 接下来,我们应该开始添加url接口,实现oauth2认证了就应该在router.coffee写下如下代码:
app = require './app'
# OAuth
app.use '/oauth', require './lib/oauth'
新建/lib/oauth/index.coffee,在这里可以实现登录获取access_token及登出等操作.
express = require 'express'
mysql = require __basename + '/connections/mysql/test'
mohair = require 'mohair'
config = require __basename + '/config/config'
querystring = require 'querystring'
oauth = require __basename + '/middlewares/oauth'
restrict = require __basename + '/middlewares/restrict'
makeExtraData = require __basename + '/helpers/oauth/extra_data'
module.exports = app = express()
#在此处进行登录验证,成功后进行页面跳转,并设置session
app.post '/login', (req, res) ->
{email, password} = req.body
mohair
.connect(mysql)
.table('users')
.select('id')
.where(email: email)
.where(password: password)
.findOne (err, result) ->
if result
req.session.userId = result.id
else
req.session.error = 'Invalid User'
res.redirect req.body.next
登出方法
app.get '/logout', (req, res) ->
req.session = null
res.redirect '/oauth/authorize?' + querystring.stringify req.query
刷新access_token
app.get '/refresh_token', restrict(), (req, res) ->
makeExtraData req.session.userId, (err, extraData) ->
result = oauth.generateAccessToken req.session.userId, null, extraData
res.json access_token: result.access_token
登出和刷新所提供的两个方法都是oauth2本身提供的方法 middlewares/restrict.coffee代码如下:
_ = require 'underscore'
module.exports = (permission) ->
(req, res, next) ->
unless req.query.access_token
return res.json 400, error: "require access_token"
if req.session.error
return res.json 400, error: req.session.error
if permission and ! _.contains req.session.permissions, permission
return res.json 400, error: 'You dont have the permission'
next()
如果有权限就会调用next()实现跳转了,在调用login的时候要传一个next的参数,这个是登录成功后跳转的页面 在routes里面,大家可以通过restrict去判断该用户是否具备某routes权限
Users = require './user'
app.get '/users', restrict('list'), Users.index
里面的list是该route的权限,是跟数据库test中的permissions表中的constant对应,该表结构如下:
实在是太复杂了…
app.post ‘/login’, (req, res) ->
这个是什么语法… 糖?
这个是coffeescript
的语法,就是ruby on rails
语言的语法,呵呵.
因为整个过程包括登录,认证以及验证,所以可能有点点复杂.
你在index.js中加入这个代码就可以用coffeescript的语法了.
require('coffee-script')
大量语法糖的混杂外加各种框架,逻辑根本看不清,这代码想要维护有点难吧
长文帮顶~
coffee 也挺不错的, 但是总是充当人肉编译器, 想编译完是啥样子, 还是写 js 吧