Sinatra/Rack的一个非常简单的身份验证方案是什么?

40

我正忙着将一个非常小的Web应用程序从ASP.NET MVC 2转移到Ruby/Sinatra。

在MVC应用程序中,使用FormsAuthentication.SetAuthCookie来在用户登录正确验证通过后设置一个持久化cookie。

我想知道Sinatra中Forms Authentication的等效物是什么?所有身份验证框架似乎都非常笨重,不是我所需要的。


4
虽然我不打算假装这个回答能回答你的问题,但我要指出自己设计和开发身份验证方案本质上是很危险的。一旦被黑客发现,他们就会变得异常兴奋。最好找一些已经被验证过的工具来解决这个问题。这并不是一个新问题,已经有很多可行的解决方案存在。 - user483040
使用bcrypt gem。它可以为密码生成加密哈希,如果黑客访问了您的数据库,他们只能获取哈希值,而不能获得密码。换句话说,让它成为单向的。你会经常看到bcrypt-ruby,但现在它只是bcrypt,并且是C扩展类型,所以你需要在Windows上编译并添加一些开发工具。你说得对,它们很笨重。https://sideprojectsoftware.com/blog/2015/02/22/sinatra-authentication应该会有所帮助。 - Douglas G. Allen
5个回答

77

这是Sinatra的一个非常简单的身份验证方案。

我将在下面解释它是如何工作的。

class App < Sinatra::Base
  set :sessions => true

  register do
    def auth (type)
      condition do
        redirect "/login" unless send("is_#{type}?")
      end
    end
  end

  helpers do
    def is_user?
      @user != nil
    end
  end

  before do
    @user = User.get(session[:user_id])
  end

  get "/" do
    "Hello, anonymous."
  end

  get "/protected", :auth => :user do
    "Hello, #{@user.name}."
  end

  post "/login" do
    session[:user_id] = User.authenticate(params).id
  end

  get "/logout" do
    session[:user_id] = nil
  end
end
对于任何你想要保护的路由,都需要添加:auth => :user条件,就像上面的/protected示例中一样。这将调用auth方法,通过condition向路由添加条件。
该条件调用了is_user?方法,该方法已定义为辅助函数。该方法应根据会话是否包含有效帐户ID返回true或false。(动态调用这样的辅助程序,可以轻松地添加其他类型的用户,具有不同的特权。)
最后,before处理程序为每个请求设置一个@user实例变量,以便在显示每个页面顶部的用户名称等内容时使用。您还可以在视图中使用is_user?辅助函数来确定用户是否已登录。

首先,感谢您提供如此周到的回复!其次,我忘了提到,如果我能够拥有持久会话,那就太好了。我假设如果我像下面这样做,那么这将允许会话保持持久性?Rack::Session::Cookie, :secret => "一些非常独特的值"如果是这种情况,这种方法是否存在任何安全问题? - AndrewVos
美丽,一个使用更多Sinatra可爱的DSL的机会 :) - Paul Y
1
但是用户凭据(用户名和密码)存储在哪里? 我们如何首先创建一个用户账户,以便他/她可以进行身份验证! - Hanynowsky

31

Todd的答案对我无效,我在Sinatra的FAQ中找到了一个更简单的方案,用于一次性非常简单的身份验证:

require 'rubygems'
require 'sinatra'

use Rack::Auth::Basic, "Restricted Area" do |username, password|
    [username, password] == ['admin', 'admin']  
end

get '/' do
    "You're welcome"
end

我认为我应该分享一下,以防有人遇到此问题并需要一个非持久化的解决方案。


4
Todd的回答本身并不可行,因为它不完整,而不是因为它是错误的。相反,这是一个相当精密和深思熟虑的解决方案,只是缺少一个App.run!在结尾,当然还需要实际实现User类(负责凭证管理)。 - p4010

8

2
第一个链接已经失效了。看起来这个链接:https://sklise.com/2013/03/08/sinatra-warden-auth/ 是可用的。 - microspino

1

我使用了被接受的答案来开发一个只有两个密码(一个是用户密码,一个是管理员密码)的应用程序。我创建了一个登录表单,用户输入密码(或者PIN码),并将其与我在Sinatra设置中设置的密码进行比较(一个用于管理员,一个用于用户)。然后根据用户输入的密码,将session[:current_user]设置为管理员或用户,并进行相应的授权。我甚至不需要一个用户模型。但我确实需要像这样做一些事情:

use Rack::Session::Cookie, :key => 'rack.session',
                       :domain => 'foo.com',
                       :path => '/',
                       :expire_after => 2592000, # In seconds
                       :secret => 'change_me'

sinatra文档所述,为了使会话在Chrome中持久存在,需要在主文件中添加此代码。添加后,会话按预期进行持久化。


0

我发现JWT是我一直在寻找的简单、现代/安全的解决方案。OP提到了庞大的框架,所以为了参考,我下载了最新版本(2.2.3)的jwt gem标签,压缩后大小为73 KB,解压后大小为191 KB。看起来维护得很好,并且在GitHub上开源。

这里有一篇关于它的好博客文章,包含代码和逐步指南,适合初学者:https://auth0.com/blog/ruby-authentication-secure-rack-apps-with-jwt/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接