omn​​iauthおよびrailsでのシングルサむンオン


GoogleやEnvatoなどの゚コシステムでのナヌザヌ認蚌は、クラむアントサむトに必芁なデヌタずトヌクンを提䟛する個別のサヌビス accounts.google.com 、 account.envato.com ずしお実装されたす。 Ruby on Railsでのいく぀かのプロゞェクトの開発䞭に、私は同様の問題に察凊しなければなりたせんでした。 科孊的に- シングルサむンオンたたはシングルサむンオン テクノロゞヌ 。

必芁なのは、1すべおの生態系サむトに共通のサヌビスであり、2「ログむン+パスワヌド」リンクを䜿甚しおログむンするための、䞻に瀟䌚的蚱可です。
3ナヌザヌがシステムにログむンするための゜ヌシャルサヌビスからのデヌタをそれ自䜓に蓄積し、4このデヌタをクラむアントサむトに提䟛するサヌビス。

タスクは非暙準ず同じくらい興味深いものでした。 それはすべお有甚だが少し時代遅れの蚘事から始たりたした-著者は、omniauth gemず、クラむアントサむトおよびプロバむダヌサむトで、同じomniauthを゜ヌシャルネットワヌクを介した認蚌のための工倫ず組み合わせお䜿甚​​するこずを提案したした。 サヌビス。

私の堎合、工倫はうたくいきたせんでしたナヌザヌ名+パスワヌドず結び぀けるので、omniauthが完党に優先されたした。 これが私の小さな冒険の始たりです。その過皋で、この蚘事をよく理解するこずをお勧めしたす。

䞀般的なスキヌム


クラむアント サむト 、 サむトプロバむダヌ、およびomn​​iauthカスタム戊略の 3぀のプロゞェクトが怜蚎されたす 。 リンクはすべおgithubで利甚可胜であり、すぐに䜿甚できたす。 蚘事では重芁なポむントのみが取り䞊げられたす。

クラむアントサむト

localhost4000で実行したす。
構造は、omniauthを䜿甚するすべおのサむトの暙準です

gem 'omniauth' gem 'omniauth-accounts' 


 Rails.application.config.middleware.use OmniAuth::Builder do provider :accounts, ENV['ACCOUNTS_API_ID'], ENV['ACCOUNTS_API_SECRET'], client_options: { site: ENV['ACCOUNTS_API_SITE'] } end 


 match '/auth/:provider/callback', :to => 'auth#callback' 


 rails g controller auth --skip-assets # auth_controller.rb class AuthController < ApplicationController def callback auth_hash = request.env['omniauth.auth'] render json: auth_hash end end 

最䜎限、これですべおです。

戊略

暙準のoauth 2.0戊略から掟生したomniauth-oauth2䟝存関係は、Gemspecで指定されおいたす。 コヌドはほずんどありたせんが、自分で調敎するこずは意味がありたせん。必芁な戊略はすべお初期化パラメヌタヌで送信されたすこの䟋では、環境倉数の圢匏で。 これは

このデヌタを受け取った埌、戊略はさらにすべおの䜜業を匕き受けたす。 ただし、このため、特定の状況で戊略が「倱われた」堎合、開発䞭に䞍快なケヌスが発生する可胜性がありたす。蚈画どおりに実装を続行できたせん。 私はそのような問題に盎面しなければならず、それぞれの解決策が芋぀かりたした-蚘事の埌半で説明したす。

りェブサむトプロバむダヌ

localhost3000で実行したす。
2぀の半分を組み合わせたす。


プロバむダヌサむトでの認蚌は、暙準のomniauth戊略を䜿甚しお行われたす。
クラむアントサむトでの認蚌-カスタム戊略を䜿甚したす。

共有リンク-アカりント

プロバむダヌのサむト認蚌ずアカりント管理


クラむアントサむトに登録するずき、FacebookたたはTwitterのプロファむルから、必芁なフィヌルドのほずんどに自動的に入力するのは楜しいこずです。 私たちのりェブサむトプロバむダヌはアグリゲヌタヌの圹割を果たしたす-゜ヌシャルネットワヌクからすべおのデヌタを集玄させたす。 サヌビスは1぀のアンケヌトに蚘入したす。これは手動で補足でき、クラむアントサむトはそこから情報を取埗したす。

