remotty-rails 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/Gemfile +18 -0
- data/LICENSE.txt +22 -0
- data/README.md +234 -0
- data/Rakefile +2 -0
- data/app/controllers/remotty/base_application_controller.rb +36 -0
- data/app/controllers/remotty/users/base_controller.rb +16 -0
- data/app/controllers/remotty/users/confirmations_controller.rb +25 -0
- data/app/controllers/remotty/users/omniauth_callbacks_controller.rb +102 -0
- data/app/controllers/remotty/users/passwords_controller.rb +47 -0
- data/app/controllers/remotty/users/registrations_controller.rb +132 -0
- data/app/controllers/remotty/users/sessions_controller.rb +48 -0
- data/app/models/remotty/base_user.rb +83 -0
- data/app/serializers/remotty/user_serializer.rb +30 -0
- data/config/locales/ko.yml +58 -0
- data/lib/generators/remotty/rails/install_generator.rb +68 -0
- data/lib/generators/remotty/rails/templates/add_column_to_users.rb +42 -0
- data/lib/generators/remotty/rails/templates/auth_token.rb +22 -0
- data/lib/generators/remotty/rails/templates/create_auth_tokens.rb +28 -0
- data/lib/generators/remotty/rails/templates/create_oauth_authentications.rb +28 -0
- data/lib/generators/remotty/rails/templates/oauth_authentication.rb +18 -0
- data/lib/generators/remotty/rails/templates/paperclip_hash.rb +1 -0
- data/lib/generators/remotty/rails/templates/user_serializer.rb +3 -0
- data/lib/remotty/rails.rb +8 -0
- data/lib/remotty/rails/authentication.rb +6 -0
- data/lib/remotty/rails/authentication/json_auth_failure.rb +29 -0
- data/lib/remotty/rails/authentication/strategies/token_header_authenticable.rb +71 -0
- data/lib/remotty/rails/engine.rb +72 -0
- data/lib/remotty/rails/version.rb +5 -0
- data/rdoc.sh +3 -0
- data/remotty-rails.gemspec +35 -0
- metadata +231 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0775052ff14b274bde5cb2946958851c7679d547
|
4
|
+
data.tar.gz: 9e29cbf6c8d47dfa73ae6717b985715a790ab400
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: daba021256deb24ad4492d4f12c9ff94b96d616c989cf8076227c50e432aa990b73a12a49adc04a8619bcd28e98bc13f16bd7923b78138e84b252e8999f48b30
|
7
|
+
data.tar.gz: 0a3b34fef53c7a60239b97f0cc47175d371c3092fca263d88cf7a3041832297b9a8f12160a6580b2b44b73861f82310877f79ccf1ca4089a26c44f084e683ca7
|
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
|
24
|
+
.idea
|
data/Gemfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in remotty-rails.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'rack-cors', :require => 'rack/cors'
|
7
|
+
gem 'active_model_serializers'
|
8
|
+
|
9
|
+
# Authentication
|
10
|
+
gem 'devise'
|
11
|
+
gem 'omniauth-facebook'
|
12
|
+
gem 'omniauth-twitter'
|
13
|
+
|
14
|
+
# File upload
|
15
|
+
gem 'paperclip'
|
16
|
+
gem 'open_uri_redirections'
|
17
|
+
gem 'rmagick', require: false
|
18
|
+
gem 'fog'
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Chungsub Kim
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
# remotty-rails
|
2
|
+
|
3
|
+
AngularJS + Rails API를 사용할 때 기본적인 셋팅을 도와주어 빠른 초기 셋팅을 가능하게 합니다.
|
4
|
+
|
5
|
+
## Description
|
6
|
+
|
7
|
+
### 적용사항
|
8
|
+
|
9
|
+
* header의 token을 이용한 인증처리
|
10
|
+
* auth_token model 추가
|
11
|
+
* facebook/twitter oauth login
|
12
|
+
* oauth_authentication model 추가
|
13
|
+
* join
|
14
|
+
* email
|
15
|
+
* oauth (facebook/twitter)
|
16
|
+
* email이 없는 경우도 처리
|
17
|
+
* custom devise controller
|
18
|
+
* full customizing
|
19
|
+
* json response
|
20
|
+
* sessions controller
|
21
|
+
* registrations controller
|
22
|
+
* confirmations controller
|
23
|
+
* passwords controller
|
24
|
+
* omniauth_callbacks controller
|
25
|
+
* user model
|
26
|
+
* use avatar for profile image
|
27
|
+
* use paperclip for attachment
|
28
|
+
* use serializer for json response
|
29
|
+
* CORS
|
30
|
+
* no cookie/no session
|
31
|
+
|
32
|
+
### Token Based Header Authenticable
|
33
|
+
|
34
|
+
header에 email과 token을 전달하여 인증을 처리함
|
35
|
+
|
36
|
+
* X-Auth-Email : e-mail
|
37
|
+
* X-Auth-Token : auth token
|
38
|
+
* X-Auth-Device : source (web(default)/ios/android/...)
|
39
|
+
* X-Auth-Device-Info : source info (ip(default)/...)
|
40
|
+
|
41
|
+
### JSON format
|
42
|
+
|
43
|
+
* disable root globally
|
44
|
+
* failure default syntax
|
45
|
+
|
46
|
+
```json
|
47
|
+
{
|
48
|
+
"error":{
|
49
|
+
"code":"ERROR_CODE",
|
50
|
+
"message":"error message"
|
51
|
+
}
|
52
|
+
}
|
53
|
+
```
|
54
|
+
|
55
|
+
### Controller Helper
|
56
|
+
|
57
|
+
* render_error helper
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
def render_error(code = 'ERROR', message = '', status = 400)
|
61
|
+
render json: {
|
62
|
+
error: {
|
63
|
+
code: code,
|
64
|
+
message: message
|
65
|
+
}
|
66
|
+
}, :status => status
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
|
71
|
+
## Library
|
72
|
+
|
73
|
+
remotty-rails에서 사용중인 라이브러리 입니다.
|
74
|
+
|
75
|
+
* `rails-api`
|
76
|
+
* Rails for API only application (https://github.com/rails-api/rails-api)
|
77
|
+
* `active_model_serializers`
|
78
|
+
* JSON serialization of objects (https://github.com/rails-api/active_model_serializers)
|
79
|
+
* `paperclip`+`rmagick`+`fog`+`httparty`
|
80
|
+
* Easy file attachment management (https://github.com/thoughtbot/paperclip)
|
81
|
+
* `devise`
|
82
|
+
* Flexible authentication solution (https://github.com/plataformatec/devise)
|
83
|
+
|
84
|
+
|
85
|
+
## Installation
|
86
|
+
|
87
|
+
* Create Rails API Project
|
88
|
+
|
89
|
+
```sh
|
90
|
+
$ gem install rails -v 4.0.5 --no-ri --no-rdoc
|
91
|
+
$ rails-api new {{project}} --skip-test-unit --skip-sprockets
|
92
|
+
```
|
93
|
+
|
94
|
+
* Add this line to your application's Gemfile:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
gem 'remotty-rails'
|
98
|
+
gem 'devise'
|
99
|
+
gem 'omniauth-facebook'
|
100
|
+
gem 'omniauth-twitter'
|
101
|
+
gem 'paperclip'
|
102
|
+
```
|
103
|
+
|
104
|
+
* And then execute:
|
105
|
+
|
106
|
+
```sh
|
107
|
+
$ bundle
|
108
|
+
```
|
109
|
+
|
110
|
+
* install devise
|
111
|
+
|
112
|
+
```sh
|
113
|
+
$ rails generate devise:install
|
114
|
+
$ rails generate devise User
|
115
|
+
```
|
116
|
+
|
117
|
+
* install remotty-rails
|
118
|
+
|
119
|
+
`initializers/devise.rb`에서 `config.secret_key` 주석 지우고 작업
|
120
|
+
|
121
|
+
```
|
122
|
+
$ rails generate remotty:rails:install
|
123
|
+
$ rake db:migrate
|
124
|
+
```
|
125
|
+
|
126
|
+
* `config/routes.rb` update
|
127
|
+
|
128
|
+
`devise_for :users`를 지우고 추가함
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
devise_for :users,
|
132
|
+
:path => 'api/v1/session',
|
133
|
+
:path_names => {
|
134
|
+
sign_in: 'login',
|
135
|
+
sign_out: 'logout'
|
136
|
+
},
|
137
|
+
:controllers => { sessions: 'remotty/users/sessions',
|
138
|
+
registrations: 'remotty/users/registrations',
|
139
|
+
confirmations: 'remotty/users/confirmations',
|
140
|
+
passwords: 'remotty/users/passwords',
|
141
|
+
omniauth_callbacks: 'remotty/users/omniauth_callbacks'}
|
142
|
+
```
|
143
|
+
|
144
|
+
## Recommend Setting
|
145
|
+
|
146
|
+
### 유용한 Gemfile
|
147
|
+
|
148
|
+
`Gemfile` update
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
group :development do
|
152
|
+
gem 'thin'
|
153
|
+
gem 'annotate'
|
154
|
+
gem 'better_errors'
|
155
|
+
gem 'binding_of_caller'
|
156
|
+
gem 'letter_opener'
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
160
|
+
### sendmail test
|
161
|
+
|
162
|
+
`development.rb` update
|
163
|
+
`letter_opener`는 gem 추가해야함 `gem 'letter_opener'`
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
config.action_mailer.default_url_options = { host: 'localhost:9000' }
|
167
|
+
config.action_mailer.delivery_method = :letter_opener
|
168
|
+
```
|
169
|
+
|
170
|
+
### custom mail view
|
171
|
+
|
172
|
+
|
173
|
+
`views/devise/mailer/confirmation_instructions.html.erb` create
|
174
|
+
`views/devise/mailer/reset_password_instructions.html.erb` create
|
175
|
+
|
176
|
+
|
177
|
+
### token 유효기간 변경
|
178
|
+
|
179
|
+
`initializers/devise.rb` update
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
config.remember_for = 2.weeks
|
183
|
+
```
|
184
|
+
|
185
|
+
### omniauth setting
|
186
|
+
|
187
|
+
`devise.rb` update
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
config.omniauth :facebook,
|
191
|
+
Settings.omniauth.facebook.app_id,
|
192
|
+
Settings.omniauth.facebook.app_secret,
|
193
|
+
{
|
194
|
+
scope: 'email',
|
195
|
+
image_size: 'large',
|
196
|
+
provider_ignores_state: true
|
197
|
+
}
|
198
|
+
config.omniauth :twitter,
|
199
|
+
Settings.omniauth.twitter.consumer_key,
|
200
|
+
Settings.omniauth.twitter.consumer_secret, {
|
201
|
+
:image_size => 'original',
|
202
|
+
:authorize_params => {
|
203
|
+
:force_login => true
|
204
|
+
},
|
205
|
+
:setup => lambda do |env|
|
206
|
+
req = Rack::Request.new(env)
|
207
|
+
req.session.options[:cookie_only] = true
|
208
|
+
req.session.options[:defer] = false
|
209
|
+
end
|
210
|
+
```
|
211
|
+
|
212
|
+
### devise parameter sanitizer
|
213
|
+
|
214
|
+
user model에 column 추가시 `application_controller.rb` 파일에 추가함
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
class ApplicationController < ActionController::API
|
218
|
+
|
219
|
+
protected
|
220
|
+
|
221
|
+
def configure_permitted_parameters
|
222
|
+
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:name, :email, :password, :current_password, :avatar) }
|
223
|
+
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:name, :avatar, :password, :password_confirmation, :current_password) }
|
224
|
+
end
|
225
|
+
end
|
226
|
+
```
|
227
|
+
|
228
|
+
## Contributing
|
229
|
+
|
230
|
+
1. Fork it ( https://github.com/remotty/remotty-rails/fork )
|
231
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
232
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
233
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
234
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Remotty::BaseApplicationController
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
before_action :authenticate_user!
|
6
|
+
before_action :configure_permitted_parameters, if: :devise_controller?
|
7
|
+
|
8
|
+
# To resolve the following error: ActionController::UnknownFormat
|
9
|
+
include ActionController::StrongParameters
|
10
|
+
|
11
|
+
# To resolve the following error: undefined method `respond_to'
|
12
|
+
# http://railscasts.com/episodes/348-the-rails-api-gem?language=ko&view=asciicast
|
13
|
+
include ActionController::MimeResponds
|
14
|
+
|
15
|
+
# To resolve the following error: undefined method `default_render'
|
16
|
+
# https://github.com/rails-api/rails-api/issues/93
|
17
|
+
include ActionController::ImplicitRender
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def render_error(code = 'ERROR', message = '', status = 400)
|
23
|
+
render json: {
|
24
|
+
error: {
|
25
|
+
code: code,
|
26
|
+
message: message
|
27
|
+
}
|
28
|
+
}, :status => status
|
29
|
+
end
|
30
|
+
|
31
|
+
def configure_permitted_parameters
|
32
|
+
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:name, :email, :password, :current_password, :avatar) }
|
33
|
+
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:name, :avatar, :password, :password_confirmation, :current_password) }
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# base user controller
|
2
|
+
#
|
3
|
+
module Remotty::Users::BaseController
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
protected
|
7
|
+
|
8
|
+
# auth_source 정보 추출 (앱 확장성 고려)
|
9
|
+
def auth_source
|
10
|
+
{
|
11
|
+
source: request.headers['X-Auth-Device'] || 'web',
|
12
|
+
info: request.headers['X-Auth-Device-Info'] || request.remote_ip
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Remotty::Users::ConfirmationsController < Devise::ConfirmationsController
|
2
|
+
include Remotty::Users::BaseController
|
3
|
+
|
4
|
+
# POST /resource/confirmation
|
5
|
+
# 토큰을 이용해 이메일 인증 확인
|
6
|
+
# 이미 사용한 토큰이거나 잘못된 경우는 에러 반환
|
7
|
+
#
|
8
|
+
# ==== return
|
9
|
+
# * +success+ - no_content
|
10
|
+
# * +failure+ - unauthorized with error message
|
11
|
+
#
|
12
|
+
def show
|
13
|
+
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
|
14
|
+
yield resource if block_given?
|
15
|
+
|
16
|
+
if resource.errors.empty?
|
17
|
+
render nothing: true, status: :no_content
|
18
|
+
else
|
19
|
+
render_error 'UNAUTHORIZED',
|
20
|
+
resource.errors.full_messages.first,
|
21
|
+
:unauthorized
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
class Remotty::Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
2
|
+
include Remotty::Users::BaseController
|
3
|
+
include ActionController::Flash
|
4
|
+
|
5
|
+
# omniauth callback 처리
|
6
|
+
# 정보에 따라 유저를 만들던가 연결하던가 추가 정보를 입력받도록 에러를 리턴함
|
7
|
+
#
|
8
|
+
def all
|
9
|
+
# omniauth에서 생성한 session 제거
|
10
|
+
session.options[:skip] = true
|
11
|
+
response.headers['Set-Cookie'] = 'rack.session=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT'
|
12
|
+
|
13
|
+
auth = request.env['omniauth.auth']
|
14
|
+
user = from_omniauth(auth)
|
15
|
+
@ret = {}
|
16
|
+
|
17
|
+
if user && user.persisted?
|
18
|
+
sign_in(:user, user, store: false)
|
19
|
+
token = user.generate_auth_token!(auth_source)
|
20
|
+
@ret = user.with_token(token)
|
21
|
+
elsif user && user.errors.size > 0
|
22
|
+
@ret = {
|
23
|
+
error: {
|
24
|
+
code: 'OAUTH_LOGIN_ERROR_EMAIL_INVALID',
|
25
|
+
message: user.errors.full_messages.first,
|
26
|
+
data: {
|
27
|
+
oauth: {
|
28
|
+
credentials: auth[:credentials],
|
29
|
+
provider: auth[:provider],
|
30
|
+
uid: auth[:uid],
|
31
|
+
info: {
|
32
|
+
name: auth[:info][:name],
|
33
|
+
image: auth[:info][:image]
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
else
|
40
|
+
@ret = {
|
41
|
+
error: {
|
42
|
+
code: 'OAUTH_LOGIN_ERROR',
|
43
|
+
message: 'require provider & uid!!'
|
44
|
+
}
|
45
|
+
}
|
46
|
+
@ret[:error][:data] = user if user
|
47
|
+
end
|
48
|
+
|
49
|
+
render :inline => "<script>window.opener.oauthCallback(#{@ret.to_json}); window.close();</script>"
|
50
|
+
end
|
51
|
+
|
52
|
+
def failure
|
53
|
+
@ret = {
|
54
|
+
error: {
|
55
|
+
code: OmniAuth::Utils.camelize(failed_strategy.name),
|
56
|
+
message: failure_message
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
render :inline => "<script>window.opener.oauthCallback(#{@ret.to_json}); window.close();</script>"
|
61
|
+
end
|
62
|
+
|
63
|
+
alias_method :facebook, :all
|
64
|
+
alias_method :twitter, :all
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# omniauth callback 분석
|
69
|
+
def from_omniauth(auth)
|
70
|
+
if auth[:provider] && auth[:uid] # 인증정보가 있으면..
|
71
|
+
oauth = OauthAuthentication.find_by_provider_and_uid(auth[:provider], auth[:uid])
|
72
|
+
if oauth # 이미 가입되어 있다면 oauth 정보를 갱신함
|
73
|
+
oauth.update_with_credential(auth[:credentials])
|
74
|
+
oauth.save
|
75
|
+
|
76
|
+
return oauth.user
|
77
|
+
else # 가입 정보가 없음!
|
78
|
+
if auth[:info][:email].present? # 이메일이 있으면 가입 또는 연동
|
79
|
+
user = User.find_or_create_by(email: auth[:info][:email]) do |u|
|
80
|
+
u.name = auth[:info][:name] || auth[:info][:email]
|
81
|
+
u.password = Devise.friendly_token[0,20]
|
82
|
+
u.skip_confirmation!
|
83
|
+
u.save
|
84
|
+
end
|
85
|
+
user.confirm! # 인증 대기 중이면 바로 인증시켜버림
|
86
|
+
|
87
|
+
# oauth 정보 생성
|
88
|
+
user.add_oauth_info(auth)
|
89
|
+
|
90
|
+
return user
|
91
|
+
else # 이메일이 없으면 추가정보를 입력받도록 함
|
92
|
+
user = User.new
|
93
|
+
user.errors.add(:email, "email required")
|
94
|
+
|
95
|
+
return user
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
end
|