构建简单的OAuth受保护资源

该博客介绍了如何构建OAuth受保护资源,包括从HTTP请求中解析令牌、存储和验证令牌,以及根据权限范围提供不同操作和服务。示例代码展示了在Node.js中处理不同HTTP方法(GET, POST, DELETE)时,如何检查权限并返回不同数据结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

构建简单的OAuth受保护资源

资源服务器需要从传入的HTTP请求中解析出OAuth令牌,验证令牌,并确定它能用于那些请求

解析HTTP请求中的OAuth令牌

    var getAccessToken = function(req, res, next){
        var inToken = null;
        var auth = req.headers['authorization'];
        if(auth && auth.toLowerCase().indexOf('bearer') == 0){
            inToken = auth.slice('bearer'.length);
        } else if(req.body && req.body.access_token){
            inToken = req.body.access_token;
        } else if(req.query && req.query.access_token){
            inToken = req.query.access_token;
        }
    };

存储验证令牌

令牌存储方式:

  • 共享数据库

  • 令牌内省Web协议,由授权服务器提供接口,让资源服务器能够在运行时检查令牌状态

  • 令牌内包含受保护资源能直接解析并理解的信息,JWT就是这样一种数据结构,可以使用受加密的JSON对象携带声明信息

验证令牌

    var getAccessToken = function(req, res, next){
        var inToken = null;
        var auth = req.headers['authorization'];
        if(auth && auth.toLowerCase().indexOf('bearer') == 0){
            inToken = auth.slice('bearer'.length);
        } else if(req.body && req.body.access_token){
            inToken = req.body.access_token;
        } else if(req.query && req.query.access_token){
            inToken = req.query.access_token
        }
        console.log('Incoming token: %s', inToken);
        nosql.one(function(token){
            if(token.access_token == inToken){
                return token;
            }
        }, function(err, token){
            if(token){
                console.log('We found a matching token: %s', inToken);
            } else {
                console.log('No matching token was found.');
            }
            req.access_token = token;
            next();
            return;
        })
    };

根据令牌提供内容

    var requireAccessToken = function(req, res, next){
        if(req.access_token){
            next();
        } else {
            res.status(401).end();
        }
    };

不同权限范围对应不同操作

    app.get('/words', getAccessToken, requireAccessToken, function(req, res){
        if(__.contains(req.access_token.scope, 'read')){
            res.json({words: savedWords.join(' '), timestamp: Data.now()});
        } else {
            res.set('WWW-Authenticate', 'Bearer realm=localhost:9002, error = "insufficient_scope", scope = "read"');
            res.status(403);
        }
    });

    app.post('/words', getAccessToken, requireAccessToken, function(req, res){
        if(__.contains(req.access_token.scope, 'write')){
            if(req.body.word){
                savedWords.push(req.body.word);
            }
            res.stastus(201).end();
        } else {
            res.set('WWW-Authenticate', 'Bearer realm = localhost:9002, error = "insufficient_scope", scope = "write"')
            res.status(403);
        }
    });

    app.delete('/words', getAccessToken, requireAccessToken, function(req, res){
        if(__.contains(req.access_token.scope, 'delete')){
            savedWord.pop();
            res.status(204).end();
        } else {
            res.set('WWW-Authenticate', 'Bearer realm = location:9002, error = "insufficient_scope", scope = "delete"')
        }
    });

不同权限范围对应不同数据结果

    app.get('/produce', getAccessToken, requireAccessToken, function(req, res){
        var produce =  {fruit: [], veggies: [], meats: []};
        if(__.contains(req.access_token.scope, 'fruit')){
            produce.fruit = ['apple', 'banana', 'kiwi'];
        }
        if(__.contains(req.access_token.scope, 'veggies')){
            produce.veggies = ['lettuce', 'onion', 'potato'];
        }
        if(__.contains(req.access_token.scope, 'meats')){
            produce.meats = ['bacon', 'steak', 'chicken breast'];
        }
    });

不同用户对应不同数据结果

    app.get('/favorites', getAccessToke, requireAccessToken, function(req, res){
       if(req.access_token.user == 'alice'){
           res.json({user: 'Alice', favorites: aliceFavorites});
       } else if(req.access_token.user == 'bob'){
           res.json({user: 'Bob', favorites: bobFavorites});
       } else {
           var unknow = {user: 'Unknown', favorites: {movies:[], foods: [], music: []}};
           res.json(unknown);
       }
    });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值