Sinatra - API - Authentication

后端 未结 3 1791
孤城傲影
孤城傲影 2020-12-22 17:28

We going to develop a little API application in Sinatra. What are the authentication options available to secure the API calls?

相关标签:
3条回答
  • 2020-12-22 17:49

    http://www.secondforge.com/blog/2014/11/05/simple-api-authentication-in-sinatra/ has a slightly more detailed answer that uses user tokens.

    This is one step more complicated than an API key, but is necessary if your API needs authentication to log in a user to do things such as editing a name/email/password, or accessing per-user information. (i.e. "private" API actions). You can also revoke/expire user tokens to let people log out, etc.

    class App < Sinatra::Base
    
      before do
        begin
          if request.body.read(1)
            request.body.rewind
            @request_payload = JSON.parse request.body.read, { symbolize_names: true }
          end
        rescue JSON::ParserError => e
          request.body.rewind
          puts "The body #{request.body.read} was not JSON"
        end
      end
    
      post '/login' do
        params = @request_payload[:user]
    
        user = User.find(email: params[:email])
        if user.password == params[:password] #compare the hash to the string; magic
          #log the user in
        else
          #tell the user they aren't logged in
        end
      end
    end
    

    (It's worth to note that it's more common to read credentials from an HTTP header instead of the JSON body, but the author mentions that.)

    0 讨论(0)
  • 2020-12-22 17:50

    Sinatra has no built-in authentication support. There are some gems available, but most are designed for user authentication (i.e. for a website). For an API, they seem like overkill. It’s easy enough to make your own. Simply check the request params in each of your routes to see if they contain a valid API key, and if not, return a 401 error.

    helpers do
      def valid_key? (key)
        false
      end
    end
    
    get "/" do
      error 401 unless valid_key?(params[:key])
    
      "Hello, world."
    end
    
    #  $ irb -r open-uri
    #  >> open("http://yourapp.com/api/?key=123")
    #  OpenURI::HTTPError: 401 Unauthorized
    

    Nothing after the call to error will happen if your valid_key? method returns false — error calls halt internally, which stops the request from continuing.

    Of course, it’s not ideal to repeat the check at the beginning of each route. Instead, you can create a small extension that adds conditions to your routes:

    class App < Sinatra::Base
      register do
        def check (name)
          condition do
            error 401 unless send(name) == true
          end
        end
      end
    
      helpers do
        def valid_key?
          params[:key].to_i % 2 > 0
        end
      end
    
      get "/", :check => :valid_key? do
        [1, 2, 3].to_json
      end
    end
    

    If you just want authentication on all your routes, use a before handler:

    before do
      error 401 unless params[:key] =~ /^xyz/
    end
    
    get "/" do
      {"e" => mc**2}.to_json
    end
    
    0 讨论(0)
  • 2020-12-22 18:01

    Update

    Nowadays Token Based Authentication are getting popular. I'd recommend to use the ruby implementation of the JWT Standard by ruby-jwt for simple authentication and authorization.

    gem 'jwt'
    
    0 讨论(0)
提交回复
热议问题