这就是我处理这个案子的方式;
- 当然,使用 HTTPS 将用户名和密码以纯文本形式发布到您的 api。
- 然后将其验证到您的数据库,当今用于对密码加盐的最佳算法是bcrypt.
- 如果用户无效返回 401 或其他。
- 如果用户有效,则返回 JWT 令牌及其使用公钥算法签名的个人资料。
- 您的前端知道公钥,因此可以解码 JWT,但无法生成新的公钥。
- 对于每个需要身份验证的请求,您都附加一个
Authentication
标头,带有Bearer [JWT]
- 后端的中间件读取此标头并使用私钥对其进行验证。
不要害怕 JWT,每种语言和框架都有大量的实现,并且比您想象的要容易。许多应用程序甚至 Google 都已经在使用 JWT。
Auth0 https://www.auth0.com是一个身份验证代理,可以针对任何身份提供商或自定义数据库进行验证,并返回 JWT。它提供了一个可用于在前端解码配置文件的 clientID 和一个用于在后端验证令牌的密钥以及客户端库 https://github.com/auth0/auth0.js去做这个。
免责声明:我为 auth0 工作。
Update:既然你在评论中提到了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: '[email protected] /cdn-cgi/l/email-protection',
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
但因为我有一个express-jwt中间件来处理所有事情/api
它需要一个 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 的忠实粉丝,我为其他一些适配器贡献了很多适配器和修复程序,但对于这种特殊情况,我不会使用它。