rodauth-rails 0.17.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +80 -0
- data/README.md +224 -548
- data/lib/generators/rodauth/install_generator.rb +40 -35
- data/lib/generators/rodauth/migration/base.erb +8 -2
- data/lib/generators/rodauth/migration_generator.rb +9 -2
- data/lib/generators/rodauth/templates/INSTRUCTIONS +40 -0
- data/lib/generators/rodauth/templates/app/mailers/rodauth_mailer.rb +36 -19
- data/lib/generators/rodauth/templates/app/misc/rodauth_app.rb +38 -0
- data/lib/generators/rodauth/templates/app/{lib/rodauth_app.rb → misc/rodauth_main.rb} +10 -53
- data/lib/generators/rodauth/templates/app/views/rodauth/_email_auth_request_form.html.erb +7 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_form.html.erb +26 -9
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_form_footer.html.erb +7 -6
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_form_header.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb +7 -5
- data/lib/generators/rodauth/templates/app/views/rodauth/change_login.html.erb +29 -6
- data/lib/generators/rodauth/templates/app/views/rodauth/change_password.html.erb +29 -6
- data/lib/generators/rodauth/templates/app/views/rodauth/close_account.html.erb +15 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/confirm_password.html.erb +13 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/create_account.html.erb +37 -7
- data/lib/generators/rodauth/templates/app/views/rodauth/email_auth.html.erb +7 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/login.html.erb +5 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/logout.html.erb +16 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/multi_phase_login.html.erb +5 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/otp_auth.html.erb +17 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/otp_disable.html.erb +15 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/otp_setup.html.erb +30 -10
- data/lib/generators/rodauth/templates/app/views/rodauth/recovery_auth.html.erb +13 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/recovery_codes.html.erb +15 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/remember.html.erb +14 -9
- data/lib/generators/rodauth/templates/app/views/rodauth/reset_password.html.erb +21 -5
- data/lib/generators/rodauth/templates/app/views/rodauth/reset_password_request.html.erb +19 -9
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_auth.html.erb +17 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_confirm.html.erb +17 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_disable.html.erb +15 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_request.html.erb +7 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_setup.html.erb +25 -5
- data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_auth.html.erb +5 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_disable.html.erb +15 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_manage.html.erb +17 -15
- data/lib/generators/rodauth/templates/app/views/rodauth/unlock_account.html.erb +17 -5
- data/lib/generators/rodauth/templates/app/views/rodauth/unlock_account_request.html.erb +11 -5
- data/lib/generators/rodauth/templates/app/views/rodauth/verify_account.html.erb +23 -5
- data/lib/generators/rodauth/templates/app/views/rodauth/verify_account_resend.html.erb +19 -9
- data/lib/generators/rodauth/templates/app/views/rodauth/verify_login_change.html.erb +7 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_auth.html.erb +13 -9
- data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +21 -9
- data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb +21 -9
- data/lib/generators/rodauth/templates/app/views/rodauth_mailer/email_auth.text.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth_mailer/reset_password.text.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth_mailer/unlock_account.text.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth_mailer/verify_account.text.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth_mailer/verify_login_change.text.erb +3 -3
- data/lib/generators/rodauth/views_generator.rb +55 -93
- data/lib/rodauth/rails/app.rb +5 -4
- data/lib/rodauth/rails/auth.rb +1 -16
- data/lib/rodauth/rails/controller_methods.rb +1 -1
- data/lib/rodauth/rails/feature/csrf.rb +15 -4
- data/lib/rodauth/rails/feature/internal_request.rb +22 -20
- data/lib/rodauth/rails/feature/render.rb +9 -1
- data/lib/rodauth/rails/railtie.rb +4 -2
- data/lib/rodauth/rails/tasks.rake +2 -2
- data/lib/rodauth/rails/version.rb +1 -1
- data/lib/rodauth/rails.rb +16 -20
- data/rodauth-rails.gemspec +2 -2
- metadata +9 -23
- data/lib/generators/rodauth/templates/app/views/rodauth/_field.html.erb +0 -10
- data/lib/generators/rodauth/templates/app/views/rodauth/_field_error.html.erb +0 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_global_logout_field.html.erb +0 -6
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_confirm_field.html.erb +0 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_display.html.erb +0 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_field.html.erb +0 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_hidden_field.html.erb +0 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_new_password_field.html.erb +0 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/_otp_auth_code_field.html.erb +0 -8
- data/lib/generators/rodauth/templates/app/views/rodauth/_password_confirm_field.html.erb +0 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/_password_field.html.erb +0 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/_recovery_code_field.html.erb +0 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/_recovery_codes_form.html.erb +0 -6
- data/lib/generators/rodauth/templates/app/views/rodauth/_sms_code_field.html.erb +0 -8
- data/lib/generators/rodauth/templates/app/views/rodauth/_sms_phone_field.html.erb +0 -8
- data/lib/generators/rodauth/templates/app/views/rodauth/_submit.html.erb +0 -3
data/README.md
CHANGED
@@ -8,6 +8,9 @@ Useful links:
|
|
8
8
|
|
9
9
|
* [Rodauth documentation](http://rodauth.jeremyevans.net/documentation.html)
|
10
10
|
* [Rails demo](https://github.com/janko/rodauth-demo-rails)
|
11
|
+
* [JSON API guide](https://github.com/janko/rodauth-rails/wiki/JSON-API)
|
12
|
+
* [OmniAuth guide](https://github.com/janko/rodauth-rails/wiki/OmniAuth)
|
13
|
+
* [Testing guide](https://github.com/janko/rodauth-rails/wiki/Testing)
|
11
14
|
|
12
15
|
Articles:
|
13
16
|
|
@@ -39,17 +42,12 @@ Active Record. There are good reasons for this, and to make Rodauth work
|
|
39
42
|
smoothly alongside Active Record, rodauth-rails configures Sequel to [reuse
|
40
43
|
Active Record's database connection][sequel-activerecord_connection].
|
41
44
|
|
42
|
-
## Upgrading
|
43
|
-
|
44
|
-
For instructions on upgrading from previous rodauth-rails versions, see
|
45
|
-
[UPGRADING.md](/UPGRADING.md).
|
46
|
-
|
47
45
|
## Installation
|
48
46
|
|
49
47
|
Add the gem to your Gemfile:
|
50
48
|
|
51
49
|
```rb
|
52
|
-
gem "rodauth-rails", "~> 0
|
50
|
+
gem "rodauth-rails", "~> 1.0"
|
53
51
|
|
54
52
|
# gem "jwt", require: false # for JWT feature
|
55
53
|
# gem "rotp", require: false # for OTP feature
|
@@ -74,9 +72,9 @@ $ rails generate rodauth:install --jwt # token authentication via the "Authoriza
|
|
74
72
|
$ bundle add jwt
|
75
73
|
```
|
76
74
|
|
77
|
-
This generator will create a Rodauth app with common
|
78
|
-
enabled, a database migration with tables required by
|
79
|
-
with default templates, and a few other files.
|
75
|
+
This generator will create a Rodauth app and configuration with common
|
76
|
+
authentication features enabled, a database migration with tables required by
|
77
|
+
those features, a mailer with default templates, and a few other files.
|
80
78
|
|
81
79
|
Feel free to remove any features you don't need, along with their corresponding
|
82
80
|
tables. Afterwards, run the migration:
|
@@ -85,11 +83,23 @@ tables. Afterwards, run the migration:
|
|
85
83
|
$ rails db:migrate
|
86
84
|
```
|
87
85
|
|
86
|
+
For your mailer to be able to generate email links, you'll need to set up
|
87
|
+
default URL options in each environment. Here is a possible configuration for
|
88
|
+
`config/environments/development.rb`:
|
89
|
+
|
90
|
+
```rb
|
91
|
+
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
|
92
|
+
```
|
93
|
+
|
88
94
|
## Usage
|
89
95
|
|
90
96
|
### Routes
|
91
97
|
|
92
|
-
|
98
|
+
Because requests to Rodauth endpoints are handled by the Rodauth middleware, and
|
99
|
+
not a Rails controller, Rodauth routes will not show in `rails routes`.
|
100
|
+
|
101
|
+
Use the `rodauth:routes` rake task to view the list of endpoints based on
|
102
|
+
currently loaded features:
|
93
103
|
|
94
104
|
```sh
|
95
105
|
$ rails rodauth:routes
|
@@ -127,19 +137,6 @@ These routes are fully functional, feel free to visit them and interact with the
|
|
127
137
|
pages. The templates that ship with Rodauth aim to provide a complete
|
128
138
|
authentication experience, and the forms use [Bootstrap] markup.
|
129
139
|
|
130
|
-
Inside Rodauth configuration and the `route` block you can access Rails route
|
131
|
-
helpers through `#rails_routes`:
|
132
|
-
|
133
|
-
```rb
|
134
|
-
class RodauthApp < Rodauth::Rails::App
|
135
|
-
configure do
|
136
|
-
# ...
|
137
|
-
login_redirect { rails_routes.activity_path }
|
138
|
-
# ...
|
139
|
-
end
|
140
|
-
end
|
141
|
-
```
|
142
|
-
|
143
140
|
### Current account
|
144
141
|
|
145
142
|
The `#current_account` method is defined in controllers and views, which
|
@@ -160,13 +157,15 @@ configurations:
|
|
160
157
|
current_account(:admin)
|
161
158
|
```
|
162
159
|
|
160
|
+
#### Custom account model
|
161
|
+
|
163
162
|
The `#current_account` method will try to infer the account model class from
|
164
163
|
the configured table name. If that fails, you can set the account model
|
165
164
|
manually:
|
166
165
|
|
167
166
|
```rb
|
168
|
-
# app/
|
169
|
-
class
|
167
|
+
# app/misc/rodauth_main.rb
|
168
|
+
class RodauthMain < Rodauth::Rails::Auth
|
170
169
|
configure do
|
171
170
|
# ...
|
172
171
|
rails_account_model Authentication::Account # custom model name
|
@@ -182,7 +181,7 @@ in your Rodauth app's routing block, which helps keep the authentication logic
|
|
182
181
|
encapsulated:
|
183
182
|
|
184
183
|
```rb
|
185
|
-
# app/
|
184
|
+
# app/misc/rodauth_app.rb
|
186
185
|
class RodauthApp < Rodauth::Rails::App
|
187
186
|
# ...
|
188
187
|
route do |r|
|
@@ -282,12 +281,12 @@ copy Rodauth templates into your Rails app:
|
|
282
281
|
$ rails generate rodauth:views
|
283
282
|
```
|
284
283
|
|
285
|
-
This will generate views for
|
286
|
-
`app/views/rodauth` directory, provided that `RodauthController` is set for
|
287
|
-
main configuration.
|
284
|
+
This will generate views for Rodauth features you have currently enabled into
|
285
|
+
the `app/views/rodauth` directory, provided that `RodauthController` is set for
|
286
|
+
the main configuration.
|
288
287
|
|
289
288
|
You can pass a list of Rodauth features to the generator to create views for
|
290
|
-
these features (this will not remove
|
289
|
+
these features (this will not remove any existing views):
|
291
290
|
|
292
291
|
```sh
|
293
292
|
$ rails generate rodauth:views login create_account lockout otp
|
@@ -302,7 +301,27 @@ $ rails generate rodauth:views --all
|
|
302
301
|
Use `--name` to generate views for a different Rodauth configuration:
|
303
302
|
|
304
303
|
```sh
|
305
|
-
$ rails generate rodauth:views --name admin
|
304
|
+
$ rails generate rodauth:views webauthn --name admin
|
305
|
+
```
|
306
|
+
|
307
|
+
#### Page titles
|
308
|
+
|
309
|
+
The generated view templates use `content_for(:title)` to store Rodauth's page
|
310
|
+
titles, which you can then retrieve in your layout template to set the page
|
311
|
+
title:
|
312
|
+
|
313
|
+
```erb
|
314
|
+
<!-- app/views/layouts/application.html.erb -->
|
315
|
+
<!DOCTYPE html>
|
316
|
+
<html>
|
317
|
+
<head>
|
318
|
+
<title><%= content_for(:title) %></title>
|
319
|
+
<!-- ... -->
|
320
|
+
</head>
|
321
|
+
<body>
|
322
|
+
<!-- ... -->
|
323
|
+
</body>
|
324
|
+
</html>
|
306
325
|
```
|
307
326
|
|
308
327
|
#### Layout
|
@@ -311,6 +330,7 @@ To use different layouts for different Rodauth views, you can compare the
|
|
311
330
|
request path in the layout method:
|
312
331
|
|
313
332
|
```rb
|
333
|
+
# app/controllers/rodauth_controller.rb
|
314
334
|
class RodauthController < ApplicationController
|
315
335
|
layout :rodauth_layout
|
316
336
|
|
@@ -331,6 +351,15 @@ class RodauthController < ApplicationController
|
|
331
351
|
end
|
332
352
|
```
|
333
353
|
|
354
|
+
#### Turbo
|
355
|
+
|
356
|
+
[Turbo] has been disabled by default on all built-in and generated view
|
357
|
+
templates, because some Rodauth actions (multi-phase login, adding recovery
|
358
|
+
codes) aren't Turbo-compatible, as they return 200 responses on POST requests.
|
359
|
+
|
360
|
+
That being said, most of Rodauth *is* Turbo-compatible, so feel free to enable
|
361
|
+
Turbo for actions where you want to use it.
|
362
|
+
|
334
363
|
### Mailer
|
335
364
|
|
336
365
|
The install generator will create `RodauthMailer` with default email templates,
|
@@ -340,48 +369,48 @@ flow to use it.
|
|
340
369
|
```rb
|
341
370
|
# app/mailers/rodauth_mailer.rb
|
342
371
|
class RodauthMailer < ApplicationMailer
|
343
|
-
def verify_account(
|
372
|
+
def verify_account(account_id, key)
|
344
373
|
# ...
|
345
374
|
end
|
346
|
-
def reset_password(
|
375
|
+
def reset_password(account_id, key)
|
347
376
|
# ...
|
348
377
|
end
|
349
|
-
def verify_login_change(
|
378
|
+
def verify_login_change(account_id, old_login, new_login, key)
|
350
379
|
# ...
|
351
380
|
end
|
352
|
-
def password_changed(
|
381
|
+
def password_changed(account_id)
|
353
382
|
# ...
|
354
383
|
end
|
355
|
-
# def email_auth(
|
384
|
+
# def email_auth(account_id, key)
|
356
385
|
# ...
|
357
386
|
# end
|
358
|
-
# def unlock_account(
|
387
|
+
# def unlock_account(account_id, key)
|
359
388
|
# ...
|
360
389
|
# end
|
361
390
|
end
|
362
391
|
```
|
363
392
|
```rb
|
364
|
-
# app/
|
365
|
-
class
|
393
|
+
# app/misc/rodauth_main.rb
|
394
|
+
class RodauthMain < Rodauth::Rails::Auth
|
366
395
|
configure do
|
367
396
|
# ...
|
368
397
|
create_reset_password_email do
|
369
|
-
RodauthMailer.reset_password(
|
398
|
+
RodauthMailer.reset_password(account_id, reset_password_key_value)
|
370
399
|
end
|
371
400
|
create_verify_account_email do
|
372
|
-
RodauthMailer.verify_account(
|
401
|
+
RodauthMailer.verify_account(account_id, verify_account_key_value)
|
373
402
|
end
|
374
|
-
create_verify_login_change_email do |
|
375
|
-
RodauthMailer.verify_login_change(
|
403
|
+
create_verify_login_change_email do |_login|
|
404
|
+
RodauthMailer.verify_login_change(account_id, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_key_value)
|
376
405
|
end
|
377
406
|
create_password_changed_email do
|
378
|
-
RodauthMailer.password_changed(
|
407
|
+
RodauthMailer.password_changed(account_id)
|
379
408
|
end
|
380
409
|
# create_email_auth_email do
|
381
|
-
# RodauthMailer.email_auth(
|
410
|
+
# RodauthMailer.email_auth(account_id, email_auth_key_value)
|
382
411
|
# end
|
383
412
|
# create_unlock_account_email do
|
384
|
-
# RodauthMailer.unlock_account(
|
413
|
+
# RodauthMailer.unlock_account(account_id, unlock_account_key_value)
|
385
414
|
# end
|
386
415
|
send_email do |email|
|
387
416
|
# queue email delivery on the mailer after the transaction commits
|
@@ -399,44 +428,8 @@ deliveries. However, if you want to send emails synchronously, you can modify
|
|
399
428
|
the configuration to call `#deliver_now` instead.
|
400
429
|
|
401
430
|
If you're using a background processing library without an Active Job adapter,
|
402
|
-
or a 3rd-party service for sending transactional emails, this
|
403
|
-
|
404
|
-
and `#send_email`, override the `#send_*_email` methods instead, which are
|
405
|
-
required to send the email immediately. For example:
|
406
|
-
|
407
|
-
```rb
|
408
|
-
# app/workers/rodauth_mailer_worker.rb
|
409
|
-
class RodauthMailerWorker
|
410
|
-
include Sidekiq::Worker
|
411
|
-
|
412
|
-
def perform(name, *args)
|
413
|
-
email = RodauthMailer.public_send(name, *args)
|
414
|
-
email.deliver_now
|
415
|
-
end
|
416
|
-
end
|
417
|
-
```
|
418
|
-
```rb
|
419
|
-
# app/lib/rodauth_app.rb
|
420
|
-
class RodauthApp < Rodauth::Rails::App
|
421
|
-
configure do
|
422
|
-
# ...
|
423
|
-
# use `#send_*_email` method to be able to immediately enqueue email delivery
|
424
|
-
send_reset_password_email do
|
425
|
-
enqueue_email(:reset_password, email_to, reset_password_email_link)
|
426
|
-
end
|
427
|
-
# ...
|
428
|
-
auth_class_eval do
|
429
|
-
# custom method for enqueuing email delivery using our worker
|
430
|
-
def enqueue_email(name, *args)
|
431
|
-
db.after_commit do
|
432
|
-
RodauthMailerWorker.perform_async(name, *args)
|
433
|
-
end
|
434
|
-
end
|
435
|
-
end
|
436
|
-
# ...
|
437
|
-
end
|
438
|
-
end
|
439
|
-
```
|
431
|
+
or a 3rd-party service for sending transactional emails, see [this wiki
|
432
|
+
page][custom mailer worker] on how to set it up.
|
440
433
|
|
441
434
|
### Migrations
|
442
435
|
|
@@ -458,7 +451,23 @@ class CreateRodauthOtpSmsCodesRecoveryCodes < ActiveRecord::Migration
|
|
458
451
|
end
|
459
452
|
```
|
460
453
|
|
461
|
-
|
454
|
+
#### Custom migration name
|
455
|
+
|
456
|
+
You can change the default migration name:
|
457
|
+
|
458
|
+
```sh
|
459
|
+
$ rails generate rodauth:migration email_auth --name create_account_email_auth_keys
|
460
|
+
```
|
461
|
+
```rb
|
462
|
+
# db/migration/*_create_account_email_auth_keys
|
463
|
+
class CreateAccountEmailAuthKeys < ActiveRecord::Migration
|
464
|
+
def change
|
465
|
+
create_table :account_email_auth_keys do |t| ... end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
```
|
469
|
+
|
470
|
+
## Model
|
462
471
|
|
463
472
|
The `Rodauth::Rails::Model` mixin can be included into the account model, which
|
464
473
|
defines a password attribute and associations for tables used by enabled
|
@@ -470,7 +479,7 @@ class Account < ApplicationRecord
|
|
470
479
|
end
|
471
480
|
```
|
472
481
|
|
473
|
-
|
482
|
+
### Password attribute
|
474
483
|
|
475
484
|
Regardless of whether you're storing the password hash in a column in the
|
476
485
|
accounts table, or in a separate table, the `#password` attribute can be used
|
@@ -494,7 +503,7 @@ Note that the password attribute doesn't come with validations, making it
|
|
494
503
|
unsuitable for forms. It was primarily intended to allow easily creating
|
495
504
|
accounts in development console and in tests.
|
496
505
|
|
497
|
-
|
506
|
+
### Associations
|
498
507
|
|
499
508
|
The `Rodauth::Rails::Model` mixin defines associations for Rodauth tables
|
500
509
|
associated to the accounts table:
|
@@ -544,6 +553,8 @@ class Account < ApplicationRecord
|
|
544
553
|
end
|
545
554
|
```
|
546
555
|
|
556
|
+
#### Association reference
|
557
|
+
|
547
558
|
Below is a list of all associations defined depending on the features loaded:
|
548
559
|
|
549
560
|
| Feature | Association | Type | Model | Table (default) |
|
@@ -568,6 +579,12 @@ Below is a list of all associations defined depending on the features loaded:
|
|
568
579
|
| webauthn | `:webauthn_keys` | `has_many` | `WebauthnKey` | `account_webauthn_keys` |
|
569
580
|
| webauthn | `:webauthn_user_id` | `has_one` | `WebauthnUserId` | `account_webauthn_user_ids` |
|
570
581
|
|
582
|
+
Note that some Rodauth tables use composite primary keys, which Active Record
|
583
|
+
doesn't support out of the box. For associations to work properly, you might
|
584
|
+
need to add the [composite_primary_keys] gem to your Gemfile.
|
585
|
+
|
586
|
+
#### Association options
|
587
|
+
|
571
588
|
By default, all associations except for audit logs have `dependent: :destroy`
|
572
589
|
set, to allow for easy deletion of account records in the console. You can use
|
573
590
|
`:association_options` to modify global or per-association options:
|
@@ -582,31 +599,21 @@ Rodauth::Rails.model(association_options: -> (name) {
|
|
582
599
|
})
|
583
600
|
```
|
584
601
|
|
585
|
-
|
586
|
-
doesn't support out of the box. For associations to work properly, you might
|
587
|
-
need to add the [composite_primary_keys] gem to your Gemfile.
|
588
|
-
|
589
|
-
### Multiple configurations
|
602
|
+
## Multiple configurations
|
590
603
|
|
591
604
|
If you need to handle multiple types of accounts that require different
|
592
|
-
authentication logic, you can create
|
605
|
+
authentication logic, you can create new configurations for them. This
|
606
|
+
is done by creating new `Rodauth::Rails::Auth` subclasses, and registering
|
607
|
+
them under a name.
|
593
608
|
|
594
609
|
```rb
|
595
|
-
# app/
|
610
|
+
# app/misc/rodauth_app.rb
|
596
611
|
class RodauthApp < Rodauth::Rails::App
|
597
612
|
# primary configuration
|
598
|
-
configure
|
599
|
-
# ...
|
600
|
-
end
|
613
|
+
configure RodauthMain
|
601
614
|
|
602
|
-
#
|
603
|
-
configure
|
604
|
-
# ... enable features ...
|
605
|
-
prefix "/admin"
|
606
|
-
session_key_prefix "admin_"
|
607
|
-
remember_cookie_key "_admin_remember" # if using remember feature
|
608
|
-
# ...
|
609
|
-
end
|
615
|
+
# secondary configuration
|
616
|
+
configure RodauthAdmin, :admin
|
610
617
|
|
611
618
|
route do |r|
|
612
619
|
r.rodauth
|
@@ -620,100 +627,46 @@ class RodauthApp < Rodauth::Rails::App
|
|
620
627
|
end
|
621
628
|
end
|
622
629
|
```
|
623
|
-
|
624
|
-
Then in your application you can reference the secondary Rodauth instance:
|
625
|
-
|
626
630
|
```rb
|
627
|
-
|
628
|
-
```
|
629
|
-
|
630
|
-
You'll likely want to save the information of which account belongs to which
|
631
|
-
configuration to the database. One way would be to have a separate table that
|
632
|
-
stores account types:
|
633
|
-
|
634
|
-
```sh
|
635
|
-
$ rails generate migration create_account_types
|
636
|
-
```
|
637
|
-
```rb
|
638
|
-
# db/migrate/*_create_account_types.rb
|
639
|
-
class CreateAccountTypes < ActiveRecord::Migration
|
640
|
-
def change
|
641
|
-
create_table :account_types do |t|
|
642
|
-
t.references :account, foreign_key: { on_delete: :cascade }, null: false
|
643
|
-
t.string :type, null: false
|
644
|
-
end
|
645
|
-
end
|
646
|
-
end
|
647
|
-
```
|
648
|
-
```sh
|
649
|
-
$ rails db:migrate
|
650
|
-
```
|
651
|
-
|
652
|
-
Then an entry would be inserted after account creation, and optionally whenever
|
653
|
-
Rodauth retrieves accounts you could filter only those belonging to the current
|
654
|
-
configuration:
|
655
|
-
|
656
|
-
```rb
|
657
|
-
# app/lib/rodauth_app.rb
|
658
|
-
class RodauthApp < Rodauth::Rails::App
|
659
|
-
configure(:admin) do
|
660
|
-
# ...
|
661
|
-
after_create_account do
|
662
|
-
db[:account_types].insert(account_id: account_id, type: "admin")
|
663
|
-
end
|
664
|
-
auth_class_eval do
|
665
|
-
def account_ds(*)
|
666
|
-
super.join(:account_types, account_id: :id).where(type: "admin")
|
667
|
-
end
|
668
|
-
end
|
669
|
-
# ...
|
670
|
-
end
|
671
|
-
end
|
672
|
-
```
|
673
|
-
|
674
|
-
#### Named auth classes
|
675
|
-
|
676
|
-
A `configure` block inside `Rodauth::Rails::App` will internally create an
|
677
|
-
anonymous `Rodauth::Auth` subclass, and register it under the given name.
|
678
|
-
However, you can also define the auth classes explicitly, by creating
|
679
|
-
subclasses of `Rodauth::Rails::Auth`:
|
680
|
-
|
681
|
-
```rb
|
682
|
-
# app/lib/rodauth_main.rb
|
683
|
-
class RodauthMain < Rodauth::Rails::Auth
|
684
|
-
configure do
|
685
|
-
# ... main configuration ...
|
686
|
-
end
|
687
|
-
end
|
688
|
-
```
|
689
|
-
```rb
|
690
|
-
# app/lib/rodauth_admin.rb
|
631
|
+
# app/misc/rodauth_admin.rb
|
691
632
|
class RodauthAdmin < Rodauth::Rails::Auth
|
692
633
|
configure do
|
693
|
-
# ...
|
634
|
+
# ... enable features ...
|
694
635
|
prefix "/admin"
|
695
636
|
session_key_prefix "admin_"
|
637
|
+
remember_cookie_key "_admin_remember" # if using remember feature
|
696
638
|
# ...
|
639
|
+
|
640
|
+
# search views in `app/views/admin/rodauth` directory
|
641
|
+
rails_controller { Admin::RodauthController }
|
697
642
|
end
|
698
643
|
end
|
699
644
|
```
|
700
645
|
```rb
|
701
|
-
# app/
|
702
|
-
class
|
703
|
-
configure RodauthMain
|
704
|
-
configure RodauthAdmin, :admin
|
705
|
-
# ...
|
646
|
+
# app/controllers/admin/rodauth_controller.rb
|
647
|
+
class Admin::RodauthController < ApplicationController
|
706
648
|
end
|
707
649
|
```
|
708
650
|
|
709
|
-
|
710
|
-
improve introspection and error messages. You can also use inheritance to share
|
711
|
-
common settings:
|
651
|
+
Then in your application you can reference the secondary Rodauth instance:
|
712
652
|
|
713
653
|
```rb
|
714
|
-
|
654
|
+
rodauth(:admin).login_path #=> "/admin/login"
|
655
|
+
```
|
656
|
+
|
657
|
+
You'll likely want to save the information of which account belongs to which
|
658
|
+
configuration to the database. See [this guide][account types] on how you can do
|
659
|
+
that.
|
660
|
+
|
661
|
+
### Sharing configuration
|
662
|
+
|
663
|
+
If there are common settings that you want to share between Rodauth
|
664
|
+
configurations, you can do so via inheritance:
|
665
|
+
|
666
|
+
```rb
|
667
|
+
# app/misc/rodauth_base.rb
|
715
668
|
class RodauthBase < Rodauth::Rails::Auth
|
716
|
-
# common settings that
|
669
|
+
# common settings that are shared between multiple configurations
|
717
670
|
configure do
|
718
671
|
enable :login, :logout
|
719
672
|
login_return_to_requested_location? true
|
@@ -723,7 +676,7 @@ class RodauthBase < Rodauth::Rails::Auth
|
|
723
676
|
end
|
724
677
|
```
|
725
678
|
```rb
|
726
|
-
# app/
|
679
|
+
# app/misc/rodauth_main.rb
|
727
680
|
class RodauthMain < RodauthBase # inherit common settings
|
728
681
|
configure do
|
729
682
|
# ... customize main ...
|
@@ -731,7 +684,7 @@ class RodauthMain < RodauthBase # inherit common settings
|
|
731
684
|
end
|
732
685
|
```
|
733
686
|
```rb
|
734
|
-
# app/
|
687
|
+
# app/misc/rodauth_admin.rb
|
735
688
|
class RodauthAdmin < RodauthBase # inherit common settings
|
736
689
|
configure do
|
737
690
|
# ... customize admin ...
|
@@ -739,112 +692,67 @@ class RodauthAdmin < RodauthBase # inherit common settings
|
|
739
692
|
end
|
740
693
|
```
|
741
694
|
|
742
|
-
|
743
|
-
directly at the class level instead of inside an `auth_class_eval`:
|
744
|
-
|
745
|
-
```rb
|
746
|
-
# app/lib/rodauth_admin.rb
|
747
|
-
class RodauthAdmin < Rodauth::Rails::Auth
|
748
|
-
configure do
|
749
|
-
# ...
|
750
|
-
end
|
751
|
-
|
752
|
-
def superadmin?
|
753
|
-
Role.where(account_id: session_id, type: "superadmin").any?
|
754
|
-
end
|
755
|
-
end
|
756
|
-
```
|
757
|
-
```rb
|
758
|
-
# config/routes.rb
|
759
|
-
Rails.application.routes.draw do
|
760
|
-
constraints Rodauth::Rails.authenticated(:admin) { |rodauth| rodauth.superadmin? } do
|
761
|
-
mount Sidekiq::Web => "sidekiq"
|
762
|
-
end
|
763
|
-
end
|
764
|
-
```
|
765
|
-
|
766
|
-
### Calling controller methods
|
695
|
+
## Outside of a request
|
767
696
|
|
768
|
-
|
769
|
-
configuration, in some cases you might want to call methods defined on your
|
770
|
-
controllers. You can do so with `rails_controller_eval`, for example:
|
771
|
-
|
772
|
-
```rb
|
773
|
-
# app/controllers/application_controller.rb
|
774
|
-
class ApplicationController < ActionController::Base
|
775
|
-
private
|
776
|
-
def setup_tracking(account_id)
|
777
|
-
# ... some implementation ...
|
778
|
-
end
|
779
|
-
end
|
780
|
-
```
|
781
|
-
```rb
|
782
|
-
# app/lib/rodauth_app.rb
|
783
|
-
class RodauthApp < Rodauth::Rails::App
|
784
|
-
configure do
|
785
|
-
after_create_account do
|
786
|
-
rails_controller_eval { setup_tracking(account_id) }
|
787
|
-
end
|
788
|
-
end
|
789
|
-
end
|
790
|
-
```
|
791
|
-
|
792
|
-
### Outside of a request
|
697
|
+
### Calling actions
|
793
698
|
|
794
699
|
In some cases you might need to use Rodauth more programmatically. If you want
|
795
700
|
to perform authentication operations outside of request context, Rodauth ships
|
796
701
|
with the [internal_request] feature just for that.
|
797
702
|
|
798
703
|
```rb
|
799
|
-
# app/
|
800
|
-
class
|
704
|
+
# app/misc/rodauth_main.rb
|
705
|
+
class RodauthMain < Rodauth::Rails::Auth
|
801
706
|
configure do
|
802
707
|
enable :internal_request
|
803
708
|
end
|
804
709
|
end
|
805
710
|
```
|
806
711
|
```rb
|
807
|
-
#
|
712
|
+
# primary configuration
|
808
713
|
RodauthApp.rodauth.create_account(login: "user@example.com", password: "secret")
|
809
714
|
RodauthApp.rodauth.verify_account(account_login: "user@example.com")
|
810
715
|
|
811
716
|
# secondary configuration
|
812
|
-
RodauthApp.rodauth(:admin).close_account(account_login: "
|
717
|
+
RodauthApp.rodauth(:admin).close_account(account_login: "user@example.com")
|
813
718
|
```
|
814
719
|
|
815
720
|
The rodauth-rails gem additionally updates the internal rack env hash with your
|
816
721
|
`config.action_mailer.default_url_options`, which is used for generating email
|
817
722
|
links.
|
818
723
|
|
724
|
+
### Generating URLs
|
725
|
+
|
819
726
|
For generating authentication URLs outside of a request use the
|
820
727
|
[path_class_methods] plugin:
|
821
728
|
|
822
729
|
```rb
|
823
|
-
# app/
|
824
|
-
class
|
730
|
+
# app/misc/rodauth_main.rb
|
731
|
+
class RodauthMain < Rodauth::Rails::Auth
|
825
732
|
configure do
|
826
733
|
enable :path_class_methods
|
734
|
+
create_account_route "register"
|
827
735
|
end
|
828
736
|
end
|
829
737
|
```
|
830
738
|
```rb
|
831
|
-
#
|
832
|
-
RodauthApp.rodauth.create_account_path
|
833
|
-
RodauthApp.rodauth.verify_account_url(key: "abc123")
|
739
|
+
# primary configuration
|
740
|
+
RodauthApp.rodauth.create_account_path # => "/register"
|
741
|
+
RodauthApp.rodauth.verify_account_url(key: "abc123") #=> "https://example.com/verify-account?key=abc123"
|
834
742
|
|
835
743
|
# secondary configuration
|
836
|
-
RodauthApp.rodauth(:admin).close_account_path
|
744
|
+
RodauthApp.rodauth(:admin).close_account_path(foo: "bar") #=> "/admin/close-account?foo=bar"
|
837
745
|
```
|
838
746
|
|
839
|
-
|
747
|
+
### Calling instance methods
|
840
748
|
|
841
749
|
If you need to access Rodauth methods not exposed as internal requests, you can
|
842
750
|
use `Rodauth::Rails.rodauth` to retrieve the Rodauth instance used by the
|
843
751
|
internal_request feature:
|
844
752
|
|
845
753
|
```rb
|
846
|
-
# app/
|
847
|
-
class
|
754
|
+
# app/misc/rodauth_main.rb
|
755
|
+
class RodauthMain < Rodauth::Rails::Auth
|
848
756
|
configure do
|
849
757
|
enable :internal_request # this is required
|
850
758
|
end
|
@@ -852,7 +760,7 @@ end
|
|
852
760
|
```
|
853
761
|
```rb
|
854
762
|
account = Account.find_by!(email: "user@example.com")
|
855
|
-
rodauth = Rodauth::Rails.rodauth(account: account)
|
763
|
+
rodauth = Rodauth::Rails.rodauth(account: account) #=> #<RodauthMain::InternalRequest ...>
|
856
764
|
|
857
765
|
rodauth.compute_hmac("token") #=> "TpEJTKfKwqYvIDKWsuZhkhKlhaBXtR1aodskBAflD8U"
|
858
766
|
rodauth.open_account? #=> true
|
@@ -971,178 +879,10 @@ connection, using the [sequel-activerecord_connection] gem.
|
|
971
879
|
This means that, from the usage perspective, Sequel can be considered just
|
972
880
|
as an implementation detail of Rodauth.
|
973
881
|
|
974
|
-
## JSON API
|
975
|
-
|
976
|
-
To make Rodauth endpoints accessible via JSON API, enable the [`json`][json]
|
977
|
-
feature:
|
978
|
-
|
979
|
-
```rb
|
980
|
-
# app/lib/rodauth_app.rb
|
981
|
-
class RodauthApp < Rodauth::Rails::App
|
982
|
-
configure do
|
983
|
-
# ...
|
984
|
-
enable :json
|
985
|
-
only_json? true # accept only JSON requests (optional)
|
986
|
-
# ...
|
987
|
-
end
|
988
|
-
end
|
989
|
-
```
|
990
|
-
|
991
|
-
This will store account session data into the Rails session. If you rather want
|
992
|
-
stateless token-based authentication via the `Authorization` header, enable the
|
993
|
-
[`jwt`][jwt] feature (which builds on top of the `json` feature) and add the
|
994
|
-
[JWT gem] to the Gemfile:
|
995
|
-
|
996
|
-
```sh
|
997
|
-
$ bundle add jwt
|
998
|
-
```
|
999
|
-
```rb
|
1000
|
-
# app/lib/rodauth_app.rb
|
1001
|
-
class RodauthApp < Rodauth::Rails::App
|
1002
|
-
configure do
|
1003
|
-
# ...
|
1004
|
-
enable :jwt
|
1005
|
-
jwt_secret "<YOUR_SECRET_KEY>" # store the JWT secret in a safe place
|
1006
|
-
only_json? true # accept only JSON requests (optional)
|
1007
|
-
# ...
|
1008
|
-
end
|
1009
|
-
end
|
1010
|
-
```
|
1011
|
-
|
1012
|
-
The JWT token will be returned after each request to Rodauth routes. To also
|
1013
|
-
return the JWT token on requests to your app's routes, you can add the
|
1014
|
-
following code to your base controller:
|
1015
|
-
|
1016
|
-
```rb
|
1017
|
-
class ApplicationController < ActionController::Base
|
1018
|
-
# ...
|
1019
|
-
after_action :set_jwt_token
|
1020
|
-
|
1021
|
-
private
|
1022
|
-
|
1023
|
-
def set_jwt_token
|
1024
|
-
if rodauth.use_jwt? && rodauth.valid_jwt?
|
1025
|
-
response.headers["Authorization"] = rodauth.session_jwt
|
1026
|
-
end
|
1027
|
-
end
|
1028
|
-
# ...
|
1029
|
-
end
|
1030
|
-
```
|
1031
|
-
|
1032
|
-
## OmniAuth
|
1033
|
-
|
1034
|
-
While Rodauth doesn't yet come with [OmniAuth] integration, we can build one
|
1035
|
-
ourselves using the existing Rodauth API.
|
1036
|
-
|
1037
|
-
In order to allow the user to login via multiple external providers, let's
|
1038
|
-
create an `account_identities` table that will have a many-to-one relationship
|
1039
|
-
with the `accounts` table:
|
1040
|
-
|
1041
|
-
```sh
|
1042
|
-
$ rails generate model AccountIdentity
|
1043
|
-
```
|
1044
|
-
```rb
|
1045
|
-
# db/migrate/*_create_account_identities.rb
|
1046
|
-
class CreateAccountIdentities < ActiveRecord::Migration
|
1047
|
-
def change
|
1048
|
-
create_table :account_identities do |t|
|
1049
|
-
t.references :account, null: false, foreign_key: { on_delete: :cascade }
|
1050
|
-
t.string :provider, null: false
|
1051
|
-
t.string :uid, null: false
|
1052
|
-
t.jsonb :info, null: false, default: {} # adjust JSON column type for your database
|
1053
|
-
|
1054
|
-
t.timestamps
|
1055
|
-
|
1056
|
-
t.index [:provider, :uid], unique: true
|
1057
|
-
end
|
1058
|
-
end
|
1059
|
-
end
|
1060
|
-
```
|
1061
|
-
```rb
|
1062
|
-
# app/models/account_identity.rb
|
1063
|
-
class AcccountIdentity < ApplicationRecord
|
1064
|
-
belongs_to :account
|
1065
|
-
end
|
1066
|
-
```
|
1067
|
-
```rb
|
1068
|
-
# app/models/account.rb
|
1069
|
-
class Account < ApplicationRecord
|
1070
|
-
has_many :identities, class_name: "AccountIdentity"
|
1071
|
-
end
|
1072
|
-
```
|
1073
|
-
|
1074
|
-
Let's assume we want to implement Facebook login, and have added the
|
1075
|
-
corresponding OmniAuth strategy to the middleware stack, together with an
|
1076
|
-
authorization link on the login form:
|
1077
|
-
|
1078
|
-
```rb
|
1079
|
-
Rails.application.config.middleware.use OmniAuth::Builder do
|
1080
|
-
provider :facebook, ENV["FACEBOOK_APP_ID"], ENV["FACEBOOK_APP_SECRET"],
|
1081
|
-
scope: "email", callback_path: "/auth/facebook/callback"
|
1082
|
-
end
|
1083
|
-
```
|
1084
|
-
```erb
|
1085
|
-
<%= link_to "Login via Facebook", "/auth/facebook" %>
|
1086
|
-
```
|
1087
|
-
|
1088
|
-
Finally, let's implement the OmniAuth callback endpoint on our Rodauth
|
1089
|
-
controller:
|
1090
|
-
|
1091
|
-
```rb
|
1092
|
-
# config/routes.rb
|
1093
|
-
Rails.application.routes.draw do
|
1094
|
-
# ...
|
1095
|
-
get "/auth/:provider/callback", to: "rodauth#omniauth"
|
1096
|
-
end
|
1097
|
-
```
|
1098
|
-
```rb
|
1099
|
-
# app/controllres/rodauth_controller.rb
|
1100
|
-
class RodauthController < ApplicationController
|
1101
|
-
def omniauth
|
1102
|
-
auth = request.env["omniauth.auth"]
|
1103
|
-
|
1104
|
-
# attempt to find existing identity directly
|
1105
|
-
identity = AccountIdentity.find_by(provider: auth["provider"], uid: auth["uid"])
|
1106
|
-
|
1107
|
-
if identity
|
1108
|
-
# update any external info changes
|
1109
|
-
identity.update!(info: auth["info"])
|
1110
|
-
# set account from identity
|
1111
|
-
account = identity.account
|
1112
|
-
end
|
1113
|
-
|
1114
|
-
# attempt to find an existing account by email
|
1115
|
-
account ||= Account.find_by(email: auth["info"]["email"])
|
1116
|
-
|
1117
|
-
# disallow login if account is not verified
|
1118
|
-
if account && account.status != rodauth.account_open_status_value
|
1119
|
-
redirect_to rodauth.login_path, alert: rodauth.unverified_account_message
|
1120
|
-
return
|
1121
|
-
end
|
1122
|
-
|
1123
|
-
# create new account if it doesn't exist
|
1124
|
-
unless account
|
1125
|
-
account = Account.create!(email: auth["info"]["email"], status: rodauth.account_open_status_value)
|
1126
|
-
end
|
1127
|
-
|
1128
|
-
# create new identity if it doesn't exist
|
1129
|
-
unless identity
|
1130
|
-
account.identities.create!(provider: auth["provider"], uid: auth["uid"], info: auth["info"])
|
1131
|
-
end
|
1132
|
-
|
1133
|
-
# load the account into the rodauth instance
|
1134
|
-
rodauth.account_from_login(account.email)
|
1135
|
-
|
1136
|
-
rodauth_response do # ensures any `after_action` callbacks get called
|
1137
|
-
# sign in the loaded account
|
1138
|
-
rodauth.login("omniauth")
|
1139
|
-
end
|
1140
|
-
end
|
1141
|
-
end
|
1142
|
-
```
|
1143
|
-
|
1144
882
|
## Configuring
|
1145
883
|
|
884
|
+
### Configuration methods
|
885
|
+
|
1146
886
|
The `rails` feature rodauth-rails loads provides the following configuration
|
1147
887
|
methods:
|
1148
888
|
|
@@ -1157,6 +897,8 @@ methods:
|
|
1157
897
|
| `rails_controller` | Controller class to use for rendering and CSRF protection. |
|
1158
898
|
| `rails_account_model` | Model class connected with the accounts table. |
|
1159
899
|
|
900
|
+
### General configuration
|
901
|
+
|
1160
902
|
The `Rodauth::Rails` module has a few config settings available as well:
|
1161
903
|
|
1162
904
|
| Name | Description |
|
@@ -1175,169 +917,102 @@ end
|
|
1175
917
|
For the list of configuration methods provided by Rodauth, see the [feature
|
1176
918
|
documentation].
|
1177
919
|
|
1178
|
-
|
1179
|
-
|
1180
|
-
When developing custom extensions for Rodauth inside your Rails project, it's
|
1181
|
-
probably better to use plain modules, at least in the beginning, as Rodauth
|
1182
|
-
feature design doesn't yet work well with Zeitwerk reloading.
|
920
|
+
### Defining custom methods
|
1183
921
|
|
1184
|
-
|
1185
|
-
|
922
|
+
All Rodauth configuration methods are just syntax sugar for defining instance
|
923
|
+
methods on the auth class. You can also define your own custom methods on the
|
924
|
+
auth class:
|
1186
925
|
|
1187
926
|
```rb
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
927
|
+
class RodauthMain < Rodauth::Rails::Auth
|
928
|
+
configure do
|
929
|
+
password_match? { |password| ldap_valid?(password) }
|
930
|
+
end
|
931
|
+
|
932
|
+
# Example external identities table
|
933
|
+
def identities
|
934
|
+
db[:account_identities].where(account_id: account_id).all
|
1192
935
|
end
|
1193
936
|
|
1194
|
-
|
937
|
+
private
|
938
|
+
|
939
|
+
# Example LDAP authentication
|
940
|
+
def ldap_valid?(password)
|
1195
941
|
SimpleLdapAuthenticator.valid?(account[:email], password)
|
1196
942
|
end
|
1197
943
|
end
|
1198
944
|
```
|
1199
945
|
```rb
|
1200
|
-
|
1201
|
-
class RodauthApp < Rodauth::Rails::App
|
1202
|
-
configure do
|
1203
|
-
# ...
|
1204
|
-
auth_class_eval do
|
1205
|
-
include RodauthLdap
|
1206
|
-
end
|
1207
|
-
# ...
|
1208
|
-
end
|
1209
|
-
end
|
946
|
+
rodauth.identities #=> [{ provider: "facebook", uid: "abc123", ... }, ...]
|
1210
947
|
```
|
1211
948
|
|
1212
|
-
|
949
|
+
### Rails URL helpers
|
1213
950
|
|
1214
|
-
|
951
|
+
Inside Rodauth configuration and the `route` block you can access Rails route
|
952
|
+
helpers through `#rails_routes`:
|
1215
953
|
|
1216
954
|
```rb
|
1217
|
-
#
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
include ActiveJob::TestHelper
|
1222
|
-
driven_by :rack_test
|
1223
|
-
|
1224
|
-
test "creating and verifying an account" do
|
1225
|
-
create_account
|
1226
|
-
assert_match "An email has been sent to you with a link to verify your account", page.text
|
1227
|
-
|
1228
|
-
verify_account
|
1229
|
-
assert_match "Your account has been verified", page.text
|
955
|
+
# app/misc/rodauth_main.rb
|
956
|
+
class RodauthMain < Rodauth::Rails::Auth
|
957
|
+
configure do
|
958
|
+
login_redirect { rails_routes.activity_path }
|
1230
959
|
end
|
960
|
+
end
|
961
|
+
```
|
1231
962
|
|
1232
|
-
|
1233
|
-
create_account(verify: true)
|
1234
|
-
|
1235
|
-
logout
|
1236
|
-
assert_match "You have been logged out", page.text
|
963
|
+
### Calling controller methods
|
1237
964
|
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
965
|
+
When using Rodauth before/after hooks or generally overriding your Rodauth
|
966
|
+
configuration, in some cases you might want to call methods defined on your
|
967
|
+
controllers. You can do so with `rails_controller_eval`, for example:
|
1241
968
|
|
969
|
+
```rb
|
970
|
+
# app/controllers/application_controller.rb
|
971
|
+
class ApplicationController < ActionController::Base
|
1242
972
|
private
|
1243
|
-
|
1244
|
-
|
1245
|
-
visit "/create-account"
|
1246
|
-
fill_in "Login", with: email
|
1247
|
-
fill_in "Password", with: password
|
1248
|
-
fill_in "Confirm Password", with: password
|
1249
|
-
click_on "Create Account"
|
1250
|
-
verify_account if verify
|
1251
|
-
end
|
1252
|
-
|
1253
|
-
def verify_account
|
1254
|
-
perform_enqueued_jobs # run enqueued email deliveries
|
1255
|
-
email = ActionMailer::Base.deliveries.last
|
1256
|
-
verify_account_link = email.body.to_s[/\S+verify-account\S+/]
|
1257
|
-
visit verify_account_link
|
1258
|
-
click_on "Verify Account"
|
1259
|
-
end
|
1260
|
-
|
1261
|
-
def login(email: "user@example.com", password: "secret")
|
1262
|
-
visit "/login"
|
1263
|
-
fill_in "Login", with: email
|
1264
|
-
fill_in "Password", with: password
|
1265
|
-
click_on "Login"
|
1266
|
-
end
|
1267
|
-
|
1268
|
-
def logout
|
1269
|
-
visit "/logout"
|
1270
|
-
click_on "Logout"
|
973
|
+
def setup_tracking(account_id)
|
974
|
+
# ... some implementation ...
|
1271
975
|
end
|
1272
976
|
end
|
1273
977
|
```
|
1274
|
-
|
1275
|
-
While request tests in JSON API mode with JWT tokens could look something like
|
1276
|
-
this:
|
1277
|
-
|
1278
978
|
```rb
|
1279
|
-
#
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
assert_response :success
|
1286
|
-
assert_match "An email has been sent to you with a link to verify your account", JSON.parse(body)["success"]
|
1287
|
-
|
1288
|
-
verify_account
|
1289
|
-
assert_response :success
|
1290
|
-
assert_match "Your account has been verified", JSON.parse(body)["success"]
|
1291
|
-
end
|
1292
|
-
|
1293
|
-
test "logging in and logging out" do
|
1294
|
-
create_account(verify: true)
|
1295
|
-
|
1296
|
-
logout
|
1297
|
-
assert_response :success
|
1298
|
-
assert_match "You have been logged out", JSON.parse(body)["success"]
|
1299
|
-
|
1300
|
-
login
|
1301
|
-
assert_response :success
|
1302
|
-
assert_match "You have been logged in", JSON.parse(body)["success"]
|
979
|
+
# app/misc/rodauth_main.rb
|
980
|
+
class RodauthMain < Rodauth::Rails::Auth
|
981
|
+
configure do
|
982
|
+
after_create_account do
|
983
|
+
rails_controller_eval { setup_tracking(account_id) }
|
984
|
+
end
|
1303
985
|
end
|
986
|
+
end
|
987
|
+
```
|
1304
988
|
|
1305
|
-
|
989
|
+
### Single-file configuration
|
1306
990
|
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
end
|
991
|
+
If you would prefer to have all Rodauth logic contained inside a single file,
|
992
|
+
you call `Rodauth::Rails::App.configure` with a block, which will create an
|
993
|
+
anonymous auth class.
|
1311
994
|
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
995
|
+
```rb
|
996
|
+
# app/misc/rodauth_app.rb
|
997
|
+
class RodauthApp < Rodauth::Rails::App
|
998
|
+
# primary configuration
|
999
|
+
configure do
|
1000
|
+
enable :login, :logout, :create_account, :verify_account
|
1001
|
+
# ...
|
1317
1002
|
end
|
1318
1003
|
|
1319
|
-
|
1320
|
-
|
1004
|
+
# secondary configuration
|
1005
|
+
configure(:admin) do
|
1006
|
+
enable :email_auth, :single_session
|
1007
|
+
# ...
|
1321
1008
|
end
|
1322
1009
|
|
1323
|
-
|
1324
|
-
|
1010
|
+
route do |r|
|
1011
|
+
# ...
|
1325
1012
|
end
|
1326
1013
|
end
|
1327
1014
|
```
|
1328
1015
|
|
1329
|
-
If you're delivering emails in the background, make sure to set Active Job
|
1330
|
-
queue adapter to `:test` or `:inline`:
|
1331
|
-
|
1332
|
-
```rb
|
1333
|
-
# config/environments/test.rb
|
1334
|
-
Rails.application.configure do |config|
|
1335
|
-
# ...
|
1336
|
-
config.active_job.queue_adapter = :test # or :inline
|
1337
|
-
# ...
|
1338
|
-
end
|
1339
|
-
```
|
1340
|
-
|
1341
1016
|
## Rodauth defaults
|
1342
1017
|
|
1343
1018
|
rodauth-rails changes some of the default Rodauth settings for easier setup:
|
@@ -1444,7 +1119,6 @@ conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
|
|
1444
1119
|
[Rodauth]: https://github.com/jeremyevans/rodauth
|
1445
1120
|
[Sequel]: https://github.com/jeremyevans/sequel
|
1446
1121
|
[feature documentation]: http://rodauth.jeremyevans.net/documentation.html
|
1447
|
-
[JWT gem]: https://github.com/jwt/ruby-jwt
|
1448
1122
|
[Bootstrap]: https://getbootstrap.com/
|
1449
1123
|
[Roda]: http://roda.jeremyevans.net/
|
1450
1124
|
[HMAC]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-HMAC
|
@@ -1453,7 +1127,6 @@ conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
|
|
1453
1127
|
[sequel-activerecord_connection]: https://github.com/janko/sequel-activerecord_connection
|
1454
1128
|
[plugin options]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Plugin+Options
|
1455
1129
|
[hmac]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-HMAC
|
1456
|
-
[OmniAuth]: https://github.com/omniauth/omniauth
|
1457
1130
|
[otp]: http://rodauth.jeremyevans.net/rdoc/files/doc/otp_rdoc.html
|
1458
1131
|
[sms_codes]: http://rodauth.jeremyevans.net/rdoc/files/doc/sms_codes_rdoc.html
|
1459
1132
|
[recovery_codes]: http://rodauth.jeremyevans.net/rdoc/files/doc/recovery_codes_rdoc.html
|
@@ -1474,3 +1147,6 @@ conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
|
|
1474
1147
|
[internal_request]: http://rodauth.jeremyevans.net/rdoc/files/doc/internal_request_rdoc.html
|
1475
1148
|
[composite_primary_keys]: https://github.com/composite-primary-keys/composite_primary_keys
|
1476
1149
|
[path_class_methods]: https://rodauth.jeremyevans.net/rdoc/files/doc/path_class_methods_rdoc.html
|
1150
|
+
[account types]: https://github.com/janko/rodauth-rails/wiki/Account-Types
|
1151
|
+
[custom mailer worker]: https://github.com/janko/rodauth-rails/wiki/Custom-Mailer-Worker
|
1152
|
+
[Turbo]: https://turbo.hotwired.dev/
|