问题
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