ru.Bee 2.1.1 → 2.2.1
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 +4 -4
- data/lib/db/create_clients.rb +15 -0
- data/lib/rubee/controllers/extensions/auth_tokenable.rb +9 -9
- data/lib/rubee/controllers/middlewares/auth_token_middleware.rb +3 -3
- data/lib/rubee.rb +1 -1
- data/lib/tests/controllers/auth_tokenable_test.rb +80 -8
- data/lib/tests/example_models/client.rb +3 -0
- data/lib/tests/test.db +0 -0
- data/readme.md +51 -2
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 79e7b11e20b2e610c5559d28354d950b38a71e1bd19731b86f962ccc2f6851b0
|
|
4
|
+
data.tar.gz: 27b7137b3328a511782c412efd960aa68c93c3ac54f261383014390f45bea3d1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 05ac2caaca3d97b2c6eca2ba86848956406a68a871f30f9529be79ed95681f50f8beacadd32b0a0c537fbb6dd68581aeaaae2403804948526b83bad77e2657c5
|
|
7
|
+
data.tar.gz: 57cdb088e5165d4374a929969b890443594f765f296ea80adc722be6ef232a6d98cec5d07ffb86890692fdefa94089c5509b3a5d9a2fb3cf7e0be761b5787153
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class CreateClients
|
|
2
|
+
def call
|
|
3
|
+
return if Rubee::SequelObject::DB.tables.include?(:clients)
|
|
4
|
+
|
|
5
|
+
Rubee::SequelObject::DB.create_table(:clients) do
|
|
6
|
+
primary_key(:id)
|
|
7
|
+
String(:name)
|
|
8
|
+
String(:digest_password)
|
|
9
|
+
index(:name)
|
|
10
|
+
# timestamps
|
|
11
|
+
datetime(:created)
|
|
12
|
+
datetime(:updated)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -3,7 +3,7 @@ require 'date'
|
|
|
3
3
|
|
|
4
4
|
module Rubee
|
|
5
5
|
module AuthTokenable
|
|
6
|
-
KEY =
|
|
6
|
+
KEY ="secret#{ENV['JWT_KEY']}#{Date.today}".freeze unless defined?(KEY) # Feel free to cusomtize it
|
|
7
7
|
EXPIRE = 3600 unless defined?(EXPIRE)
|
|
8
8
|
|
|
9
9
|
def self.included(base)
|
|
@@ -27,22 +27,22 @@ module Rubee
|
|
|
27
27
|
@request.env['rack.session']&.[]('authentificated')
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def authentificated_user
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@authentificated_user ||=
|
|
30
|
+
def authentificated_user(user_model: ::User, login: :email, password: :password)
|
|
31
|
+
if params[login] && params[password]
|
|
32
|
+
query_params = { login => params[login], password => params[password] }
|
|
33
|
+
@authentificated_user ||= user_model.where(query_params).first
|
|
34
34
|
elsif @request.cookies['jwt'] && valid_token?
|
|
35
35
|
token = @request.cookies['jwt']
|
|
36
36
|
hash = ::JWT.decode(token, Rubee::AuthTokenable::KEY, true, { algorithm: 'HS256' })
|
|
37
|
-
@authentificated_user ||=
|
|
37
|
+
@authentificated_user ||= user_model.where(login => hash[0][login]).first
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
def authentificate!
|
|
42
|
-
return false unless authentificated_user
|
|
41
|
+
def authentificate!(user_model: ::User, login: :email, password: :password)
|
|
42
|
+
return false unless authentificated_user(user_model:, login:, password:)
|
|
43
43
|
|
|
44
44
|
# Generate token
|
|
45
|
-
payload = {
|
|
45
|
+
payload = { login: { login => params[login] }, klass: user_model.name, exp: Time.now.to_i + EXPIRE }
|
|
46
46
|
@token = ::JWT.encode(payload, KEY, 'HS256')
|
|
47
47
|
# Set jwt token to the browser within cookie, so next browser request will include it.
|
|
48
48
|
# make sure it passed to response_with headers options
|
|
@@ -27,11 +27,11 @@ module Rubee
|
|
|
27
27
|
|
|
28
28
|
def valid_token?(token)
|
|
29
29
|
return false unless token
|
|
30
|
-
|
|
31
30
|
hash = decode_jwt(token)
|
|
32
|
-
|
|
31
|
+
login_params = hash[:login]
|
|
32
|
+
klass = hash[:klass]&.split('::')&.inject(Object) { |o, c| o.const_get(c) }
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
klass&.where(login_params.transform_keys(&:to_sym))&.any?
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def decode_jwt(token)
|
data/lib/rubee.rb
CHANGED
|
@@ -17,7 +17,7 @@ module Rubee
|
|
|
17
17
|
CSS_DIR = File.join(APP_ROOT, LIB, 'css') unless defined?(CSS_DIR)
|
|
18
18
|
ROOT_PATH = File.expand_path(File.join(__dir__, '..')) unless defined?(ROOT_PATH)
|
|
19
19
|
|
|
20
|
-
VERSION = '2.
|
|
20
|
+
VERSION = '2.2.1'
|
|
21
21
|
|
|
22
22
|
require_relative 'rubee/router'
|
|
23
23
|
require_relative 'rubee/logger'
|
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
require_relative '../test_helper'
|
|
2
2
|
|
|
3
|
+
class TestController < Rubee::BaseController
|
|
4
|
+
include(Rubee::AuthTokenable)
|
|
5
|
+
auth_methods(:show)
|
|
6
|
+
def show
|
|
7
|
+
response_with(type: :json, object: { ok: :ok })
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# POST /test/login (login logic)
|
|
11
|
+
def login
|
|
12
|
+
if authentificate! # AuthTokenable method that init @token_header
|
|
13
|
+
# Redirect to restricted area, make sure headers: @token_header is passed
|
|
14
|
+
response_with(type: :json, object: { ok: :ok }, headers: @token_header)
|
|
15
|
+
else
|
|
16
|
+
@error = "Wrong email or password"
|
|
17
|
+
response_with(type: :json, object: { error: 'user unauthenticated' }, status: :unauthenticated)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# POST /test/logout (logout logic)
|
|
22
|
+
def logout
|
|
23
|
+
unauthentificate! # AuthTokenable method aimed to handle logout action.
|
|
24
|
+
# Make sure @zeroed_token_header is paRssed within headers options
|
|
25
|
+
response_with(type: :json, object: { ok: 'logged out' }, headers: @zeroed_token_header)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class TesttwoController < Rubee::BaseController
|
|
30
|
+
include(Rubee::AuthTokenable)
|
|
31
|
+
auth_methods(:show)
|
|
32
|
+
def show
|
|
33
|
+
response_with(type: :json, object: { ok: :ok })
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# POST /testtwo/login (login logic)
|
|
37
|
+
def login
|
|
38
|
+
if authentificate!(user_model: Client, login: :name, password: :digest_password)
|
|
39
|
+
response_with(type: :json, object: { ok: :ok }, headers: @token_header)
|
|
40
|
+
else
|
|
41
|
+
@error = "Wrong email or password"
|
|
42
|
+
response_with(type: :json, object: { error: 'user unauthenticated' }, status: :unauthenticated)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# POST /testtwo/logout (logout logic)
|
|
47
|
+
def logout
|
|
48
|
+
unauthentificate!(user_model: Client, login: :name, password: :digest_password)
|
|
49
|
+
response_with(type: :json, object: { ok: 'logged out' }, headers: @zeroed_token_header)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
3
53
|
class AuthTokenableTest < Minitest::Test
|
|
4
54
|
include Rack::Test::Methods
|
|
5
55
|
|
|
@@ -9,21 +59,43 @@ class AuthTokenableTest < Minitest::Test
|
|
|
9
59
|
|
|
10
60
|
def setup
|
|
11
61
|
Rubee::Autoload.call
|
|
62
|
+
Rubee::Router.draw do |route|
|
|
63
|
+
route.post('/test/login', to: 'test#login')
|
|
64
|
+
route.post('/test/logout', to: 'test#logout')
|
|
65
|
+
route.get('/test/show', to: 'test#show')
|
|
66
|
+
route.post('/testtwo/login', to: 'testtwo#login')
|
|
67
|
+
route.post('/testtwo/logout', to: 'testtwo#logout')
|
|
68
|
+
route.get('/testtwo/show', to: 'testtwo#show')
|
|
69
|
+
end
|
|
70
|
+
User.create(email: '9oU8S@example.com', password: '123456')
|
|
71
|
+
Client.create(name: '9o@example.com', digest_password: '123456')
|
|
12
72
|
end
|
|
13
73
|
|
|
14
|
-
def
|
|
15
|
-
|
|
16
|
-
return unless WelcomeController.instance_variable_defined?(:@auth_methods)
|
|
74
|
+
def test_test_controller_included_auth_tokenable
|
|
75
|
+
get('/test/show')
|
|
17
76
|
|
|
18
|
-
|
|
77
|
+
assert_equal(last_response.status, 401)
|
|
19
78
|
end
|
|
20
79
|
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
|
|
80
|
+
def test_test_controller_included_auth_tokenable_authenticated
|
|
81
|
+
post('/test/login', { email: '9oU8S@example.com', password: '123456' })
|
|
82
|
+
rack_mock_session.cookie_jar["jwt"] = last_response.cookies["jwt"].value.last
|
|
83
|
+
get('/test/show')
|
|
24
84
|
|
|
25
|
-
|
|
85
|
+
assert_equal(last_response.status, 200)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def test_test_controller_included_auth_tokenable_unauthenticated_custom_model
|
|
89
|
+
get('/testtwo/show')
|
|
26
90
|
|
|
27
91
|
assert_equal(last_response.status, 401)
|
|
28
92
|
end
|
|
93
|
+
|
|
94
|
+
def test_test_controller_included_auth_tokenable_authenticated_custom_model
|
|
95
|
+
post('/testtwo/login', { name: '9o@example.com', digest_password: '123456' })
|
|
96
|
+
rack_mock_session.cookie_jar["jwt"] = last_response.cookies["jwt"].value.last
|
|
97
|
+
get('/testtwo/show')
|
|
98
|
+
|
|
99
|
+
assert_equal(last_response.status, 200)
|
|
100
|
+
end
|
|
29
101
|
end
|
data/lib/tests/test.db
CHANGED
|
Binary file
|
data/readme.md
CHANGED
|
@@ -151,14 +151,14 @@ cd my_project
|
|
|
151
151
|
|
|
152
152
|
***Prerequisites***<br />
|
|
153
153
|
Make sure:
|
|
154
|
-
**Ruby** language (3.1
|
|
154
|
+
**Ruby** language (3.1 or higher, 3.4.1 recommended) is installed
|
|
155
155
|
**Bundler** is installed
|
|
156
156
|
|
|
157
157
|
```bash
|
|
158
158
|
bundle install
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
4. Run
|
|
161
|
+
4. Run ru.Bee server. Default port is 7000
|
|
162
162
|
```bash
|
|
163
163
|
rubee start # or rubee start_dev for development
|
|
164
164
|
|
|
@@ -978,6 +978,7 @@ rubee db run:create_users
|
|
|
978
978
|
This will create table users and initiate first user with demo credentials.
|
|
979
979
|
email: "ok@ok.com", password: "password"
|
|
980
980
|
Feel free to customize it in the /db/create_users.rb file before running migration.
|
|
981
|
+
Please note user model is default but are free to use any model you need. See more examples below.
|
|
981
982
|
|
|
982
983
|
Then in the controller you can include the AuthTokenable module and use its methods:
|
|
983
984
|
```ruby
|
|
@@ -1015,6 +1016,54 @@ class UsersController < Rubee::BaseController
|
|
|
1015
1016
|
end
|
|
1016
1017
|
end
|
|
1017
1018
|
```
|
|
1019
|
+
For security reason it is recommended to initialize JWT_KEY while starting ru.Bee application.
|
|
1020
|
+
```bash
|
|
1021
|
+
JWT_KEY=SDJwer0wer23j rubee start
|
|
1022
|
+
```
|
|
1023
|
+
User is a default model for validation but using it is not a mandatory. You can use any model you need by
|
|
1024
|
+
passing arguments to authentificate! and unauthentificate! methods.
|
|
1025
|
+
|
|
1026
|
+
```ruby
|
|
1027
|
+
class Client < Sequel::Model
|
|
1028
|
+
attr_accessor :id, :name, :digest_password, :created, :updated
|
|
1029
|
+
end
|
|
1030
|
+
|
|
1031
|
+
class ClientController < Rubee::BaseController
|
|
1032
|
+
include Rubee::AuthTokenable
|
|
1033
|
+
# List methods you want to restrict
|
|
1034
|
+
auth_methods :index
|
|
1035
|
+
|
|
1036
|
+
# GET /clinets/login (login form page)
|
|
1037
|
+
def edit
|
|
1038
|
+
response_with
|
|
1039
|
+
end
|
|
1040
|
+
|
|
1041
|
+
# POST /clients/login (login logic)
|
|
1042
|
+
def login
|
|
1043
|
+
if authentificate! user_model: Client, login: :name, password: :digest_password
|
|
1044
|
+
response_with type: :redirect, to: "/clinets", headers: @token_header
|
|
1045
|
+
else
|
|
1046
|
+
@error = "Wrong login or password"
|
|
1047
|
+
response_with render_view: "clinets_edit"
|
|
1048
|
+
end
|
|
1049
|
+
end
|
|
1050
|
+
|
|
1051
|
+
# POST /clinets/logout
|
|
1052
|
+
def logout
|
|
1053
|
+
unauthentificate! user_model: Client, login: :name, password: :digest_password
|
|
1054
|
+
response_with type: :redirect, to: "/clients/login", headers: @zeroed_token_header
|
|
1055
|
+
end
|
|
1056
|
+
|
|
1057
|
+
# GET /clinets (restricted endpoint)
|
|
1058
|
+
def index
|
|
1059
|
+
response_with object: Client.all, type: :json
|
|
1060
|
+
end
|
|
1061
|
+
end
|
|
1062
|
+
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
[Back to content](#content)
|
|
1066
|
+
|
|
1018
1067
|
## OAuth authentification
|
|
1019
1068
|
If you want to plug in the OAuth 2.0 authentication, you can use the following code using OAuth2 gem:
|
|
1020
1069
|
First thing you need to do is to add the gem to your Gemfile
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ru.Bee
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Oleg Saltykov
|
|
@@ -58,6 +58,7 @@ files:
|
|
|
58
58
|
- lib/css/app.css
|
|
59
59
|
- lib/db/create_accounts.rb
|
|
60
60
|
- lib/db/create_addresses.rb
|
|
61
|
+
- lib/db/create_clients.rb
|
|
61
62
|
- lib/db/create_comments.rb
|
|
62
63
|
- lib/db/create_posts.rb
|
|
63
64
|
- lib/db/create_users.rb
|
|
@@ -280,6 +281,7 @@ files:
|
|
|
280
281
|
- lib/tests/controllers/users_controller_test.rb
|
|
281
282
|
- lib/tests/example_models/account.rb
|
|
282
283
|
- lib/tests/example_models/address.rb
|
|
284
|
+
- lib/tests/example_models/client.rb
|
|
283
285
|
- lib/tests/example_models/comment.rb
|
|
284
286
|
- lib/tests/example_models/post.rb
|
|
285
287
|
- lib/tests/example_models/user.rb
|