Access Level for him and her
by: Federico Saravia Barrantes @fsaravia and Lautaro Orazi @tarolandia
Introduction
"Vinyl" is a simple gem that allows developers to define different access levels for a resource and a series of local and global validators to gain access to those levels. It works by analyzing a series of validators defined by you and returning a number representing the access level a particular request is able to reach.
What is it useful for?
This gem is useful when you need to control the output of a process depending on who wants to access to a resource.
For example: user A wants to get user B's profile.
- If A == B, then A has full access to data
- If A is friend of B, than A can see private data but not config data
- If A is not friend of B, then A only can see public data
In this example we have 3 different levels of access to B's information.
Install
gem install vinyl
Basic Config
require 'vinyl'
Vinyl.configure do |config|
config.api_acl_mode = Vinyl::Configuration::STRATEGY_DESCENDING
config.force_access_control = true
config.warn_on_missing_validators = true
end
:api_acl_mode can take two values:
- Vinyl::Configuration::STRATEGY_DESCENDING, Check for validators starting on the highest access level
- Vinyl::Configuration::STRATEGY_ASCENDING, Check for validators starting on the lowest access level
:force_access_control true/false
Deny access if no validators are given for a route/method combination and no global validators exist
:warn_on_missing_validators true/false
Display a warning on STDOUT when calling a non-existent validator (Missing validators output always default to false)
Defining Rules
A rule defines the access level and the validators for a route/method combination:
Vinyl.when_route
'/api/route',
:with_method => 'POST|GET|PUT|DELETE',
:get_access_level => 1...n,
:if_pass => ['validator1', 'validator2', …, 'validatorn']
Example:
Vinyl.when_route '/profiles.json',
:with_method => 'GET',
:get_access_level => 1,
:if_pass => ['is_user']
Vinyl.when_route '/profiles.json',
:with_method => 'GET',
:get_access_level => 2,
:if_pass => ['is_admin']
You can define your routes using a string, they may include wildcards or you can also use regular expressions:
Example:
Vinyl.when_route '/profiles*',
:with_method => 'GET',
:get_access_level => 1,
:if_pass => ['is_user']
Vinyl.when_route /^\/profiles\/(\d+)\.(.+)/,
:with_method => 'GET',
:get_access_level => 1,
:if_pass => ['is_user']
Defining validators
There are two kinds of validators: global and normal validators. All validators you define must return true or false.
Global validators will be applied to every rule. You can add a global validator using add_global_validator method:
Vinyl.add_global_validator("name_of_global_validator", lambda {
# your code here
return true/false
})
Normal validators will be applied when a rule includes it into its validators list. Validators can be added using add_validator method:
Vinyl.add_validator("name_of_validator", lambda {
# your code here
return true/false
})
Defining Variables
Inside validators you can use your models, classes and whatever. If you want a custom variable to be available in the scope of the validators, add it this way:
Vinyl.my_variable = variable_value
Inside your validator:
Vinyl.add_validator("my_validator", lambda {
puts my_variable # will output variable_value
return true/false
})
Clearing Variables
If you need to reset previously defined variables to avoid validation errors just call:
Vinyl.reset_variables
Getting Access Level
At this point you had defined your rules, validators and variables. Now you are ready to check for the access level.
access_level = Vinyl.check_level('/call/route','call_method')
If you need to avoid a global validator you can use bypass method:
access_level = Vinyl.bypass("global_validator_name").check_level('/call/route','call_method')
or a list of them
access_level = Vinyl.bypass(["global_1","global_2"]).check_level('/call/route','call_method')
Using bypass means exclude the validators only for the current check.
License
See the UNLICENSE
file included with this gem distribution.