anadea-identity 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +174 -0
  4. data/Rakefile +10 -0
  5. data/app/assets/images/facebook.png +0 -0
  6. data/app/assets/images/google_oauth2.png +0 -0
  7. data/app/assets/images/twitter.png +0 -0
  8. data/app/controllers/identity/base_controller.rb +5 -0
  9. data/app/controllers/identity/omniauth_callbacks_controller.rb +24 -0
  10. data/app/controllers/identity/users_controller.rb +58 -0
  11. data/app/models/identity/role.rb +16 -0
  12. data/app/models/identity/user.rb +47 -0
  13. data/app/views/devise/confirmations/new.html.erb +23 -0
  14. data/app/views/devise/mailer/confirmation_instructions.html.erb +6 -0
  15. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  16. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  17. data/app/views/devise/passwords/edit.html.erb +28 -0
  18. data/app/views/devise/passwords/new.html.erb +21 -0
  19. data/app/views/devise/registrations/edit.html.erb +34 -0
  20. data/app/views/devise/registrations/new.html.erb +28 -0
  21. data/app/views/devise/sessions/new.html.erb +31 -0
  22. data/app/views/devise/shared/_links.erb +25 -0
  23. data/app/views/devise/unlocks/new.html.erb +20 -0
  24. data/app/views/identity/users/edit.html.erb +70 -0
  25. data/app/views/identity/users/index.html.erb +55 -0
  26. data/config/locales/ca.yml +59 -0
  27. data/config/locales/de.yml +110 -0
  28. data/config/locales/en.yml +111 -0
  29. data/config/locales/es-AR.yml +51 -0
  30. data/config/locales/es-ES.yml +59 -0
  31. data/config/locales/es.yml +51 -0
  32. data/config/locales/fr.yml +51 -0
  33. data/config/locales/hu.yml +59 -0
  34. data/config/locales/it.yml +51 -0
  35. data/config/locales/nl.yml +59 -0
  36. data/config/locales/pl.yml +57 -0
  37. data/config/locales/pt-BR.yml +51 -0
  38. data/config/locales/ru.yml +56 -0
  39. data/config/locales/tr.yml +51 -0
  40. data/config/locales/zh-CN.yml +57 -0
  41. data/config/locales/zh-TW.yml +57 -0
  42. data/config/routes.rb +5 -0
  43. data/db/migrate/20150402142437_devise_create_identity_users.rb +42 -0
  44. data/db/migrate/20150402152859_rolify_create_identity_roles.rb +19 -0
  45. data/lib/anadea/identity.rb +1 -0
  46. data/lib/generators/identity/locales_generator.rb +8 -0
  47. data/lib/generators/identity/views_generator.rb +8 -0
  48. data/lib/identity.rb +50 -0
  49. data/lib/identity/admin/user.rb +89 -0
  50. data/lib/identity/devise_config.rb +31 -0
  51. data/lib/identity/engine.rb +21 -0
  52. data/lib/identity/version.rb +3 -0
  53. data/lib/identity/view_helper.rb +22 -0
  54. data/lib/tasks/whoami_tasks.rake +4 -0
  55. metadata +157 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b90fe456fe3459656452c7191052e3cf7b9e72bd
