rodauth-rails 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +589 -0
- data/lib/generators/rodauth/install_generator.rb +65 -0
- data/lib/generators/rodauth/mailer_generator.rb +38 -0
- data/lib/generators/rodauth/templates/app/controllers/rodauth_controller.rb +3 -0
- data/lib/generators/rodauth/templates/app/mailers/rodauth_mailer.rb +37 -0
- data/lib/generators/rodauth/templates/app/models/account.rb +2 -0
- data/lib/generators/rodauth/templates/config/initializers/rodauth.rb +3 -0
- data/lib/generators/rodauth/templates/config/initializers/sequel.rb +13 -0
- data/lib/generators/rodauth/templates/db/migrate/create_rodauth.rb +170 -0
- data/lib/generators/rodauth/templates/lib/rodauth_app.rb +186 -0
- data/lib/generators/rodauth/views_generator.rb +123 -0
- data/lib/rodauth/features/rails.rb +1 -0
- data/lib/rodauth/rails/app/flash.rb +50 -0
- data/lib/rodauth/rails/app.rb +45 -0
- data/lib/rodauth/rails/controller_methods.rb +20 -0
- data/lib/rodauth/rails/feature.rb +118 -0
- data/lib/rodauth/rails/middleware.rb +21 -0
- data/lib/rodauth/rails/railtie.rb +18 -0
- data/lib/rodauth/rails.rb +33 -0
- data/lib/rodauth-rails.rb +1 -0
- data/rodauth-rails.gemspec +22 -0
- metadata +147 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d146993e77acfbe027e5cfe399cc13cfe16d2e967d73b0caf149c1363a222b9b
|
4
|
+
data.tar.gz: f77401bec1bfabd12cb87285e3e6a42b9b7ca7bf0fb986a32b27babba7d49d72
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7592679984260110c5cd702601d9c9841fc5c5e8980790aad8bb223997851d06c43045361a91ab7ad6c7bb0b113a79bd52e26e5de3a488e7269cf1e3bdf2ecaa
|
7
|
+
data.tar.gz: 70fa3b31cffff7cecb98cf2951a35bd2dd4f6ca65cd4d9b49494d94be0858e73aa5d292d2292053d1b847921f05212b8c8d3b0b2ffd81aed4e191916749d4249
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Janko Marohnić
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,589 @@
|
|
1
|
+
# rodauth-rails
|
2
|
+
|
3
|
+
Provides Rails integration for the [Rodauth] authentication framework.
|
4
|
+
|
5
|
+
## Resources
|
6
|
+
|
7
|
+
* [Rodauth documentation](http://rodauth.jeremyevans.net/documentation.html)
|
8
|
+
* [rodauth-rails wiki](https://github.com/janko/rodauth-rails/wiki)
|
9
|
+
* [Rails demo](https://github.com/janko/rodauth-demo-rails)
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add the gem to your Gemfile:
|
14
|
+
|
15
|
+
```rb
|
16
|
+
gem "rodauth-rails", "~> 0.1"
|
17
|
+
```
|
18
|
+
|
19
|
+
Then run `bundle install`.
|
20
|
+
|
21
|
+
Next, run the install generator:
|
22
|
+
|
23
|
+
```
|
24
|
+
$ rails generate rodauth:install
|
25
|
+
```
|
26
|
+
|
27
|
+
The generator will create the following files:
|
28
|
+
|
29
|
+
* Rodauth migration at `db/migrate/*_create_rodauth.rb`
|
30
|
+
* Rodauth initializer at `config/initializers/rodauth.rb`
|
31
|
+
* Sequel initializer at `config/initializers/sequel.rb` for ActiveRecord integration
|
32
|
+
* Rodauth app at `lib/rodauth_app.rb`
|
33
|
+
* Rodauth controller at `app/controllers/rodauth_controller.rb`
|
34
|
+
* Account model at `app/models/account.rb`
|
35
|
+
|
36
|
+
### Migration
|
37
|
+
|
38
|
+
The migration file creates tables required by Rodauth. You're encouraged to
|
39
|
+
review the migration, and modify it to only create tables for features you
|
40
|
+
intend to use.
|
41
|
+
|
42
|
+
```rb
|
43
|
+
# db/migrate/*_create_rodauth.rb
|
44
|
+
class CreateRodauth < ActiveRecord::Migration
|
45
|
+
def change
|
46
|
+
create_table :accounts do |t| ... end
|
47
|
+
create_table :account_password_hashes do |t| ... end
|
48
|
+
create_table :account_password_reset_keys do |t| ... end
|
49
|
+
create_table :account_verification_keys do |t| ... end
|
50
|
+
create_table :account_login_change_keys do |t| ... end
|
51
|
+
create_table :account_remember_keys do |t| ... end
|
52
|
+
# ...
|
53
|
+
end
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
Once you're done, you can run the migration:
|
58
|
+
|
59
|
+
```
|
60
|
+
$ rails db:migrate
|
61
|
+
```
|
62
|
+
|
63
|
+
### Rodauth initializer
|
64
|
+
|
65
|
+
The Rodauth initializer assigns the constant for your Rodauth app, which will
|
66
|
+
be called by the Rack middleware that's added in front of your Rails router.
|
67
|
+
|
68
|
+
```rb
|
69
|
+
# config/initializers/rodauth.rb
|
70
|
+
Rodauth::Rails.configure do |config|
|
71
|
+
config.app = "RodauthApp"
|
72
|
+
end
|
73
|
+
```
|
74
|
+
|
75
|
+
### Sequel initializer
|
76
|
+
|
77
|
+
Rodauth uses [Sequel] for database interaction. If you're using ActiveRecord,
|
78
|
+
an additional initializer will be created which configures Sequel to use the
|
79
|
+
ActiveRecord connection.
|
80
|
+
|
81
|
+
```rb
|
82
|
+
# config/initializers/sequel.rb
|
83
|
+
require "sequel/core"
|
84
|
+
|
85
|
+
# initialize the appropriate Sequel adapter without creating a connection
|
86
|
+
DB = Sequel.postgres(test: false)
|
87
|
+
# have Sequel use ActiveRecord's connection for database interaction
|
88
|
+
DB.extension :activerecord_connection
|
89
|
+
```
|
90
|
+
|
91
|
+
### Rodauth app
|
92
|
+
|
93
|
+
Your Rodauth app is created in the `lib/` directory, which comes with a default
|
94
|
+
set of authentication features enabled, as well as extensive examples on ways
|
95
|
+
you can configure authentication behaviour.
|
96
|
+
|
97
|
+
```rb
|
98
|
+
# lib/rodauth_app.rb
|
99
|
+
class RodauthApp < Rodauth::Rails::App
|
100
|
+
configure do
|
101
|
+
# authentication configuration
|
102
|
+
end
|
103
|
+
|
104
|
+
route do |r|
|
105
|
+
# request handling
|
106
|
+
end
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
Note that Rails doesn't autoload files in the `lib/` directory by default, so
|
111
|
+
make sure to add `lib/` to your `config.autoload_paths`:
|
112
|
+
|
113
|
+
```rb
|
114
|
+
# config/application.rb
|
115
|
+
module YourApp
|
116
|
+
class Application < Rails::Application
|
117
|
+
# ...
|
118
|
+
config.autoload_paths += %W[#{config.root}/lib]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
### Controller
|
124
|
+
|
125
|
+
Your Rodauth app will by default use `RodauthController` for view rendering
|
126
|
+
and CSRF protection.
|
127
|
+
|
128
|
+
```rb
|
129
|
+
# app/controllers/rodauth_controller.rb
|
130
|
+
class RodauthController < ApplicationController
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
### Account Model
|
135
|
+
|
136
|
+
Rodauth stores user accounts in the `accounts` table, so the generator will
|
137
|
+
also create an `Account` model for custom use.
|
138
|
+
|
139
|
+
```rb
|
140
|
+
# app/models/account.rb
|
141
|
+
class Account < ApplicationRecord
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
## Getting started
|
146
|
+
|
147
|
+
Let's start by adding some basic authentication navigation links to our home
|
148
|
+
page:
|
149
|
+
|
150
|
+
```erb
|
151
|
+
<ul>
|
152
|
+
<% if rodauth.authenticated? %>
|
153
|
+
<li><%= link_to "Sign out", rodauth.logout_path, method: :post %></li>
|
154
|
+
<% else %>
|
155
|
+
<li><%= link_to "Sign in", rodauth.login_path %></li>
|
156
|
+
<li><%= link_to "Sign up", rodauth.create_account_path %></li>
|
157
|
+
<% end %>
|
158
|
+
</ul>
|
159
|
+
```
|
160
|
+
|
161
|
+
These links are fully functional, feel free to visit them and interact with the
|
162
|
+
pages. The templates that ship with Rodauth aim to provide a complete
|
163
|
+
authentication experience, and the forms use [Boostrap] markup.
|
164
|
+
|
165
|
+
Let's also add the `#current_account` method for retrieving the account of the
|
166
|
+
the authenticated session:
|
167
|
+
|
168
|
+
```rb
|
169
|
+
# app/controllers/application_controller.rb
|
170
|
+
class ApplicationController < ActionController::Base
|
171
|
+
private
|
172
|
+
|
173
|
+
def current_account
|
174
|
+
@current_account ||= Account.find(rodauth.session_value)
|
175
|
+
end
|
176
|
+
helper_method :current_account
|
177
|
+
end
|
178
|
+
```
|
179
|
+
```erb
|
180
|
+
<p>Authenticated as: <%= current_account.email %></p>
|
181
|
+
```
|
182
|
+
|
183
|
+
### Requiring authentication
|
184
|
+
|
185
|
+
Next, we'll likely want to require authentication for certain sections/pages of
|
186
|
+
our app. We can do this in our Rodauth app's routing block, which helps keep
|
187
|
+
the authentication logic encapsulated:
|
188
|
+
|
189
|
+
```rb
|
190
|
+
# lib/rodauth_app.rb
|
191
|
+
class RodauthApp < Rodauth::Rails::App
|
192
|
+
# ...
|
193
|
+
route do |r|
|
194
|
+
# ...
|
195
|
+
r.rodauth # route rodauth requests
|
196
|
+
|
197
|
+
# require authentication for /dashboard/* and /account/* routes
|
198
|
+
if r.path.start_with?("/dashboard") || r.path.start_with?("/account")
|
199
|
+
rodauth.require_authentication # redirect to login page if not authenticated
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
We can also require authentication at the controller layer:
|
206
|
+
|
207
|
+
```rb
|
208
|
+
# app/controllers/application_controller.rb
|
209
|
+
class ApplicationController < ActionController::Base
|
210
|
+
private
|
211
|
+
|
212
|
+
def authenticate
|
213
|
+
rodauth.require_authentication # redirect to login page if not authenticated
|
214
|
+
end
|
215
|
+
end
|
216
|
+
```
|
217
|
+
```rb
|
218
|
+
# app/controllers/dashboard_controller.rb
|
219
|
+
class DashboardController < ApplicationController
|
220
|
+
before_action :authenticate
|
221
|
+
end
|
222
|
+
```
|
223
|
+
```rb
|
224
|
+
# app/controllers/posts_controller.rb
|
225
|
+
class PostsController < ApplicationController
|
226
|
+
before_action :authenticate, except: [:index, :show]
|
227
|
+
end
|
228
|
+
```
|
229
|
+
|
230
|
+
Or at the Rails router level:
|
231
|
+
|
232
|
+
```rb
|
233
|
+
# config/routes.rb
|
234
|
+
Rails.application.routes.draw do
|
235
|
+
constraints -> (r) { r.env["rodauth"].require_authentication } do
|
236
|
+
namespace :admin do
|
237
|
+
# ...
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
```
|
242
|
+
|
243
|
+
### Views
|
244
|
+
|
245
|
+
The templates built into Rodauth are useful when getting started, but at some
|
246
|
+
point we'll probably want more control over the markup. For that we can run the
|
247
|
+
following command:
|
248
|
+
|
249
|
+
```sh
|
250
|
+
$ rails generate rodauth:views
|
251
|
+
```
|
252
|
+
|
253
|
+
This will generate views for the default set of Rodauth features into the
|
254
|
+
`app/views/rodauth` directory, which will be automatically picked up by the
|
255
|
+
`RodauthController`.
|
256
|
+
|
257
|
+
You can pass a list of Rodauth features to the generator to create views for
|
258
|
+
these features (this will not remove any existing views):
|
259
|
+
|
260
|
+
```sh
|
261
|
+
$ rails generate rodauth:views --features login create_account lockout otp
|
262
|
+
```
|
263
|
+
|
264
|
+
Or you can generate views for all features:
|
265
|
+
|
266
|
+
```sh
|
267
|
+
$ rails generate rodauth:views --all
|
268
|
+
```
|
269
|
+
|
270
|
+
You can also tell the generator to create views into another directory (in this
|
271
|
+
case don't forget to rename the Rodauth controller accordingly).
|
272
|
+
|
273
|
+
```sh
|
274
|
+
# generates views into app/views/authentication
|
275
|
+
$ rails generate rodauth:views --name authentication
|
276
|
+
```
|
277
|
+
|
278
|
+
#### Layout
|
279
|
+
|
280
|
+
To use different layouts for different Rodauth views, you can compare the
|
281
|
+
request path in the layout method:
|
282
|
+
|
283
|
+
```rb
|
284
|
+
class RodauthController < ApplicationController
|
285
|
+
layout :rodauth_layout
|
286
|
+
|
287
|
+
private
|
288
|
+
|
289
|
+
def rodauth_layout
|
290
|
+
case request.path
|
291
|
+
when rodauth.login_path,
|
292
|
+
rodauth.create_account_path,
|
293
|
+
rodauth.verify_account_path,
|
294
|
+
rodauth.reset_password_path,
|
295
|
+
rodauth.reset_password_request_path
|
296
|
+
"authentication"
|
297
|
+
else
|
298
|
+
"dashboard"
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
```
|
303
|
+
|
304
|
+
### Mailer
|
305
|
+
|
306
|
+
Rodauth may send emails as part of the authentication flow. Most email settings
|
307
|
+
can be customized:
|
308
|
+
|
309
|
+
```rb
|
310
|
+
# lib/rodauth_app.rb
|
311
|
+
class RodauthApp < Rodauth::Rails::App
|
312
|
+
# ...
|
313
|
+
configure do
|
314
|
+
# ...
|
315
|
+
# general settings
|
316
|
+
email_from "no-reply@myapp.com"
|
317
|
+
email_subject_prefix "[MyApp] "
|
318
|
+
send_email(&:deliver_later)
|
319
|
+
# ...
|
320
|
+
# feature settings
|
321
|
+
verify_account_email_subject "Verify your account"
|
322
|
+
verify_account_email_body { "Verify your account by visting this link: #{verify_account_email_link}" }
|
323
|
+
# ...
|
324
|
+
end
|
325
|
+
end
|
326
|
+
```
|
327
|
+
|
328
|
+
This is convenient when starting out, but eventually you might want to use your
|
329
|
+
own mailer. You can start by running the following command:
|
330
|
+
|
331
|
+
```sh
|
332
|
+
$ rails generate rodauth:mailer
|
333
|
+
```
|
334
|
+
|
335
|
+
This will create a `RodauthMailer` with the associated mailer views in
|
336
|
+
`app/views/rodauth_mailer` directory.
|
337
|
+
|
338
|
+
```rb
|
339
|
+
# app/mailers/rodauth_mailer.rb
|
340
|
+
class RodauthMailer < ApplicationMailer
|
341
|
+
def verify_account(recipient, email_link) ... end
|
342
|
+
def reset_password(recipient, email_link) ... end
|
343
|
+
def verify_login_change(recipient, old_login, new_login, email_link) ... end
|
344
|
+
def password_changed(recipient) ... end
|
345
|
+
# def email_auth(recipient, email_link) ... end
|
346
|
+
# def unlock_account(recipient, email_link) ... end
|
347
|
+
end
|
348
|
+
```
|
349
|
+
|
350
|
+
You can then uncomment the lines in your Rodauth configuration to have it call
|
351
|
+
your mailer. If you've enabled additional authentication features, make sure to
|
352
|
+
override their `send_*_email` methods as well.
|
353
|
+
|
354
|
+
```rb
|
355
|
+
# lib/rodauth_app.rb
|
356
|
+
class RodauthApp < Rodauth::Rails::App
|
357
|
+
# ...
|
358
|
+
configure do
|
359
|
+
# ...
|
360
|
+
send_reset_password_email do
|
361
|
+
RodauthMailer.reset_password(email_to, password_reset_email_link).deliver_now
|
362
|
+
end
|
363
|
+
send_verify_account_email do
|
364
|
+
RodauthMailer.verify_account(email_to, verify_account_email_link).deliver_now
|
365
|
+
end
|
366
|
+
send_verify_login_change_email do |login|
|
367
|
+
RodauthMailer.verify_login_change(login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link).deliver_now
|
368
|
+
end
|
369
|
+
send_password_changed_email do
|
370
|
+
RodauthMailer.password_changed(email_to).deliver_now
|
371
|
+
end
|
372
|
+
# send_email_auth_email do
|
373
|
+
# RodauthMailer.email_auth(email_to, email_auth_email_link).deliver_now
|
374
|
+
# end
|
375
|
+
# send_unlock_account_email do
|
376
|
+
# RodauthMailer.unlock_account(email_to, unlock_account_email_link).deliver_now
|
377
|
+
# end
|
378
|
+
# ...
|
379
|
+
end
|
380
|
+
end
|
381
|
+
```
|
382
|
+
|
383
|
+
## How it works
|
384
|
+
|
385
|
+
### Middleware
|
386
|
+
|
387
|
+
rodauth-rails inserts a `Rodauth::Rails::Middleware` into your middleware
|
388
|
+
stack, which calls your Rodauth app for each request, before the request
|
389
|
+
reaches the Rails router.
|
390
|
+
|
391
|
+
```sh
|
392
|
+
$ rails middleware
|
393
|
+
...
|
394
|
+
use Rodauth::Rails::Middleware
|
395
|
+
run MyApp::Application.routes
|
396
|
+
```
|
397
|
+
|
398
|
+
The Rodauth app stores the `Rodauth::Auth` instance in the Rack env hash, which
|
399
|
+
is then available in your Rails app:
|
400
|
+
|
401
|
+
```rb
|
402
|
+
request.env["rodauth"] #=> #<Rodauth::Auth>
|
403
|
+
request.env["rodauth.secondary"] #=> #<Rodauth::Auth> (if using multiple configurations)
|
404
|
+
```
|
405
|
+
|
406
|
+
For convenience, this object can be accessed via the `#rodauth` method in views
|
407
|
+
and controllers:
|
408
|
+
|
409
|
+
```rb
|
410
|
+
class MyController < ApplicationController
|
411
|
+
def my_action
|
412
|
+
rodauth #=> #<Rodauth::Auth>
|
413
|
+
rodauth(:secondary) #=> #<Rodauth::Auth> (if using multiple configurations)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
```
|
417
|
+
```erb
|
418
|
+
<% rodauth #=> #<Rodauth::Auth> %>
|
419
|
+
<% rodauth(:secondary) #=> #<Rodauth::Auth> (if using multiple configurations) %>
|
420
|
+
```
|
421
|
+
|
422
|
+
### App
|
423
|
+
|
424
|
+
The `Rodauth::Rails::App` class is a [Roda] subclass that provides Rails
|
425
|
+
integration for Rodauth:
|
426
|
+
|
427
|
+
* uses Rails' flash instead of Roda's
|
428
|
+
* uses Rails' CSRF protection instead of Roda's
|
429
|
+
* sets [HMAC] secret to Rails' secret key base
|
430
|
+
* uses ActionController for rendering templates
|
431
|
+
* uses ActionMailer for sending emails
|
432
|
+
|
433
|
+
The `configure { ... }` method wraps configuring the Rodauth plugin, forwarding
|
434
|
+
any additional [options].
|
435
|
+
|
436
|
+
```rb
|
437
|
+
configure { ... } # defining default Rodauth configuration
|
438
|
+
configure(json: true) # passing options to the Rodauth plugin
|
439
|
+
configure(:secondary) { ... } # defining multiple Rodauth configurations
|
440
|
+
```
|
441
|
+
|
442
|
+
### Sequel
|
443
|
+
|
444
|
+
Rodauth uses the [Sequel] library for database queries, due to more advanced
|
445
|
+
database usage (SQL expressions, database-agnostic date arithmetic, SQL
|
446
|
+
function calls).
|
447
|
+
|
448
|
+
If ActiveRecord is used in the application, the `rodauth:install` generator
|
449
|
+
will have automatically configured Sequel to reuse ActiveRecord's database
|
450
|
+
connection (using the [sequel-activerecord_connection] gem).
|
451
|
+
|
452
|
+
This means that, from the usage perspective, Sequel can be considered just
|
453
|
+
as an implementation detail of Rodauth.
|
454
|
+
|
455
|
+
## Configuring
|
456
|
+
|
457
|
+
For the list of configuration methods provided by Rodauth, see the [feature
|
458
|
+
documentation].
|
459
|
+
|
460
|
+
The `rails` feature rodauth-rails loads is customizable as well, here is the
|
461
|
+
list of its configuration methods:
|
462
|
+
|
463
|
+
| Name | Description |
|
464
|
+
| :---- | :---------- |
|
465
|
+
| `rails_render(**options)` | Renders the template with given render options. |
|
466
|
+
| `rails_csrf_tag` | Hidden field added to Rodauth templates containing the CSRF token. |
|
467
|
+
| `rails_csrf_param` | Value of the `name` attribute for the CSRF tag. |
|
468
|
+
| `rails_csrf_token` | Value of the `value` attribute for the CSRF tag. |
|
469
|
+
| `rails_check_csrf!` | Verifies the authenticity token for the current request. |
|
470
|
+
| `rails_controller_instance` | Instance of the controller with the request env context. |
|
471
|
+
| `rails_controller` | Controller class to use for rendering and CSRF protection. |
|
472
|
+
|
473
|
+
The `Rodauth::Rails` module has a few config settings available as well:
|
474
|
+
|
475
|
+
| Name | Description |
|
476
|
+
| :----- | :---------- |
|
477
|
+
| `app` | Constant name of your Rodauth app, which is called by the middleware. |
|
478
|
+
| `middleware` | Whether to insert the middleware into the Rails application's middleware stack. Defaults to `true`. |
|
479
|
+
|
480
|
+
```rb
|
481
|
+
# config/initializers/rodauth.rb
|
482
|
+
Rodauth::Rails.configure do |config|
|
483
|
+
config.app = "RodauthApp"
|
484
|
+
config.middleware = true
|
485
|
+
end
|
486
|
+
```
|
487
|
+
|
488
|
+
## Testing
|
489
|
+
|
490
|
+
If you're writing system tests, it's generally better to go through the actual
|
491
|
+
authentication flow with tools like Capybara, and to not use any stubbing.
|
492
|
+
|
493
|
+
In functional and integration tests you can just make requests to Rodauth
|
494
|
+
routes:
|
495
|
+
|
496
|
+
```rb
|
497
|
+
# test/controllers/posts_controller_test.rb
|
498
|
+
class PostsControllerTest < ActionDispatch::IntegrationTest
|
499
|
+
test "should require authentication" do
|
500
|
+
get posts_url
|
501
|
+
assert_redirected_to "/login"
|
502
|
+
|
503
|
+
login
|
504
|
+
get posts_url
|
505
|
+
assert_response :success
|
506
|
+
|
507
|
+
logout
|
508
|
+
assert_redirected_to "/login"
|
509
|
+
end
|
510
|
+
|
511
|
+
private
|
512
|
+
|
513
|
+
def login(login: "user@example.com", password: "secret")
|
514
|
+
post "/create-account", params: {
|
515
|
+
"login" => login,
|
516
|
+
"password" => password,
|
517
|
+
"password-confirm" => password,
|
518
|
+
}
|
519
|
+
|
520
|
+
post "/login", params: {
|
521
|
+
"login" => login,
|
522
|
+
"password" => password,
|
523
|
+
}
|
524
|
+
end
|
525
|
+
|
526
|
+
def logout
|
527
|
+
post "/logout"
|
528
|
+
end
|
529
|
+
end
|
530
|
+
```
|
531
|
+
|
532
|
+
## Rodauth defaults
|
533
|
+
|
534
|
+
rodauth-rails changes some of the default Rodauth settings for easier setup:
|
535
|
+
|
536
|
+
### Database functions
|
537
|
+
|
538
|
+
By default on PostgreSQL, MySQL, and Microsoft SQL Server, Rodauth uses
|
539
|
+
database functions to access password hashes, with the user running the
|
540
|
+
application unable to get direct access to password hashes. This reduces the
|
541
|
+
risk of an attacker being able to access password hashes and use them to attack
|
542
|
+
other sites.
|
543
|
+
|
544
|
+
While this is useful additional security, it is also more complex to set up and
|
545
|
+
to reason about, as it requires having two different database users and making
|
546
|
+
sure the correct migration is run for the correct user.
|
547
|
+
|
548
|
+
To keep with Rails' "convention over configuration" doctrine, rodauth-rails
|
549
|
+
disables the use of database functions, though it can still be turned back on.
|
550
|
+
|
551
|
+
### Account statuses
|
552
|
+
|
553
|
+
The recommended [Rodauth migration] stores possible account status values in a
|
554
|
+
separate table, and creates a foreign key on the accounts table, which ensures
|
555
|
+
only a valid status value will be persisted.
|
556
|
+
|
557
|
+
Unfortunately, this doesn't work when the database is restored from the schema
|
558
|
+
file, in which case the account statuses table will be empty. This happens in
|
559
|
+
tests by default, but it's also commonly done in development.
|
560
|
+
|
561
|
+
To address this, rodauth-rails modifies the setup to store account status text
|
562
|
+
directly in the accounts table. If you're worried about invalid status values
|
563
|
+
creeping in, you may use enums instead. Alternatively, you can still go back to
|
564
|
+
the setup recommended by Rodauth.
|
565
|
+
|
566
|
+
## License
|
567
|
+
|
568
|
+
The gem is available as open source under the terms of the [MIT
|
569
|
+
License](https://opensource.org/licenses/MIT).
|
570
|
+
|
571
|
+
## Code of Conduct
|
572
|
+
|
573
|
+
Everyone interacting in the rodauth-rails project's codebases, issue trackers,
|
574
|
+
chat rooms and mailing lists is expected to follow the [code of
|
575
|
+
conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
|
576
|
+
|
577
|
+
[Rodauth]: https://github.com/jeremyevans/rodauth
|
578
|
+
[Sequel]: https://github.com/jeremyevans/sequel
|
579
|
+
[rendering views outside of controllers]: https://blog.bigbinary.com/2016/01/08/rendering-views-outside-of-controllers-in-rails-5.html
|
580
|
+
[feature documentation]: http://rodauth.jeremyevans.net/documentation.html
|
581
|
+
[Rodauth plugin]: https://github.com/jeremyevans/rodauth/#label-Plugin+Options
|
582
|
+
[Bootstrap]: https://getbootstrap.com/
|
583
|
+
[Roda]: http://roda.jeremyevans.net/
|
584
|
+
[HMAC]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-HMAC
|
585
|
+
[database authentication functions]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Password+Hash+Access+Via+Database+Functions
|
586
|
+
[multiple configurations]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-With+Multiple+Configurations
|
587
|
+
[views]: /app/views/rodauth
|
588
|
+
[Rodauth migration]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Creating+tables
|
589
|
+
[sequel-activerecord_connection]: https://github.com/janko/sequel-activerecord_connection
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
require "rails/generators/migration"
|
3
|
+
require "rails/generators/active_record"
|
4
|
+
require "rodauth/version"
|
5
|
+
|
6
|
+
module Rodauth
|
7
|
+
module Rails
|
8
|
+
module Generators
|
9
|
+
class InstallGenerator < ::Rails::Generators::Base
|
10
|
+
include ::Rails::Generators::Migration
|
11
|
+
|
12
|
+
source_root "#{__dir__}/templates"
|
13
|
+
namespace "rodauth:install"
|
14
|
+
|
15
|
+
def create_rodauth_migration
|
16
|
+
return unless defined?(ActiveRecord::Base)
|
17
|
+
|
18
|
+
migration_template "db/migrate/create_rodauth.rb", "db/migrate/create_rodauth.rb"
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_rodauth_initializer
|
22
|
+
template "config/initializers/rodauth.rb"
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_sequel_initializer
|
26
|
+
return unless defined?(ActiveRecord::Base)
|
27
|
+
return unless %w[postgresql mysql2 sqlite3].include?(adapter)
|
28
|
+
|
29
|
+
template "config/initializers/sequel.rb"
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_rodauth_app
|
33
|
+
template "lib/rodauth_app.rb"
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_rodauth_controller
|
37
|
+
template "app/controllers/rodauth_controller.rb"
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_account_model
|
41
|
+
return unless defined?(ActiveRecord::Base)
|
42
|
+
|
43
|
+
template "app/models/account.rb"
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# required by #migration_template action
|
49
|
+
def self.next_migration_number(dirname)
|
50
|
+
ActiveRecord::Generators::Base.next_migration_number(dirname)
|
51
|
+
end
|
52
|
+
|
53
|
+
def migration_version
|
54
|
+
if ActiveRecord.version >= Gem::Version.new("5.0.0")
|
55
|
+
"[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def adapter
|
60
|
+
ActiveRecord::Base.connection_config.fetch(:adapter)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|