authentication - 网站和自有API之间的身份验证

标签 authentication

之前可能已经问过这个问题,所以我先发制人地道歉。

我建立了一个网站,并建立了一个 API。该 API 将来也将被移动应用程序使用。我拥有两者,所以我很确定两条腿和三条腿的 OAuth 不适合我。 API 具有可供全世界访问的部分以及 protected 且需要用户帐户的其他部分。为了简单起见,我刚刚使用了 https + 基本身份验证解决方案(目前)。手动测试 API 的请求时一切正常(我没有编写测试,因为我是一个坏人),事情按预期工作,基本身份验证很好。

我正在尝试解决用户使用纯文本用户和密码登录的流程,将其发送到 API 进行身份验证,API 只需要说是或否,但来自站点的所有请求(代表用户)当他们想要 POST/GET/PUT/DEL protected 资源之一时,应使用他们的凭据以某种方式对 API 进行签名。

在我读过的所有身份验证资源中,我仍然对使用什么方案感到困惑。在站点端存储明文密码以便我可以对它进行 base 64 编码并通过网络发送它似乎很糟糕,但看起来这就是我必须做的。我读过摘要认证,但我不确定我是否明白。欢迎任何和所有建议。

最佳答案

这就是我处理这个案子的方式;

  • 当然,使用 HTTPS 将用户名和密码作为纯文本发布到您的 api。
  • 然后将其验证到您的数据库中,当今用于加盐密码的最佳算法是 bcrypt .
  • 如果用户无效,则返回 401 或其他任何内容。
  • 如果用户有效,则返回带有使用公钥算法签名的个人资料的 JWT token 。
  • 您的前端知道公钥,因此它可以解码 JWT,但无法生成新的。
  • 对于每个需要身份验证的请求,您附加一个 Authentication标题,带有 Bearer [JWT]
  • 后端的中间件读取此 header 并使用私钥对其进行验证。

  • 不要害怕 JWT,每种语言和框架都有很多实现,而且比您想象的要容易。许多应用程序已经在使用 JWT,甚至谷歌。

    Auth0是一个身份验证代理,可以针对任何身份提供者或自定义数据库进行验证,并返回 JWT。它提供可用于解码前端配置文件的客户端 ID 和用于验证后端 token 的 key 以及 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 token ,有效期为 5 小时。

    然后我们在 /api/something 中有一个示例端点但是因为我在 /api 上有一个用于所有内容的 express-jwt 中间件它需要一个带有有效 token 的 Authorization: Bearer header 。中间件不仅会验证 token ,还会解析配置文件并将其放在 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 中的配置文件以获取用户配置文件,并且我还保存 token 以供以后在每个请求中使用。

    ajaxSetup/beforeSend 技巧为每次调用添加 header 。所以,然后我可以向/api/something 发出请求。

    可以想象,这种方法不使用 cookie 和 session ,因此它在 CORS 场景中开箱即用。

    我是passport.js 的忠实粉丝,我为其他一些适配器贡献了很多适配器和修复程序,但对于这种特殊情况,我不会使用它。

    关于authentication - 网站和自有API之间的身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20793902/

    相关文章:

    c# - Windows 模拟 LogonUser 错误

    java - 是否建议使用 ProgressDialog 进行登录?

    php - login.php 重定向到空白页面

    python - Django LDAP 身份验证失败 : SERVER_DOWN

    mysql - 是否有 "easy"方法将网站数据库上的用户从 MsSql 身份验证提供程序迁移到 MySql 身份验证提供程序?

    authentication - 是否可以在不使用登录屏幕的情况下对 Keycloak 的身份提供者 (OpenAM) 进行身份验证?

    php - 交响乐 5.1 : LDAP Authentication with Entity User Provider

    node.js - Passport.js + Express.js 验证后将用户转发到原始目的地

    security - 在 Symfony 中重写 login_check 功能

    javascript - Angular ui-router,可以在其他解析之前解析身份验证检查吗?