JavaServer Faces(JSF)のソーシャルネットワーク認証

サイトユーザーの認証およびソーシャルネットワークを介したログイン中のパスワードの害について多くのことが書かれています。 ただし、基本的には、理論的な考慮事項、またはモジュールをPHPにCMSの1つに統合するいくつかの側面に関するものです。



VKontakte、Facebook、My World、Yandex、Odnoklassniki、Google、Twitter、LinkedInネットワークのユーザーの認証をJSF2を使用して整理する例を紹介します。 これは完全にオーサリング開発であり、最も一般的なOAuth runetプロバイダーを対象としています。 サードパーティのライブラリ、サーブレット、jsp、およびスプリングを使用せずに記述されています-JSF2およびCDIのみ。



これらはすべて、トレーニングサービスを提供する有料サイトの開発で生まれました。 当然、人々が「苦労して稼いだ」ものの少なくとも一部を手放すためには、本当に一生懸命努力する必要があります。 パスワード、電子メール、キャプチャ、タイムゾーンを使用した複雑な登録は、これに大きく貢献しません。 したがって、決定はユーザー名とパスワード(2回)のみに限定され、追加の質問はありません! 実際には、これにより複数回の登録が行われ、パスワードを忘れてしまいます。多くの場合、支払い後(通常、誰も自分のアカウントを覚えていない)や同様のトラブルが発生します。 アンケートに記入する人もほとんどいませんでした-サポートサービスは甘くありませんでした。



ソリューションは、「ワンクリック」でユーザーの登録とその後の認証を提供することを提案しました。 OAuthテクノロジーを使用したソーシャルネットワークは完全に適合します。 すでに承認があり、一意の識別子を取得するだけで済みました。 それが行われました。



私たちのサイトのメインページには、「ログイン」と「登録」の2つのボタンがあります。 技術的には、ユーザーは間違いを犯す方法がないため、これらを組み合わせることができます。ユーザーは手動でデータを入力しません。 データベースにまだないOAuthを介して識別子を受け取った場合、新しいユーザーを登録しています。それ以外の場合は、システムにそれを許可します。 新しいユーザーに対しては、あいさつを引き続き表示できます。



各ソーシャルネットワークには、すべての機能を実装する既製のライブラリがすでに存在するため、細心の注意を払った読者が、なぜ独自のソリューションを開発する必要があったのかと尋ねます。 はい、あります。 しかし、この「すべて」、この場合は冗長な機能のために、余分なボリューム、多数の依存関係、および異なる(ライブラリごとに)異なるアプローチを統合およびサポートする必要があります。 外国のバグや脆弱性も割り引く必要はありません。



それでは、すべてがどのように機能するかを詳しく見てみましょう



Habréの記事では、デモプロジェクトが開発されました-作業システムから部品が噛まれ、余分なものはすべて削除され、作業モデルのみが残りました。 記事の下部には、プロジェクトとデモへのリンクがあります。



すべてlogin.xhtmlで始まり​​、次のようになります。

画像

Habrapakから取られたアイコン。 各アイコンにはメソッドコールが割り当てられ、リクエストが生成され、リダイレクトを通じてユーザーがOAuthプロバイダーのWebサイトに送信されます。



Yandexのサンプルコード:

String plainUrl = "https://oauth.yandex.ru/authorize?" +"client_id="+ yaId +"&response_type=code"; FacesContext.getCurrentInstance().getExternalContext().redirect(plainUrl);
      
      







ユーザーが自分のデータへのアクセスを提供する申し出に同意した後、彼は私たちのサイトに戻ります。ホスト側はyaLogin.xhtmlページです

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head></h:head> <f:metadata> <f:viewParam id="code" name="code" value="#{yalogin.code}" /> <f:viewParam id="error" name="error" value="#{yalogin.error}" /> <f:viewParam id="state" name="state" value="#{yalogin.state}" /> <f:event type="preRenderView" listener="#{yalogin.phase2()}" /> </f:metadata> <body> </body> </html>
      
      







ご覧のとおり、受信したパラメーターコード、エラー、および状態がクラス変数に渡され、phase2()メソッドが起動され、実際にさらに処理が行われます。



