之前可能已经提出这个问题,所以我这是先发制人的道歉。
我构建了一个网站,我构建了一个API。移动应用程序将来也会使用该API。我拥有这两个,所以我很确定两个和三个腿的OAuth不适合我。 API包含可供全球访问的部分以及受保护且需要用户帐户的其他部分。为了简单起见,我刚刚使用了https + Basic Auth解决方案(目前为止)。当手动向API测试请求时,这一切都很好(我没有写测试,因为我是一个坏人),事情按预期工作,Basic Auth很好。
我正在尝试解决用明文用户和密码登录的用户流程,将其发送到API进行身份验证,API只需要说是或否,但是来自网站的所有请求(代表API的用户应该以某种方式使用他们的凭据进行签名,以便他们想要POST / GET / PUT / DEL其中一个受保护资源。
在我读过的所有auth资源中,我仍然对使用什么方案感到困惑。在网站端存储明文密码,以便我可以对64进行编码并通过网络发送它看起来很糟糕,但看起来这就是我必须要做的事情。我已经阅读了digest auth但我不确定是否已经知道了。欢迎提出任何建议。
答案 0 :(得分:10)
这就是我处理这种情况的方法;
Authentication
标题,Bearer [JWT]
不要害怕JWT,每种语言和框架都有很多实现,比你想象的要容易。许多应用程序已经使用JWT甚至谷歌。
Auth0是一个身份验证代理,可以针对任何身份提供者或自定义数据库进行验证,并返回JWT。它提供了一个clientID,可用于解码前端的配置文件,以及一个秘密,用于验证后端中的令牌以及client side library来执行此操作。
免责声明:我为auth0工作。
更新:由于您提及node.js并在评论中表达,我将举例说明此技术。
var http = require('http');
var express = require('express');
var jwt = require('jsonwebtoken'); //https://npmjs.org/package/node-jsonwebtoken
var expressJwt = require('express-jwt'); //https://npmjs.org/package/express-jwt
var secret = "this is the secret secret secret 12356";
var app = express();
app.configure(function () {
this.use(express.urlencoded());
this.use(express.json());
this.use('/api', expressJwt({secret: secret}));
});
//authentication endpoint
app.post('/authenticate', function (req, res) {
//validate req.body.username and req.body.password
//if is invalid, return 401
var profile = {
first_name: 'John',
last_name: 'Foo',
email: 'foo@bar.com',
id: 123
};
var token = jwt.sign(profile, secret, {
expiresInMinutes: 60*5
});
res.json({
token: token
});
});
//protected api
app.get('/api/something', function (req, res) {
console.log('user ' + req.user.email + ' is calling /something');
res.json({
name: 'foo'
});
});
//sample page
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
http.createServer(app).listen(8080, function () {
console.log('listening on http://localhost:8080');
});
这是一个快速应用程序,其中一个端点验证用户名和密码。如果凭据有效,则返回具有完整配置文件的JWT令牌,并且到期时间为5小时。
然后我们在/api/something
中有一个示例端点,但由于我在/api
上有一个express-jwt中间件,它需要一个带有有效令牌的Authorization:Bearer头。中间件不仅验证令牌,还解析配置文件并将其放在req.user上。
如何使用此客户端?这是jquery的一个例子:
//this is used to parse the profile
function url_base64_decode(str) {
var output = str.replace("-", "+").replace("_", "/");
switch (output.length % 4) {
case 0:
break;
case 2:
output += "==";
break;
case 3:
output += "=";
break;
default:
throw "Illegal base64url string!";
}
return window.atob(output); //polifyll https://github.com/davidchambers/Base64.js
}
var token;
//authenticate at some point in your page
$(function () {
$.ajax({
url: '/authenticate',
type: 'POST',
data: {
username: 'john',
password: 'foo'
}
}).done(function (authResult) {
token = authResult.token;
var encoded = token.split('.')[1];
var profile = JSON.parse(url_base64_decode(encoded));
alert('Hello ' + profile.first_name + ' ' + profile.last_name);
});
});
//send the authorization header with token on every call to the api
$.ajaxSetup({
beforeSend: function(xhr) {
if (!token) return;
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
}
});
//api call
setTimeout(function () {
$.ajax({
url: '/api/something',
}).done(function (res) {
console.log(rest);
});
}, 5000);
首先,我使用用户名和密码进行身份验证调用,我可以解码JWT中的配置文件以获取用户配置文件,并且还保存令牌以便稍后在每个请求中使用。
ajaxSetup / beforeSend技巧为每次调用添加标头。那么,我可以向/ api / something发出请求。
您可以想象这种方法不使用cookie和会话,因此它在CORS场景中开箱即用。
我是passport.js的忠实粉丝,我为其他适配器贡献了很多适配器和修复程序,但对于这种特殊情况,我不会使用它。
答案 1 :(得分:1)
我最近一直在考虑类似的情况;这是我做的:
我没有充分的理由推荐这个,但万一你有理由使用它:
0.4。为每个请求附加一个时间戳,并在几分钟后使它们过期。
您应该在数据库中保存加密密码的原因,以防有人窃取您的数据库。
基本上我对SSL非常信任,我读过的内容告诉我没关系。