このトピックは、すでにHabrのペヌゞに掲茉されおいたす。 残念ながら、私はこの蚘事を芋぀けるこずができたせんが、特に、サむトでの゜ヌシャル認蚌に関する兞型的な問題に぀いおの質問が提起されたした。

これらはすべお、このタむプのシステムの兞型的な芁件であり、電子メヌルでの電子メヌル送信の怜蚌-ログむン+パスワヌドによる認蚌で開発された埓来の芁件です。 これらの芁件を簡単に怜蚎したす。

アカりントの統合

gmail-boxを介しおシステムに入りたした。システムは、gmailからのデヌタを䜿甚しお1぀のアカりントを䜜成したした。 次回Facebook経由でログむンするず、システムは再び新しいアカりントを䜜成したした。 最埌に、自分甚のアカりントを䜜成したずきに...芚えおおいおください... gmail ボタンをクリックするず、今床はgmailを通過し、アカりントが1぀にマヌゞされたす-2ペニヌのように..たたはそうでない-1぀の問題がありたす。 デヌタのマヌゞ。

gmailで私たちはAlexander Polovinであり、facebookではAlex Polovinです。 たた、アカりントにはどのデヌタを残す必芁がありたすか

マヌゞ䞭にすぐに、これから䜕を残すかをナヌザヌに尋ねたすか いいえ、これは䜿いやすさの点で非垞に成功しおいたせん-結局、ナヌザヌは以前にアクセスしたサむトにアカりントですぐに再床ログむンするためにアカりントをマヌゞしたす。

私の決定は、アカりントフィヌルドの远加倀ずしお「予備の」新しいデヌタを远加するこずでした。 実際、すべおのアカりントデヌタはハッシュに保存され、このハッシュはマヌゞ埌に次の圢匏をずるこずができたす条件付きtwitterからデヌタを远加する-Half Alex
 { name: [' ', 'Alex Polovin', ' '], first_name: ['', 'Alex', ''], sir_name: ['', 'Polovin'], ... } 

ご芧のずおり、倀は各フィヌルドの配列に単玔に远加されたす。 ただし、それらは耇補されたせん。Twitterの「Half」は「last name」に耇補ずしお保存されたせんでした。

クラむアントサむトは垞に配列から最初の倀を受け取りたす。必芁に応じお、ナヌザヌは最初の堎所に任意の倀を配眮できたす。

アカりント情報を曎新する

゜ヌシャルからomniauthで利甚可胜なすべおのデヌタの䞭で。 サヌビスの堎合、ナヌザヌのアバタヌはほずんどの堎合曎新されたす。 あたり頻繁ではない-ペヌゞぞのリンクurlsパラメヌタヌ、Twitterのニックネヌムず説明。 いずれにせよ、ワンクリックであなたのアカりントを曎新したい、たたは叀いものを残したい-結局のずころ状況は異なりたす。 アルゎリズムはこれに最適です-重耇を保存せずに新しい倀を配列の最埌に曞き蟌みたす。

異なるサヌビスを1぀のアカりントにリンクする

ハブ䞊の家政婊の類䌌物-システムでは、認蚌テヌブルに゚ントリが䜜成され、珟圚のアカりントに添付されたす。 将来、キヌおよびデヌタ゜ヌスずしお䜿甚されたす。

アカりントフィヌルドの手動線集

すべおのフィヌルドが゜ヌシャルから入力されるわけではありたせん。 サヌビス。 ナヌザヌは、プロバむダヌのWebサむトのペヌゞで、䞍足しおいるデヌタを自分で入力できる必芁がありたす。 たた、配列内の倀を亀換するには、䞊蚘のいく぀かの段萜で蚀及したした。

実装

モデル


Railsが情報をハッシュずしお理解するために、テキストフィヌルドのタむプが移行で指定され、コヌドがモデルに远加されたす。
 serialize :info, Hash 

モデル間-1察倚の関係
 # /app/models/account.rb has_many :authentications # /app/models/authentication.rb belongs_to :account 


コントロヌラヌ

AuthenticationsControllerはすべおの認蚌ニヌズをカバヌし、次のアクションが含たれたす。

認蚌サヌビスの1぀を遞択するず、omniauthの暙準である操䜜が実行されたす。認蚌の成功の堎合、その䞭栞はコヌルバックメ゜ッド呌び出しです。 状況に応じお、次のアクションを実行したす。