エラーが返されたかどうかを確認します。

 if (error!=null) { logger.info("error="+error); try { FacesContext.getCurrentInstance().getExternalContext().redirect("error.jsf"); } catch (Exception e) { logger.log(Level.SEVERE, "phase2() Error: redirect failed!", e); } return ""; }
      
      







すべてが正常である場合、トークンのリクエストを作成します。

  Properties props = new Properties(); props.put("grant_type", "authorization_code"); props.put("code", code); props.put("client_id", yaId); props.put("client_secret", yaSecret); String ret1 = HttpURL.httpsPost("https://oauth.yandex.ru/token", props, "UTF-8");
      
      







そして、parsimの結果:

  class YA{ String access_token; String token_type; } YA ya = (YA) XStreamFactory.get(YA.class, ret1);
      
      







アクセストークンを取得すると、ユーザーに関する情報をリクエストできます。

 String ret2 = HttpURL.httpsGet("https://login.yandex.ru/info?format=json&oauth_token="+ya.access_token); class PersonData { public String birthday; public String display_name; public String sex; public String id; public String default_email; public String real_name; } PersonData personData = (PersonData) XStreamFactory.get(PersonData.class, ret2);
      
      







これで、受信したデータをCoreオブジェクト(ディスパッチャー)に転送できます。

  core.getUserAutoReqProps().setEmail(personData.default_email); String[] fname = personData.real_name.split(" "); core.getUserAutoReqProps().setLastName(fname[0]); core.getUserAutoReqProps().setFirstName(fname[1]); core.getUserAutoReqProps().setSex("male".equalsIgnoreCase(personData.sex)); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); core.getUserAutoReqProps().setBorn(dateFormat.parse(personData.birthday));
      
      







一意のユーザーIDを覚えて、サイトの保護された部分に移動します。

  core.setValidatedId("http://my.ya.ru/"+personData.id); FacesContext.getCurrentInstance().getExternalContext().redirect("welcome.jsf");
      
      







認証されたユーザーがいます! 当然、まだ承認が必要ですが、これは記事の範囲外です。



ご覧のとおり、1つのOAuthプロバイダーで作業するには、1つのjavaクラスと1つのxhtmlページで十分です。 Yandexの場合、これはYALogin.javaとyaLogin.xhtmlになり、VKontakteの場合はVKLogin.javaとvkLogin.xhtmlになります。



アプリケーションの登録中に取得したIDとシークレットを保存する場所の問題は、次のように解決されました。アプリケーションサーバーのファイルシステム上の外部ファイルで。 これにより、次の利点が得られます。開発者はファイルにテストアプリケーションデータがあり、サーバー上の実際のデータがあるため、展開中に変更する必要はなく、機密性が尊重されます。 oauth.propertiesファイルの例はプロジェクトにあります。

ファイルパスはweb.xmlに保存されます。

 <context-param> <param-name>OAuthPropertiesPath</param-name> <param-value>/opt/oauth/oauth.properties</param-value> </context-param>
      
      







アプリケーションが起動すると、アクションBeanが開き、このファイルを解析します。

 @Named @ApplicationScoped public class OAuthDAO implements Serializable { private static final long serialVersionUID = 1L; private Properties prop; private static Logger logger = Logger.getLogger(OAuthDAO.class.getName()); public OAuthDAO() { load(); } public boolean load(){ try (FileInputStream fis = new FileInputStream(FacesContext.getCurrentInstance().getExternalContext().getInitParameter("OAuthPropertiesPath"))){ prop = new Properties(); prop.load(fis); if (prop.isEmpty()) { return false; } } catch (Exception ex) { return false; } return true; } public String getProperty(String key) { return prop.getProperty(key); } }
      
      







提示されたテストアプリケーションでは、認証が完了すると、アプリケーションの保護された部分を象徴するwelcome.xhtmlページが表示されます。 権限のないユーザーがこのページにアクセスするのを防ぐために、core.fiscal()メソッドがpreRenderViewイベントによって呼び出され、イベントがチェックされます。

 <f:metadata> <f:event listener="#{core.fiscal()}" type="preRenderView" /> </f:metadata>
      
      







デモではGlassFishアプリケーションサーバーを実行しています。 JSONとXMLの解析には、XStreamライブラリが使用されました。



こちらのアプリケーションをご覧ください

Eclipse プロジェクトをダウンロードしてください



All Articles