Exclude some paths from global authentication in Sinatra

我与影子孤独终老i 提交于 2020-01-03 01:35:08

问题


I have an API in Sinatra, using a middleware doing a global restrict authentication with token. This middleware inserts the authentication check in a before statement, in order to protect everything globally without the need to add a check in each route definition.

before do
  denied unless
    authorized? or
    env['PATH_INFO'] == '/auth/login' or
    env['REQUEST_METHOD'] == 'OPTIONS' # For AngularJS headers checks
end

But now I have some routes I need to exclude from this global restrictions (only 2 or 3 on tens) and don't know how to do that.

I first think about Sinatra conditions : http://www.sinatrarb.com/intro.html#Conditions but since it's in a before statements, I'm unable to take action to avoid that before.

I then found this solution : Before filter on condition

But it's not really a clean way to do it and it can't work for me with middlewares and a modular Sinatra app.

So after having searching a lot, I need some help and advices.

How to do that, maybe with helpers, conditions, and some modifications in my middleware ?


回答1:


Why not put the list of routes that need no authorisation into an array and check it?

configure do
  set :no_auth_neededs, ['/auth/login', "/a", "/b", "/c"]
end

before do
  denied unless
    authorized? or
    settings.no_auth_neededs.include?(env['PATH_INFO']) or
    env['REQUEST_METHOD'] == 'OPTIONS' # For AngularJS headers checks
end

I haven't tested this.


Update:

There are two other ways I can think of doing this that my laziness doesn't whine about, if I put in 10 seconds of thinking time… but I'm happy to trust intuition :)

Extending the DSL

Write an authorised_route handler:

require 'sinatra/base'

module Sinatra
  module AuthorisedRoute
    def authorised_route(verb,path,&block)
      before path do
        denied unless
          authorized? or
          request.request_method == 'OPTIONS' # For AngularJS headers checks
      end
      send verb.to_sym, path, &block
    end
  end

  register AuthorisedRoute
end

class API < Sinatra::Base
  register AuthorisedRoute

  authorised_route "get", "/blah" do
    # blah
  end

  get "/free-route" do
    # blah
  end
end

You could remove that before block and just put the logic in the route, YMMV. There's lots of ways to use this kind of thing. Note the replacement of env with request (see Accessing the Request Object)

See the docs for more on DSL extensions

Use a class

Separate out the two types of route, that's what classes are for, groups of things that share attributes and/or behaviour:

require 'sinatra/base'

class AuthedAPI < Sinatra::Base

  before do
    denied unless
      authorized? or
      request.request_method == 'OPTIONS' # For AngularJS headers checks
  end

  # you should probably add the `denied` and `authorized?` helpers too

  # list of routes follow…
end

# define route that don't need auth in here
class OpenAPI < Sinatra::Base
  get "/auth/login" do
    # stuff…
  end
end

class API < Sinatra::Base
  use OpenAPI  # put OpenAPI first or a `denied` will happen.
  use AuthedAPI
end

and then map the API to "/" (or whatever the API's root path is) in the rackup file. Only the routes in AuthedAPI will be subject to the before block.



来源:https://stackoverflow.com/questions/25604380/exclude-some-paths-from-global-authentication-in-sinatra

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!