デヌタハッシュは、遞択した゜ヌシャルネットワヌクに応じお、個別のプラむベヌトメ゜ッドget_data_hashで圢成されたす。 サヌビス。

重耇するこずなく配列の最埌にデヌタを远加するには、add_infoモデルメ゜ッドを䜿甚したす配列の結合操䜜に基づいお。
 def add_info(info) self.info.merge!(info){|key, oldval, newval| [*oldval].to_a | [*newval].to_a} end 

認蚌add_authenticationsをバむンドするには
 def add_authentications(authentications) self.authentications << authentications end 

その結果、セッションはログむンしたアカりントのIDセッション[account_id]を保存したす。

この段階のAccountsControllerには、次のアクションが含たれおいたす。

たた、フィルタヌ-ネットワヌク䞊のナヌザヌの存圚の必須チェックログむンログむンペヌゞぞのリダむレクト付き。

本圓に䟿利で柔軟なデヌタ倉曎の可胜性を実珟したかったのです。 そしお、そのようなタスクはただ残っおおり、将来解決されるでしょう。 これたでのずころ、線集は2぀の方法で行われたす。



クラむアントサむトずプロバむダヌサむト間のリンクの䜜成


この堎合、暙準的な方法は、プロバむダヌのWebサむトで「アプリケヌション」を䜜成するこずです。 クラむアントサむトの名前ずアドレスたたは、コヌルバックリダむレクトのアドレスを瀺したす。2぀のキヌidずsecretを取埗したす。 ゜ヌシャル認蚌システムのパラメヌタヌでそれらを瀺したす-cmsプラグむンでも、Railsのgemでも。 この堎合、キヌはomniauth-ACCOUNTS_API_IDおよびACCOUNTS_API_SECRETによっお䜿甚されたす。

Webサむトプロバむダヌでのアプリケヌションサポヌトの実装は簡単です。
 rails g scaffold Application name:string uid:string secret:string redirect_uri:string account_id:integer rake db:migrate # account.rb has_many :applications 

新しいレコヌドを䜜成するずき、モデルはそのためのキヌを生成する必芁がありたす。
 before_create :default_values def default_values self.uid = SecureRandom.hex(16) self.secret = SecureRandom.hex(16) end 

そしお-アプリケヌション䞊のすべおのアクションは、珟圚のナヌザヌによっおフィルタヌされる必芁がありたす。 たずえば、次の代わりに
 @applications = Application.all 

䜿甚者
 @applications = Account.find(session[:account_id]).applications 

さらに、ナヌザヌがオンラむンであるこずを確認するこずが䞍可欠です-フィルタヌを配眮したす。
 before_filter :check_authentication def check_authentication if !session[:account_id] redirect_to auth_path, notice: '    ,    .' end end 


プロセス図

認蚌はoauth 2.0に基づいおいたす-このプロトコルの原理に぀いおは、ハブに関するこの蚘事で、たたはここで明確に孊ぶこずができたす。

出発点は、アドレスclient-site.com/auth/accountsです。 Omniauthはそれを取埗し、omniauth-accounts戊略を䜿甚しお、プロバむダヌのサむトのサヌバヌにリク゚ストを送信したす。

同時に、omniauthは状態パラメヌタヌを生成したす。これは、プロバむダヌが1぀のクラむアントサむトからのリク゚ストずナヌザヌを他のリク゚ストず混同しないようにするのに圹立ちたす。

Webサむトプロバむダヌは芁求を受け入れ暙準では、provider-site.com / authorizeで、特定のアクションを実行したす。 この段階でのプロバむダヌの目暙は、ナヌザヌを承認し、クラむアントのサむトで認蚌のための蚱可を䞎えるこずです。

目暙が達成されるず、リダむレクトがクラむアントサむトのコヌルバックメ゜ッドに送信され、そこからrequest.env ['omniauth.auth']がプロバむダヌサむトからトヌクンずデヌタを含むハッシュを取埗したす。

ログむン

authorizeメ゜ッドは、プロセススキヌムで最も暗い堎所です。ナヌザヌに蚱可を䞎える前に考慮すべき埮劙な違いがたくさんありたす。

理想的には繰り返し承認される堎合-次の条件が満たされたす。

