devise tutorial - 2011 rubyconf taiwan
DESCRIPTION
[Tutorial] Build your authentication system with DeviseTRANSCRIPT
BUILD YOUR AUTHENTICATION SYSTEM
WITH DEVISETse-Ching Ho (何澤清)
2011-08-26
HTTPS://GITHUB.COM/TSECHINGHO/DEVISE_TUTORIAL
git clone git://github.com/tsechingho/devise_tutorial.git
•OminiAuth Client Applicationproviders: Facebook, Twitter, Github
•OpenID Client Applicationproviders: Google, Yahoo, Google Apps
• LDAP Client Applicationproviders: Localhost OpenLDAP
• CAS Client Applicationproviders: Localhost CAS
AGENDA
WHAT IS AUTHENTICATION ?
ABOUT AUTHENTICATION
• authentication and authorization are two things
• authentication is just an identity token / ticket
• can use multi authentication providers on one site
• one user can have many authentications
CAS server
devise
omniauth
OpenID providers
Oauth providers
LDAP providers
3rd partyproviders
username /password
customer
DEVISE - OMNIAUTH WAY
WHAT DO WE NEED ?
USER STORY PLEASE
updated_at datetime
string
created_at
id
datetime
last_sign_in_ip
integer
last_sign_in_at
remember_created_at
string
datetime
sign_in_count
datetime
string
encrypted_password
datetimereset_password_sent_at
string
current_sign_in_at
datetime
string
integer
reset_password_token
current_sign_in_ip
Model: Managerhas_many :authentications, :as => :resource
has_one :profile, :as => :resource
managers
datetimeupdated_at
created_at datetime
nickname string
fullname string
last_name string
first_name string
resource_type string
resource_id integer
id integer
Model: Profilebelongs_to :resource, :polymorphic => true
profiles
updated_at datetime
datetimecreated_at
umail string
uname string
stringuid
provider string
resource_type string
resource_id integer
id integer
Model: Authenticationbelongs_to :resource, :polymorphic => true
authentications
updated_at datetime
string
created_at
id
datetime
last_sign_in_ip
integer
last_sign_in_at
remember_created_at
string
datetime
sign_in_count
datetime
string
encrypted_password
datetimereset_password_sent_at
string
current_sign_in_at
datetime
string
integer
reset_password_token
current_sign_in_ip
Model: Userhas_many :authentications, :as => :resource
has_one :profile, :as => :resource
users
POSSIBLE DB SCHEMA
WHY DEVISE ?
FEATURES OF DEVISE
• rack - simple and fast
• strategies - logical and flexible
•modularity - maintainable rails engine
•multi-models - signed in at the same time
• extensions - diversity
• authentication scheme with general user’s needs
•Database authenticatable
• Token authenticatable
•Omniauthable
• Confirmable
• Recoverable
• Registerable
• Rememberable
• Trackable
• Timeoutable
• Validatable
• Lockable
• Encryptalbe
BUILDED IN MODULES
EXTENSION MODULES
•ORM
• Encryption
• Authentication
• UI enhancement
• https://github.com/plataformatec/devise/wiki/Extensions
FILTERS & HELPERS
• authenticate_user!
• user_signed_in?
• current_user
• user_session
• user_root_path
DEMO
SHOW, DON’T TELL
GIT LOGS ARE FRIENDS
• rails new devise_tutorial -JTd mysql• cd devise_tutorial• vim Gemfile• bundle install• rails generate scaffold page title:string content:text• rake db:create• rake db:migrate• rails server
bundle exec unicorn -p 3000• tail -f log/development.log
NEW RAILS APP
GIT CHECKOUT HEROKU
• git checkout heroku
• heroku keys:add
• heroku create
• git push heroku master
• heroku rake db:setup
• heroku open
DEPLOY TO HEROKU
GIT CHECKOUT USER
DEVISE CUSTOMIZATION
• config - set configurations for devise
•migrations - set database fields
•models - select modules, set attributes
• routes - set uri mapping
• controllers - set filters and redirects
• views - set html and css
rake middlewareuse ActionDispatch::Staticuse Rack::Lockuse ActiveSupport::Cache::Strategy::LocalCacheuse Rack::Runtimeuse Rails::Rack::Loggeruse ActionDispatch::ShowExceptionsuse ActionDispatch::RemoteIpuse Rack::Sendfileuse ActionDispatch::Callbacksuse ActiveRecord::ConnectionAdapters::ConnectionManagementuse ActiveRecord::QueryCacheuse ActionDispatch::Cookiesuse ActionDispatch::Session::CookieStoreuse ActionDispatch::Flashuse ActionDispatch::ParamsParseruse Rack::MethodOverrideuse ActionDispatch::Headuse ActionDispatch::BestStandardsSupportuse Warden::Managerrun DeviseTutorial::Application.routes
GIT CHECKOUT MANAGER
rake routes manager_root GET /pages/:id(.:format) {:controller=>"pages", :id=>"management", :action=>"show"} new_manager_session GET /managers/sign_in(.:format) {:controller=>"devise/sessions", :action=>"new"} manager_session POST /managers/sign_in(.:format) {:controller=>"devise/sessions", :action=>"create"} destroy_manager_session DELETE /managers/sign_out(.:format) {:controller=>"devise/sessions", :action=>"destroy"} manager_password POST /managers/password(.:format) {:controller=>"devise/passwords", :action=>"create"} new_manager_password GET /managers/password/new(.:format) {:controller=>"devise/passwords", :action=>"new"} edit_manager_password GET /managers/password/edit(.:format) {:controller=>"devise/passwords", :action=>"edit"} PUT /managers/password(.:format) {:controller=>"devise/passwords", :action=>"update"}cancel_manager_registration GET /managers/cancel(.:format) {:controller=>"devise/registrations", :action=>"cancel"} manager_registration POST /managers(.:format) {:controller=>"devise/registrations", :action=>"create"} new_manager_registration GET /managers/sign_up(.:format) {:controller=>"devise/registrations", :action=>"new"} edit_manager_registration GET /managers/edit(.:format) {:controller=>"devise/registrations", :action=>"edit"} PUT /managers(.:format) {:controller=>"devise/registrations", :action=>"update"} DELETE /managers(.:format) {:controller=>"devise/registrations", :action=>"destroy"} user_root GET /pages/:id(.:format) {:controller=>"pages", :id=>"dashboard", :action=>"show"} new_user_session GET /users/sign_in(.:format) {:controller=>"devise/sessions", :action=>"new"} user_session POST /users/sign_in(.:format) {:controller=>"devise/sessions", :action=>"create"} destroy_user_session DELETE /users/sign_out(.:format) {:controller=>"devise/sessions", :action=>"destroy"} user_password POST /users/password(.:format) {:controller=>"devise/passwords", :action=>"create"} new_user_password GET /users/password/new(.:format) {:controller=>"devise/passwords", :action=>"new"} edit_user_password GET /users/password/edit(.:format) {:controller=>"devise/passwords", :action=>"edit"} PUT /users/password(.:format) {:controller=>"devise/passwords", :action=>"update"} cancel_user_registration GET /users/cancel(.:format) {:controller=>"devise/registrations", :action=>"cancel"} user_registration POST /users(.:format) {:controller=>"devise/registrations", :action=>"create"} new_user_registration GET /users/sign_up(.:format) {:controller=>"devise/registrations", :action=>"new"} edit_user_registration GET /users/edit(.:format) {:controller=>"devise/registrations", :action=>"edit"} PUT /users(.:format) {:controller=>"devise/registrations", :action=>"update"} DELETE /users(.:format) {:controller=>"devise/registrations", :action=>"destroy"} root /(.:format) {:controller=>"pages", :action=>"show"}
GIT CHECKOUT PROVIDER
updated_at datetime
string
created_at
id
datetime
last_sign_in_ip
integer
last_sign_in_at
remember_created_at
string
datetime
sign_in_count
datetime
string
encrypted_password
datetimereset_password_sent_at
string
current_sign_in_at
datetime
string
integer
reset_password_token
current_sign_in_ip
Model: Userhas_many :authentications, :as => :resource
has_one :profile, :as => :resource
users
updated_at datetime
datetimecreated_at
umail string
uname string
stringuid
provider string
resource_type string
resource_id integer
id integer
Model: Authenticationbelongs_to :resource, :polymorphic => true
authentications
PROVIDER - USER DB SCHEMA
GIT CHECKOUT OA-OAUTH
rake middlewareuse ActionDispatch::Static......use ActionDispatch::BestStandardsSupportuse Warden::Manageruse OmniAuth::Strategies::Facebookuse OmniAuth::Strategies::Twitteruse OmniAuth::Strategies::GitHubuse OmniAuth::Strategies::OpenIDuse OmniAuth::Strategies::OpenIDuse OmniAuth::Strategies::OpenIDuse OmniAuth::Strategies::GoogleAppsuse OmniAuth::Strategies::GoogleAppsrun DeviseTutorial::Application.routes
OMNIAUTH MIDDLEWARES
DEVISE OMNIAUTH ROUTES
• /users/auth/:provider(.:format) { :controller => "users/omniauth_callbacks", :action => "passthru" }
• user_omniauth_callback/users/auth/:action/callback(.:format) { :controller => "users/omniauth_callbacks", :action => /facebook|twitter|github/ }
NEEDS OF OAUTH
• create new app record for each client site
• app id and app secret are required
• callback url must match
• access token / error message will append to callback url
• specific yaml pattern for user auth data
---provider: facebookuid: "1290347368"credentials: token: 49923..........6RqGcuser_info: nickname: tsechingho email: [email protected] first_name: Tse-Ching last_name: Ho name: Tse-Ching Ho image: http://graph.facebook.com/1290347368/picture?type=square urls: Facebook: http://www.facebook.com/tsechingho Website:extra: user_hash: id: "1290347368" name: Tse-Ching Ho first_name: Tse-Ching last_name: Ho link: http://www.facebook.com/tsechingho username: tsechingho hometown: id: "110922325599480" name: Taichung, Taiwan
NEW FACEBOOK APPhttps://developers.facebook.com/apps
developers.facebook.com
CORRECT APP SETTINGSapp id, app secret, site url, site domain are required.
developers.facebook.com
FACEBOOK USER PANELhttp://www.facebook.com/settings?tab=applications
https://developers.facebook.com/docs/reference/api/permissions/
facebook.com
• ca_file / ca_path
• /users/auth/facebook
• users/omniauth_callbacks#passthru
• https://www.facebook.com/connect/uiserver.php
• /users/auth/facebook/callback?code=xxxxxx
FACEBOOK OAUTH WORK FLOW
facebook.com
NEW TWITTER APPhttps://dev.twitter.com/apps/newuse http://127.0.0.1 for localhost
dev.twitter.com
CORRECT APP SETTINGSconsumer key, consumer secret, callback url are required.
dev.twitter.com
TWITTER USER PANELyou can stop it, not remove it.
twitter.com
• /users/auth/twitter
• users/omniauth_callbacks#passthru
• https://api.twitter.com/oauth/authenticate
• /users/auth/twitter/callback?code=xxxxxx
• twitter auth data is too big for cookies session store
• no email in user auth data
TWITTER OAUTH WORK FLOW
api.twitter.com
GITHUB
NEW GITHUB APPhttps://github.com/account/applications/new
github.com
CORRECT APP SETTINGSclient id, client secret, callback url are required.
github.com
GITHUB APP/USER PANEL ?Don’t delete oauth application,
otherwise you have to create new one.
github.com
• /users/auth/github
• users/omniauth_callbacks#passthru
• https://github.com/login/oauth/authorize
• /users/auth/github/callback?code=xxxxxx
GITHUB OAUTH WORK FLOWgithub.com
GIT CHECKOUT OA-OPENID
SIGN IN GOOGLE ACCOUNT
• ca_file / open_id_store
• /users/auth/google
• users/omniauth_callbacks#passthru
• https://www.google.com/accounts/o8/ud
• https://accounts.google.com/o/openid2/auth
• https://www.google.com/accounts/o8/id?id=xxxxxx
• /users/auth/google/callback
GOOGLE OPENID WORK FLOW
YAHOO
SIGN IN YAHOO ACCOUNT
• ca_file / open_id_store
• /users/auth/yahoo
• users/omniauth_callbacks#passthru
• https://open.login.yahooapis.com/openid/op/auth
• https://login.yahoo.com/config/login
• https://me.yahoo.com/a/xxxxxx
• /users/auth/yahoo/callback
YAHOO OPENID WORK FLOW
GOOGLE APPS
SIGN IN GOOGLE ACCOUNThttp://www.google.com/enterprise/marketplace/
http://developer.googleapps.com/marketplace/getting-started
• ca_file / open_id_store
• /users/auth/gmail
• users/omniauth_callbacks#passthru
• https://www.google.com/accounts/o8/ud?source=gmail.com
• https://accounts.google.com/o/openid2/auth
• https://www.google.com/accounts/o8/id?id=xxxxxx
• /users/auth/gmail/callback
GOOGLE APPS OPENID WORK FLOW
ISSUES
FINDING USER ?
USERNAMEVS
UNCHANGEABLE EMAIL
ONE EMAIL - ONE USERVS
ONE USER - MULTI EMAILS
IF EMAIL OF PROVIDER USER CHANGED,
THEN >.<
PUBLIC EMAIL ADDRESSVS
PROVIDER - UID PAIR
WHO AM I ?
ONE PROVIDER - ONE USERVS
ONE USER - MULTI PROVIDERS
OWN LOCAL USER FIRSTOR
OWN PROVIDER USER FIRST
ONE USERMULTI MAILS
MULTI PROVIDERS
RESOURCES
• http://www.communityguides.eu/articles/11
• http://www.communityguides.eu/articles/16
• http://railscasts.com/episodes/235-omniauth-part-1
• http://railscasts.com/episodes/236-omniauth-part-2
• https://github.com/plataformatec/devise/wiki/Example-Applications
TUTORIALS
DOCUMENTS
• https://github.com/plataformatec/devise/wiki
• https://github.com/intridea/omniauth/wiki
• https://github.com/intridea/authbuttons
Q & A