Skip to content

Commit e4d473b

Browse files
author
Alexei
committed
doc and config generator
1 parent 5afc00a commit e4d473b

File tree

2 files changed

+143
-163
lines changed

2 files changed

+143
-163
lines changed

README.md

Lines changed: 125 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,37 @@
11
JWT Authentication
22
===========================
33

4-
This is mix of Simple Token Authentication and JWT.
5-
64
[devise]: https://github.com/plataformatec/devise
75
[jwt-gem]: https://github.com/progrium/ruby-jwt
6+
[sta-gem]: https://github.com/gonzalo-bulnes/simple_token_authentication
7+
8+
This is mix of [Simple Token Authentication][sta-gem] and [JWT][jwt-gem], based on [Devise][devise].
9+
10+
11+
12+
* [Installation](#installation)
13+
* [Using](#using)
14+
* [Configuring](#configuring)
15+
* [Authentication](#authentication)
16+
* [Devise](#devise)
817

918
Installation
10-
------------
19+
-----
1120

12-
Install [Devise][devise] with any modules you want, then add the gem to your `Gemfile`:
21+
Add the gem to your `Gemfile`:
1322

1423
```ruby
1524
# Gemfile
1625

17-
gem 'jwt_authentication'
26+
gem 'jwt_authentication', github: 'Rezonans/jwt_authentication'
1827
```
1928

20-
### Make models token authenticatable
29+
Using
30+
-----
31+
32+
### Models
33+
34+
Make models token authenticatable
2135

2236
#### ActiveRecord
2337

@@ -43,47 +57,85 @@ class User < ActiveRecord::Base
4357
end
4458
```
4559

60+
Method `acts_as_jwt_authenticatable` extends Model with several methods: `:jwt_token`, `:generate_authentication_token!`
61+
and some others. Obviously, `jwt_token` returns token for current record and `:generate_authentication_token!` updates record with new authentication_token.
62+
4663
If the model or models you chose have no `:authentication_token` attribute, add them one (with an index):
4764

4865
```bash
4966
rails g jwt_authentication MODEL
5067
```
5168
This will add 'acts_as_jwt_authenticatable' to specified MODEL. Also, this will generate migration for adding 'authentication_token' to MODEL.
52-
To skip generating migration, add '-m' parameter: rails g jwt_authentication User -m
69+
To skip generating migration, add '-m' parameter: rails g jwt_authentication User -m.
70+
Migration looks like:
71+
```ruby
72+
def change
73+
add_column :users, :authentication_token, :string
74+
add_index :users, :authentication_token
75+
end
76+
```
5377

5478

5579
### Allow controllers to handle jwt authentication
5680

57-
Finally define which controllers will handle jwt authentication (typ. `ApplicationController`) for which _jwt authenticatable_ models:
81+
Define controllers, which will handle jwt authentication (typ. `HomeController`) for which _jwt authenticatable_ models:
5882

5983
```ruby
60-
# app/controllers/application_controller.rb
84+
# app/controllers/home_controller.rb
6185

62-
class ApplicationController < ActionController::Base # or ActionController::API
86+
class HomeController < ActionController::Base # or ActionController::API
6387
# ...
6488

6589
acts_as_jwt_authentication_handler
6690
# Note: you can specify several parameters for handling authentication for this controller:
67-
# :model (which "acts as jwt authenticatable") for authenticating
68-
#
69-
# :key_field. Name of the field in _payload_ of decoded jwt. Entity will be searched in database by this field.
70-
#
71-
# :before_filter. Should the before_filter (with selected authenticate method) be injected in controller.
72-
#
73-
# :fallback. What to do, if jwt_authentication falls.
74-
#
75-
# :sign_in. How to authenticate entity in controller.
91+
# :models (which "acts as jwt authenticatable") for authenticating, hash, that specifies models
92+
# and those authentication parameters :header_name, :param_name, :sign_in
7693
#
7794
# example:
78-
# acts_as_jwt_authentication_handler model: :terminal, before_filter: true, fallback: :none, key_field: :id, sign_in: :simplified
95+
# acts_as_jwt_authentication_handler models: {terminal: {header_name: 'terminal_auth_token',
96+
# param_name: 'X-Auth-Terminal-Token',
97+
# sign_in: :simplified}
7998
#
8099
# ...
81100
end
82101
```
83-
See detailed parameters description in [Configuration](#configuration)
84102

85-
Configuration
86-
-------------
103+
Method `acts_as_jwt_authentication_handler` extends controller with methods: `:jwt_authenticate_user`, `::jwt_authenticate_user!` and some others.
104+
Instead of _user_ there will be specified model names, pair of methods for each model.
105+
106+
See detailed parameters and methods description in [Authentication](#authentication)
107+
108+
Atfer controller was extended with jwt_authentication helpers, you may authenticate entity in actions or in before filter:
109+
110+
```ruby
111+
class TerminalsController < ActionController
112+
acts_as_jwt_authentication_handler models: {terminal: {sign_in: :simlified}}
113+
before_filter :jwt_authenticate_terminal!
114+
115+
def show
116+
@terminal
117+
end
118+
119+
end
120+
121+
```
122+
123+
### Routing
124+
125+
Define devise routes for creating devise mapping.
126+
127+
```ruby
128+
# config/routes.rb
129+
130+
...
131+
devise_for :users, module: :jwt_authentication
132+
...
133+
134+
```
135+
Devise routing is necessary, because it creates devise mappings.
136+
137+
Configuring
138+
------
87139

88140
Some aspects of the behavior of _Jwt Authentication_ can be customized with an initializer.
89141
Below is an example with reasonable defaults:
@@ -93,30 +145,16 @@ Below is an example with reasonable defaults:
93145

94146
JwtAuthentication.configure do |config|
95147
#
96-
# # Configure model, that will be default for `acts_as_jwt_authentication_handler` calling.
148+
# # Configure models, that will be default for `acts_as_jwt_authentication_handler` calling.
97149
# # Note: specified model should have `authentication_token` attribute (Model should "act as jwt authenticatable")
98-
# config.model = :user
99-
#
100-
# # Configure default fallback, that will be default for `acts_as_jwt_authentication_handler` calling.
101-
# # Possible values: :none, :devise, :response, :error
102-
# config.fallback = :none
103-
#
104-
# # Configure default sign_in authentication reaction, that will be default for `acts_as_jwt_authentication_handler` calling.
105-
# # Possible values: :devise, :devise_session, :simplified
106-
# config.sign_in = :devise
107-
#
108-
# # Configure default before_filter injection mark, that will be default for `acts_as_jwt_authentication_handler` calling.
109-
# # True - inject, false - do not inject.
110-
# config.before_filter = true
111-
#
112-
# # Configure default key_field, that will be default for `acts_as_jwt_authentication_handler` calling.
113-
# # Value of this filed will be searched in payload if received jwt, entity fill by searched by this field :
114-
# # token: { email: [email protected] } # decoded jwt
115-
# # `model.where(key_field => key).first` # entity search
116-
# config.key_field = :email
117-
#
118-
# # Configure default header and parameter names for searching jwt in request.
119-
# config.header_names = { user: { jwt_header_name: 'X-User-JWT', jwt_param_name: 'user_jwt' } }
150+
# # header_name - name of header to search auth_token in request
151+
# # param_name - name of parameters to search auth_token in request
152+
# # sign_in - method to be executed if authentication success, possible values: :devise, :simplified
153+
# # if :devise selected, devises method sign_in() will be called at success authentication,
154+
# # if :simplified selected, instance variable with name of resource will be set (@user or @terminal)
155+
# config.models = {user: {header_name: 'X-User-Token',
156+
# param_name: 'user_token',
157+
# sign_in: :devise}}
120158
#
121159
# # Configure mark of jwt timeout verification
122160
# config.jwt_timeout_verify = true
@@ -126,102 +164,61 @@ JwtAuthentication.configure do |config|
126164
#
127165
# # Configure jwt timeout for simple login (without "remember me)
128166
# # Devise SessionsController generates jwt according to this parameter
167+
# # * This parameter may be overridden in each model:
168+
# # acts_as_jwt_authenticatable jwt_timeout: 10.minutes
129169
# config.jwt_timeout = 20.minutes
130170
#
131171
# # Configure jwt timeout for session login (with "remember me)
132172
# # Devise SessionsController generates jwt according to this parameter
173+
# # * This parameter may be overridden in each model:
174+
# # acts_as_jwt_authenticatable jwt_timeout_remember_me: 1.week
133175
# config.jwt_timeout_remember_me = 1.month
134176
#
135-
# # Configure list of controller actions not to be authenticated with jwt_authentication
136-
# # Example:
137-
# # {'Devise::SessionsController' => [:create, :destroy],
138-
# # 'Devise::RegistrationsController' => [:create],
139-
# # 'Devise::PasswordsController' => [:create, :update],
140-
# # 'Devise::ConfirmationsController' => [:create, :show]}
141-
# config.jwt_skip_authentication_for = {}
177+
# # Configure list of model keys, to be stored in jwt payload.
178+
# # Also, record we be searched by this fields at authentication.
179+
# # * This parameter may be overridden in each model:
180+
# # acts_as_jwt_authenticatable key_fields: [:email, :id]
181+
# config.key_fields = [:email]
142182
#
143183

144184
end
145-
146-
# # Configure list of Devise Controllers to be overridden. Those controllers will work via JSON.
147-
# # Note: request should contain 'Accept' header, that has 'application/json' value
148-
# # Possible controllers list: %i{registrations confirmations passwords sessions}
149-
# JwtAuthentication.override_devise_controllers [:sessions, :passwords]
150-
151185
```
152-
You'll find details for `:fallback` parameters in in [Fallback](#fallback)
153-
You'll find details for `:sign_in` parameters in in [Sign in](#sign-in)
154186

155-
Usage
187+
Authentication
156188
-----
157189

158-
### Tokens Generation
159-
160-
Assuming `user` is an instance of `User`, which is _jwt authenticatable_: each time `user` will be saved, and `user.authentication_token.blank?` it receives a new and unique authentication token (via `Devise.friendly_token`).
161-
162-
### Authentication Method 1: Query Params
163-
164-
You can authenticate passing the `user_token` params as query params:
165-
166-
```
167-
GET https://secure.example.com?user_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJ...iGhux7wDwM_QFpU
168-
```
169-
170-
The _token authentication handler_ (e.g. `ApplicationController`) will perform the user sign in if both are correct.
171-
172-
### Authentication Method 2: Request Headers
173-
174-
You can also use request headers (which may be simpler when authenticating against an API):
175-
176-
```
177-
X-User-Token eyJ0eXAiOiJKV1QiLCJhbGciOiJ...iGhux7wDwM_QFpU
178-
```
179-
180-
Authentication process
190+
As there was mentioned in [Using](#using), method `acts_as_jwt_authentication_handler` add to controller two methods:
191+
`:jwt_authenticate_user` and `:jwt_authenticate_user!`. Method with bang raises error, if authentication falls,
192+
method without bang do nothing if authentication falls.
193+
Authentication process in primitive simple:
194+
* Analize request - try to find token in params or header. If token not found, authentication falls.
195+
* Read payload from jwt
196+
* Search for entity by field, that payload contains. If entity not found, authentication falls.
197+
* Decode jwt with entities `authentication_token` (private key, that is stored as entities field).
198+
If `jwt_timeout_verify` specified, timeout verification will take place also.
199+
* If token successfully verified - _sign_in handler_ will be called, otherwise authentication falls.
200+
201+
`sign_in_handler`. You may specify, what to do at success authentication in `sign_in` parameter in model:
202+
```ruby
203+
# config/initializers/jwt_authentication.rb
204+
...
205+
config.models = {user: {sign_in: :devise}}
206+
...
207+
```
208+
There are 2 variants:
209+
* `:devise` (default) - `:sign_in` (devise controller method) will be called
210+
* `:simplified` - create instance variable with resource name (@user, @terminal, etc).
211+
212+
Devise
181213
-----
182214

183-
### Authentication methods
184-
185-
`acts_as_jwt_authentication_handler` method in controller will generate and add 4 auth method for controller.
186-
Each of them will try to authenticate entity with.
187-
The difference is in then behavior at auth falling: it matches fallback parameter in config:
188-
189-
* `:authenticate_user_by_jwt` - fallback: :`none`
190-
* `:authenticate_user_by_jwt!` - fallback: :`error`
191-
* `:authenticate_user_by_jwt_and_devise` fallback: :`devise`
192-
* `:authenticate_user_by_jwt_with_response` fallback: :`response`
193-
Instead of user there`ll be name of specified model
194-
Detailed info about fallback is in [Fallback](#fallback)
195-
196-
If parameter `before_filter` set to true, one of this methods (it depends on `fallback`) will be set as before_filter
197-
198-
You may set one of this method in any action:
215+
JwtAuthentication inherits devise controllers: Registrations, Confirmations, Sessions, Passwords.
216+
So, you can extend this functionality with inheritance or overriding some of them.
217+
Note, that you need to specify routes to this inherited controllers, like this:
199218
```ruby
200-
class GroupsController < ApplicationController
201-
def index
202-
authenticate_user_by_jwt!
203-
render json: current_user.groups
204-
end
205-
end
206-
```
207-
208-
### Sign in
209-
Jwt Authentication supports 3 variants of authentication - _:devise_, _:devise_with_session_, _:simplified_
210-
* `:devise` _(default)_ standard devise _sign_in_ call with _entity_m, that was authenticated
211-
* `:devise_with_session` the same as _:devise_, but with saving devise session
212-
* `:simplified` just creates `@user` (or other specified @entity) controller instance variable
219+
# config/routes.rb
220+
...
221+
devise_for :users, module: :jwt_authentication
222+
...
213223

214-
### Fallback
215-
There are 4 variants of fallback - `:none`, `:devise`, `:response`, `:error`
216-
* `:none` _(default)_ nothing happens if entity could not be authenticated
217-
* `:devise` control is given to devise strategies
218-
* `:response` process will be interrupted and 'not authenticated' error is returned in json
219-
* `:error` process will be interrupted with NotAuthenticated error throwing
220-
221-
Devise controllers
222-
-----
223-
224-
You may override Devise controllers for working via JSON.
225-
For doing this, uncomment `override_devise_controllers` method in _jwt_authentication.rb_ initializer and specify controllers to be overridden.
226-
`override_devise_controllers` will create alias method chains for needed actions: create -> create_with_token, create_without_token, etc.
227-
Dependently on accept headers in request, actions will be called. IF _json_ was requested, create_with_token will be called, create_without_token otherwise.
224+
```

0 commit comments

Comments
 (0)