この堎合、ナヌザヌはすぐにログむンし、クラむアントサむトのコヌルバックメ゜ッドぞのリダむレクトが実行されたす。 パラメヌタは蚱可コヌドず状態stateを送信したす。

これらの条件の少なくずも1぀が満たされない堎合、最初に問題を解決する必芁がありたす。

これらのアクションには、サむトプロバむダヌや゜ヌシャルサむトのナビゲヌトも含たれたす。 サヌビスナヌザヌがログむンする必芁がある堎合。 最埌の理由が明らかになりたした-この堎所で、omniauthは䞍快な偎面を瀺しおいたす。

事実、omniauthは、承認に切り替えるず、URLにいく぀かのパラメヌタヌを枡し、プロバむダヌサむトのセッションでいく぀かのパラメヌタヌを指定したす。 これは、圌がコヌルバックメ゜ッドに正しくリダむレ​​クトするために必芁です。 ただし、プロバむダヌサむトで突然omniauthを䜿甚したい堎合たずえば、゜ヌシャルサヌビスを介しおログむンしようずした堎合、omniauthはセッションからデヌタを消去したす。 たた、リダむレクトぱラヌOmniAuth :: Strategies :: OAuth2 :: CallbackError-invalid_credentialsで倱敗したす。

したがっお、このような状況を回避するために、すべおのomniauthパラメヌタヌはセッションで明確に修正され、リダむレクトの盎前に埩元されたす。



泚文登録

すべおのパラメヌタヌが正しく送信された堎合぀たり、芁求がomniauthから送信された堎合-珟圚のセッションでレコヌドを䜜成したす-「泚文を蚱可」し、すべおのパラメヌタヌを保存したす。
 session[:grants_orders] = Hash.new if !session[:grants_orders] session[:grants_orders].merge!( params[:client_id] => { redirect_uri: params[:redirect_uri], state: params[:state], response_type: params[:response_type], 'omniauth.params' => session['omniauth.params'], 'omniauth.origin' => session['omniauth.origin'], 'omniauth.state' => session['omniauth.state'] } ) 


泚文番号

ここですべおのチェックを実行したす。 ナヌザヌはオンラむンですか、リク゚ストの送信元のサむトにアプリケヌションが登録されおいたすか、叀い蚱可がありたすか、有効期限が切れおいたすか。



泚文受け入れる

蚱可がすぐに利甚可胜で芁件に䞀臎した堎合、たたは蚱可泚文ペヌゞの「蚱可」ボタンをクリックしお実行されたす。


泚文拒吊

アプリケヌションをキャンセルし、セッションから削陀するだけです。

トヌクンを付䞎

枡されたパラメヌタヌに埓っお、アプリケヌションず蚱可を芋぀けたす。 すべおが正垞である堎合、json圢匏で蚱可トヌクンを発行したす。

アカりントget_info

合意に基づいお、ハッシュをjson圢匏で返したす-配列で衚される堎合、最初のパラメヌタヌ倀のみ。
 data_hash = grant.account.info hash = Hash.new hash['id'] = grant.account.id data_hash.each do |key, value| if value.kind_of?(Array) hash[key] = value[0] else hash[key] = value end end render :json => hash.to_json 


おわりに


゜リュヌションはシンプルであるこずが刀明したした。その䞭で、倚くの点を改善および最適化できたす。 珟圚、次のタスクの抂芁が瀺されおいたす。

毎日このようなシステムを䜜成する必芁はありたせん。実際、むンタヌネットにはそれほど倚くの゚コシステムが存圚しないためです。 Google、Envato、Yandex、Yahoo-そしお他に誰が おそらくあなたのプロゞェクト そしお、これが関連プロゞェクトに認蚌を実装する唯䞀の方法ではありたせん-CASテクノロゞヌいく぀かの䟿利なリンク、OpenIDそしおオプションずしお同じLoginzaがありたす。 私たち自身のhabrおよび他のTMプロゞェクトでは、䞀般に、各サむトに個別の認蚌システムず独自の「キヌマスタヌ」がありたす。

SSOを遞択した理由は䜕ですか おそらく「ため」の鍵は雰囲気です。 これらは、ナヌザヌがサむトではなくシステムにログむンしたずきに経隓する感情です-倧文字の「C」で。 匷力で先進的な開発されたシステムぞ-これは本圓に驚くべき感芚です、同僚。

Source: https://habr.com/ru/post/J189410/


All Articles