4
+ data.tar.gz: 7942ef52f965589850dc1e2d9b1be489aaf96fac
5
+ SHA512:
6
+ metadata.gz: 351d14c0435915e9e1324bbca2b9e53dbcda6764044e16b8138de4d24e2ca44bbf7525e343623104243ab18a0145b38028e2d62a0cd27a7718373bd413f46b8a
7
+ data.tar.gz: d072c2f56d804f4174305d38f4bc1bb3a412359b66a0d739e92742bd7f1a917a8f9d392e7d4c9c190eaa501c74cd81d60f3ed3ceeffe61e19571795de94ca112
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 Anadea
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # Identity
2
+
3
+ Аутентификация и авторизация для Rails приложения.
4
+
5
+ ## Установка
6
+
7
+ Добавьте строчку в Gemfile приложения:
8
+
9
+ ```ruby
10
+ gem 'anadea-identity'
11
+ ```
12
+
13
+ и запустите в консоли:
14
+
15
+ ```console
16
+ $ bundle
17
+ ```
18
+
19
+ Сгенерируйте миграции:
20
+
21
+ ```console
22
+ $ rake identity_engine:install:migrations
23
+ ```
24
+
25
+ проверьте их и запустите:
26
+
27
+ ```console
28
+ $ rake db:migrate
29
+ ```
30
+
31
+ ## Использование
32
+
33
+ ### Аутентификация
34
+
35
+ Проверьте маршруты: `rake routes`. Вы увидите набор маршрутов, подобных тем, что
36
+ даёт [Devise](https://github.com/plataformatec/devise). Собственно, Identity и
37
+ есть не слишком толстая обёртка поверх Devise.
38
+
39
+ У вас работает логин (через форму email/пароль), регистрация (через форму
40
+ email/пароль/подтверждение пароля), восстановление пароля и многое другое.
41
+
42
+ ### Модель User
43
+
44
+ Вызов `current_user` в контроллере вернёт `Identity::User`, соответствующий
45
+ таблице `identity_users`. Не нужно добавлять в эту модель методы и не нужно
46
+ добавлять в эту таблицу колонки, кроме тех, которые используются Devise или
47
+ Identity. Эту модель следует считать публичным интерфейсом, предоставляеым гемом.
48
+
49
+ Рекомендуется заводить модели типа `Profile` или `Account` которые будут
50
+ "принадлежать" (`belong_to :user, class_name: "Identity::User"`) этой модели
51
+ и ссылаться на неё с помощью внешнего ключа.
52
+
53
+ ### Авторизация
54
+
55
+ Модель `Identity::User` расширена ролями с помощью
56
+ [Rolify](https://github.com/RolifyCommunity/rolify). В частности, у вас есть
57
+ говорящие за себя методы:
58
+
59
+ ```ruby
60
+ user.add_role :manager
61
+ user.remove_role :manager
62
+ user.has_role? :manager
63
+
64
+ Identity::User.with_role :manager
65
+ ```
66
+
67
+ У вас есть многое другое – смотрите документацию Rolify.
68
+
69
+ Используйте эти методы в вызовах вашего авторизационного фреймворка, такого, как
70
+ [CanCanCan](https://github.com/CanCanCommunity/cancancan).
71
+
72
+ ### Админка
73
+
74
+ Чтобы получить админку по пользователям, подключите
75
+ [ActiveAdmin](https://github.com/activeadmin/activeadmin) и сгенерируйте
76
+ конфигурационный файл без генерации пользователей (`--skip-users`).
77
+
78
+ ### Конфигурация
79
+
80
+ Создайте руби-файл в `config/initializers` со следующим содержимым:
81
+
82
+ ```ruby
83
+ Identity.setup do |config|
84
+ config.devise_modules += [:confirmable]
85
+ # и много других конфигурационных опций
86
+ end
87
+ ```
88
+
89
+ #### Доступные опции
90
+
91
+ Вы всегда можете узнать полный список конфигурацинных опций и их значения по
92
+ умолчанию, ознакомившись [с исходным кодом](lib/identity.rb).
93
+
94
+ * `config.devise_modules` – модули Devise, которые вы используете. Например,
95
+ выключение `registerable` приведёт к невозможности зарегистрироваться, в том
96
+ числе, исчезнет соответствующая ссылка, а включение `confirmable` приведёт к
97
+ тому, что приложение станет требовать подтверждение адреса электронной почты,
98
+ при условии, что в таблице `identity_users` есть соответствующие колонки
99
+ (по умолчанию нет).
100
+
101
+ Вы можете как модифицировать этот массив, так и полностью его переопределить:
102
+
103
+ ```ruby
104
+ config.devise_modules += [:confirmable]
105
+ config.devise_modules = [:database_authenticatable, :omniauthable, ...]
106
+ ```
107
+
108
+ По умолчанию включены модули database_authenticatable, registerable,
109
+ recoverable, rememberable, trackable и validatable. Если включить хотя бы один
110
+ omniauth provider, автоматически подключится omniauthable. За подробным их
111
+ описанием обратитесь в документацию Devise.
112
+
113
+ * `config.layout` – макет (layout), используемый формами логина, регистрации и
114
+ прочего. По умолчанию используется главный макет вашего приложения –
115
+ `"application"`.
116
+
117
+ * `config.auth_routes` – если задать `false`, маршруты подключены не будут и вы
118
+ можете сами подключить их.
119
+
120
+ * `config.admin_role` – "главная" роль в приложении. Роль, которой можно
121
+ управлять из предлаемой гемом админки, и роль, которая по умолчанию является
122
+ допуском в эту админку.
123
+
124
+ Вы также можете использовать любые конфигурационные опции самого Devise.
125
+ Они будут переданы Devise в точности. Например:
126
+
127
+ ```ruby
128
+ config.parent_controller = "ApplicationController"
129
+ ```
130
+
131
+ За подробным списком того, что можно сконфигурировать в Devise, обратитесь к его
132
+ документации.
133
+
134
+ #### Сделанные кастомизации в конфигурации Devise.
135
+
136
+ Мы делаем небольшие изменения в конфигурации Devise по умолчанию. Вы можете это
137
+ увидеть в [исходном коде гема](lib/identity/devise_config.rb).
138
+
139
+ * `config.mailer_sender` – мы достаём это из переменной окружения MAIL_FROM.
140
+ * `config.sign_out_via` – GET и только GET. Это должно работать без джаваскрипта.
141
+ * `config.parent_controller` – мы не наследуемся от `ApplicationController` вашего
142
+ приложения. Devise предлагает для этого определять методы в
143
+ `ApplicationController`.Если вам нужно переопределить поведение аутентификационных
144
+ контроллеров, мы рекомендуем создать специальный базовый контроллер в
145
+ приложении и указать его в качестве `parent_controller`. Затем определять в
146
+ нём методы типа `after_sign_in_path_for`, как и предлагает Devise.
147
+
148
+ ### Логин через Facebook.
149
+
150
+ Для того, чтобы включить в приложении логин через Facebook нужно:
151
+
152
+ * подключить `gem 'omniauth-facebook'` в своем Gemfile.
153
+ * указать `config.omniauth :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']`
154
+ в `config/initializers/identity.rb`.
155
+ * создать приложение в Facebook можно с помощью [инструкции](https://getsocio.com/Help/How_to_set_up_Facebook_Application).
156
+
157
+ ### Логин через Twitter.
158
+
159
+ Для того, чтобы включить в приложении логин через Twitter нужно:
160
+
161
+ * подключить `gem 'omniauth-twitter'` в своем Gemfile.
162
+ * указать `config.omniauth :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']`
163
+ в `config/initializers/identity.rb`.
164
+ * создать приложение в Twitter можно [здесь](https://apps.twitter.com/).
165
+
166
+ ### Логин через Google.
167
+
168
+ Для того, чтобы включить в приложении логин через Google нужно:
169
+
170
+ * подключить `gem 'omniauth-google-oauth2'` в своем Gemfile.
171
+ * указать `config.omniauth :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET']`
172
+ в `config/initializers/identity.rb`.
173
+ * создать приложение в Google можно [здесь](https://console.developers.google.com/project).
174
+ * для создания приложения можно воспользоваться [инструкцией](https://developers.google.com/identity/protocols/OpenIDConnect#appsetup)
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "bundler/setup"
3
+
4
+
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ task default: :spec
8
+
9
+ APP_RAKEFILE = File.expand_path("../spec/rails_app/Rakefile", __FILE__)
10
+ load 'rails/tasks/engine.rake'
Binary file
Binary file
Binary file
@@ -0,0 +1,5 @@
1
+ module Identity
2
+ class BaseController < ActionController::Base
3
+ layout Identity.layout
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ module Identity
2
+ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
3
+ def facebook
4
+ omniauth_login('Facebook')
5
+ end
6
+
7
+ def twitter
8
+ omniauth_login('Twitter')
9
+ end
10
+
11
+ def google_oauth2
12
+ omniauth_login('Google')
13
+ end
14
+
15
+ private
16
+
17
+ def omniauth_login(title)
18
+ @user = Identity::User.from_omniauth!(request.env["omniauth.auth"])
19
+
20
+ set_flash_message(:notice, :success, :kind => title) if is_navigational_format?
21
+ sign_in_and_redirect @user, :event => :authentication
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,58 @@
1
+ module Identity
2
+ class UsersController < ActionController::Base
3
+ layout Identity.admin_layout
4
+ before_action :ensure_allowed!
5
+ helper_method :resource, :resources
6
+
7
+ def index
8
+ @resources = User.search_and_order(params[:search], params[:page])
9
+ end
10
+
11
+ def show
12
+ redirect_to edit_identity_user_path(params[:id])
13
+ end
14
+
15
+ def edit
16
+ @resource = find_user
17
+ end
18
+
19
+ def update
20
+ @resource = find_user
21
+ if @resource.admin_update(user_params, current?(@resource))
22
+ @resource.skip_reconfirmation! if @resource.respond_to?(:skip_reconfirmation!)
23
+ @resource.save
24
+ redirect_to [Identity.admin_namespace, :users], notice: "#{@resource.email} updated."
25
+ else
26
+ render :edit
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :resource, :resources
33
+
34
+ def ensure_allowed!
35
+ unless Identity.admin_guard[current_user, self]
36
+ raise ActionController::RoutingError.new('Nothing here, move around')
37
+ end
38
+ end
39
+
40
+ def devise_mapping
41
+ request.env["devise.mapping"]
42
+ end
43
+
44
+ def current?(user)
45
+ user.id == current_user.id
46
+ end
47
+
48
+ def find_user
49
+ User.find params[:id]
50
+ end
51
+
52
+ def user_params
53
+ params.require(:identity_user).permit(
54
+ :email, :password, :password_confirmation, :active, Identity.admin_role
55
+ )
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,16 @@
1
+ require "rolify"
2
+
3
+ module Identity
4
+ class Role < ActiveRecord::Base
5
+ self.table_name = 'identity_roles'
6
+
7
+ has_and_belongs_to_many :users, :join_table => :identity_users_identity_roles
8
+ belongs_to :resource, :polymorphic => true
9
+
10
+ validates :resource_type,
11
+ :inclusion => { :in => Rolify.resource_types },
12
+ :allow_nil => true
13
+
14
+ scopify
15
+ end
16
+ end
@@ -0,0 +1,47 @@
1
+ require "devise"
2
+ require "rolify"
3
+ require "kaminari"
4
+
5
+ module Identity
6
+ class User < ActiveRecord::Base
7
+ self.table_name = 'identity_users'
8
+ devise *Identity.devise_modules
9
+
10
+ if Devise.omniauth_providers.any?
11
+ devise :omniauthable, omniauth_providers: Devise.omniauth_providers
12
+ end
13
+
14
+ rolify role_cname: 'Identity::Role'
15
+
16
+ def self.from_omniauth!(auth)
17
+ where(provider: auth.provider, uid: auth.uid).first_or_create! do |user|
18
+ user.email = auth.provider == "twitter" ? "#{auth.info.nickname}_email@example.com" : auth.info.email
19
+ user.password = Devise.friendly_token[0,20]
20
+ end
21
+ end
22
+
23
+ define_singleton_method Identity.admins_method do
24
+ with_role(Identity.admin_role)
25
+ end
26
+
27
+ def self.find_first_by_auth_conditions(tainted_conditions, opts={active: true})
28
+ super
29
+ end
30
+
31
+ def self.active
32
+ result = where(active: true)
33
+ result = result.where.not(confirmed_at: nil) if devise_modules.include?(:confirmable)
34
+ result
35
+ end
36
+
37
+ def role_names
38
+ roles.pluck(:name).sort.join(', ')
39
+ end
40
+
41
+ define_method Identity.admin_role do
42
+ has_role?(Identity.admin_role)
43
+ end
44
+ alias_method Identity.admin_predicate, Identity.admin_role
45
+
46
+ end
47
+ end
@@ -0,0 +1,23 @@
1
+ <div class="row">
2
+ <div class="col-sm-6">
3
+
4
+ <%= bootstrap_devise_error_messages! %>
5
+ <div class="panel panel-default">
6
+ <div class="panel-heading">
7
+ <h4><%= t('.resend_confirmation_instructions', :default => 'Resend confirmation instructions') %></h4>
8
+ </div>
9
+ <div class="panel-body">
10
+ <%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post, role: "form" }) do |f| %>
11
+ <div class="form-group">
12
+ <%= f.label :email %>
13
+ <%= f.email_field :email, autofocus: true, class: "form-control" %>
14
+ </div>
15
+
16
+ <%= f.submit t('.resend_confirmation_instructions', :default => 'Resend confirmation instructions'), class: "btn btn-primary" %>
17
+ <% end %>
18
+ </div>
19
+ </div>
20
+
21
+ <%= render "devise/shared/links" %>
22
+ </div>
23
+ </div>
@@ -0,0 +1,6 @@
1
+ <p><%= t('.greeting', :recipient => @resource.email, :default => "Welcome #{@resource.email}!") %></p>
2
+
3
+ <p><%= t('.instruction', :default => "You can confirm your account email through the link below:") %></p>
4
+
5
+ <p><%= link_to t('.action', :default => "Confirm my account"),
6
+ confirmation_url(@resource, :confirmation_token => @token, locale: I18n.locale) %></p>
@@ -0,0 +1,8 @@
1
+ <p><%= t('.greeting', :recipient => @resource.email, :default => "Hello #{@resource.email}!") %></p>
2
+
3
+ <p><%= t('.instruction', :default => "Someone has requested a link to change your password, and you can do this through the link below.") %></p>
4
+
5
+ <p><%= link_to t('.action', :default => "Change my password"), edit_password_url(@resource, :reset_password_token => @token, locale: I18n.locale) %></p>
6
+
7
+ <p><%= t('.instruction_2', :default => "If you didn't request this, please ignore this email.") %></p>
8
+ <p><%= t('.instruction_3', :default => "Your password won't change until you access the link above and create a new one.") %></p>
@@ -0,0 +1,7 @@
1
+ <p><%= t('.greeting', :recipient => @resource.email, :default => "Hello #{@resource.email}!") %></p>
2
+
3
+ <p><%= t('.message', :default => "Your account has been locked due to an excessive amount of unsuccessful sign in attempts.") %></p>
4
+
5
+ <p><%= t('.instruction', :default => "Click the link below to unlock your account:") %></p>
6
+
7
+ <p><%= link_to t('.action', :default => "Unlock my account"), unlock_url(@resource, :unlock_token => @resource.unlock_token, locale: I18n.locale) %></p>
@@ -0,0 +1,28 @@
1
+ <div class="row">
2
+ <div class="col-sm-6">
3
+ <%= bootstrap_devise_error_messages! %>
4
+ <div class="panel panel-default">
5
+ <div class="panel-heading">
6
+ <h4><%= t('.change_your_password', :default => 'Change your password') %></h4>
7
+ </div>
8
+ <div class="panel-body">
9
+ <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put, role: "form" }) do |f| %>
10
+ <%= f.hidden_field :reset_password_token %>
11
+
12
+ <div class="form-group">
13
+ <%= f.label :password, t('.new_password', :default => 'New password') %>
14
+ <%= f.password_field :password, autofocus: true, class: "form-control" %>
15
+ </div>
16
+
17
+ <div class="form-group">
18
+ <%= f.label :password_confirmation, t('.confirm_new_password', :default => 'Confirm new password') %>
19
+ <%= f.password_field :password_confirmation, class: "form-control" %>
20
+ </div>
21
+
22
+ <%= f.submit t('.change_my_password', :default => 'Change my password'), class: "btn btn-primary" %>
23
+ <% end %>
24
+ </div>
25
+ </div>
26
+ <%= render "devise/shared/links" %>
27
+ </div>
28
+ </div>