第1章 $fh.auth

$fh.auth(options, success, failure);

認証を行うとともに、オプションでアクセス権限管理によってユーザー承認も行います。fh.auth を使用するには、ドメイン管理者のアカウントが必要になります。ユーザーレベルについては、ユーザーの管理 を参照してください。oauth プロバイダーに対して $fh.auth を使用する予定の場合は、OAuth ポリシー を参照してください。

一般的に、認証タイプが FeedHenry または LDAP の場合は、ユーザーが自分の認証情報を入力し、auth リクエストのインスタンスでそれらを設定できるようにするビューを構築するだけで十分です。

認証ポリシーのタイプが OAuth の場合、認証プロセスは複雑なものになります。ユーザーは OAuth プロバイダーのログインページにログインし、アプリケーションが自分の情報にアクセスできるようにするためにパーミッションを付与する必要があります。

このプロセスを簡単なものにするために、ネイティブの SDK (iOS、Android および .NET) が追加の UI コンポーネントを提供し、シームレスに処理できるようにします。UI コンポーネントが画面上に現れ、OAuth プロバイダーの認証ページを読み込みます。コンポーネントは OAuth プロセスが終了するとこれを検知して自動的に閉じ、結果を success または failure 関数に渡します。UI コンポーネントは以下のようなものです。

iOS_OAuth_Sample.png

サポートされるプラットフォーム

  • JavaScript SDK

    • Cordova
    • Web Apps
  • Android SDK
  • iOS Objective-C SDK
  • iOS Swift SDK
  • .NET SDK

    • Windows
    • Xamarin

詳細なバージョン情報については、Supported Configurations (英語) を参照してください。

1.1. 例

JavaScript

// LDAP or Platform User Example
$fh.auth({
  "policyId": "My LDAP Auth Policy", // name of auth policy to use - see link:{ProductFeatures}#administration[Auth Policies Administration] for details on how to configure an auth policy
  "clientToken": "myAppId", // Your App ID
  "endRedirectUrl": window.location.href, // The URL to return to after authentication. Optional
  "params": { // the parameters associated with the requested auth policy - see below for full details.
    "userId": "joe@bloggs.com", // LDAP or Platform username
    "password": "password" // LDAP or Platform password
  }
}, function (res) {
  // Authentication successful - store sessionToken in variable
  var sessionToken = res.sessionToken; // The platform session identifier
  var authResponse = res.authResponse; // The authentication information returned from the authentication service.
  // This may include things such as validated email address,
  // OAuth token or other response data from the authentication service
}, function (msg, err) {
  var errorMsg = err.message;
  /* Possible errors:
    unknown_policyId - The policyId provided did not match any defined policy. Check the auth policies defined. See link:{ProductFeatures}#administration[Auth Policies Administration]
      user_not_found - The auth policy associated with the policyId provided has been set up to require that all users authenticating exist on the platform, but this user does not exists.
      user_not_approved - - The auth policy associated with the policyId provided has been set up to require that all users authenticating are in a list of approved users, but this user is not in that list.
        user_disabled - The user has been disabled from logging in.
        user_purge_data - The user has been flagged for data purge and all local data should be deleted.
        device_disabled - The device has been disabled. No user or apps can log in from the requesting device.
        device_purge_data - The device has been flagged for data purge and all local data should be deleted.
    */
if (errorMsg === "user_purge_data" || errorMsg === "device_purge_data") {
  // User or device has been black listed from administration console and all local data should be wiped
} else {
  alert("Authentication failed - " + errorMsg);
}
});


// OAuth 2.0 Example
// OAuth does not require any params, instead the "authCallback" param should be set on the $fh.auth call.
// This should be a function name that you have defined, and will be called after Auth has completed.
$fh.auth({
  "policyId": "My OAuth Policy",
  "clientToken": "myAppId",
  "authCallback": "authLoginCallback",
  "endRedirectUrl": window.location.href
}, function () {
  //
}, function () {
  //
});

var authLoginCallback = function(err, res) {
  if (!err) {
    // Authentication successful - store sessionToken in variable
    var sessionToken = res.sessionToken;
  } else {
    alert("Authentication failed - " + err.message);
  }
}

Android (Java)

下記の例にあるようにビルトイン OAuth ハンドラーを使用するには、以下の設定をアプリケーションの AndroidManifest.xml ファイルの application 要素に追加する必要があります。

<application>
  ...
  <activity android:name="com.feedhenry.sdk.oauth.FHOAuthIntent" />
</application>
注記

Auth コードを呼び出す前に、FH.init コードが初期化されていることを確認してください。例については こちら を参照してください。

//Example code to authenticate a user with username and password that are defined in an auth policy called "MyFeedHenryPolicy"
private void loginWithFh(){
  EditText userField = (EditText) findViewById(R.id.fh_login_user);
  EditText passField = (EditText) findViewById(R.id.fh_login_password);
  String userName = userField.getText().toString();
  String password = passField.getText().toString();
if("".equals(userName)){
  FhUtil.showMessage(this, "Error", "User name is empty");
  return;
}
if("".equals(password)){
  FhUtil.showMessage(this, "Error", "Password is empty");
  return;
}
try{
  FHAuthRequest authRequest = FH.buildAuthRequest("MyFeedHenryPolicy", userName, password);
  authRequest.executeAsync(new FHActCallback() {


    @Override
    public void success(FHResponse resp) {
      Log.d("FHLoginActivity", "Login success");
    }

    @Override
    public void fail(FHResponse resp) {
      Log.d("FHLoginActivity", "Login fail");
    }
  });
}catch(Exception e){
  e.printStackTrace();
  }
}

認証ポリシーのタイプが OAuth の場合、Intent が起動して OAuth プロバイダーの認証ページが読み込まれます。OAuth プロセスが終了するとこれを検知して自動的に閉じ、結果を success または failure 関数に渡します。これを有効にするには、アプリケーションのコンテキストで FHAuthRequest インスタンスの setPresentingActivity メソッドを呼び出すだけです。

private void doOAuth(){
try{
FHAuthRequest authRequest = FH.buildAuthRequest();
authRequest.setPresentingActivity(this);
authRequest.setAuthPolicyId("MyGooglePolicy"); //"MyGooglePolicy" should be replaced with policy id you created
authRequest.executeAsync(new FHActCallback() {


    @Override
    public void success(FHResponse resp) {
      Log.d("FHAuthActivity", resp.getJson().toString());
    }

    @Override
    public void fail(FHResponse resp) {
      Log.d("FHAuthActivity", resp.getErrorMessage());
    }
  });
} catch(Exception e){
  Log.e("FHAuthActivity", e.getMessage(), e);
  }
}

setPresentingActivity メソッドが呼び出されない場合は、自身のコードでこれを処理することができます。例を示します。

private void doOAuth(){
try{
  FHAuthRequest authRequest = FH.buildAuthRequest();
  authRequest.setAuthPolicyId("MyGooglePolicy"); //"MyGooglePolicy" should be replaced with policy id you created
  authRequest.executeAsync(new FHActCallback() {


    @Override
    public void success(FHResponse resp) {
      Log.d("FHAuthActivity", resp.getJson().toString());
      //because the setPresentingActivity method is not called, the reponse will contain a URL which should be used for user to login. Normally it should be loaded into a WebView
      String url = resp.getJson().getString("url");
      // load the url in a WebView, and then a seriers of redirects will happen
      // the last url will contain a string "status=complete"
      // and there will be a query parameter called "authResponse" in that url
      // the value of that parameter is the data returned from the OAuth provided (JSON stringified and URL encoded)
    }

    @Override
    public void fail(FHResponse resp) {
      Log.d("FHAuthActivity", resp.getErrorMessage());
    }
  });
} catch(Exception e){
  Log.e("FHAuthActivity", e.getMessage(), e);
  }
}

iOS (Objective-C)

//Example to authenticate user using username and password
NSString* userName = self.usernameField.text;
if(!userName){
  return [self showMessage:@"Error" message:@"User Name field is required"];
}
NSString* password = self.passwordField.text;
if(!password){
  return [self showMessage:@"Error" message:@"Password field is required"];
}
FHAuthReqeust* authRequest = [FH buildAuthRequest];
[authRequest authWithPolicyId:@"MyFeedHenryPolicy" UserId:userName Password:password]; //"MyFeedHenryPolicy" should be replaced with policy id you created
void (^success)(FHResponse *)=^(FHResponse * res){
  NSLog(@"parsed response %@ type=%@",res.parsedResponse,[res.parsedResponse class]);
  if ([[[res parsedResponse] valueForKey:@"status"] isEqualToString:@"error"]) {
    [self showMessage:@"Failed" message:%5Bres.parsedResponse valueForKey:@"message"]];
  } else {
    [self showMessage:@"Success" message:res.rawResponseAsString];
  }
};
void (^failure)(FHResponse *)=^(FHResponse* res){
  NSLog(@"parsed response %@ type=%@",res.parsedResponse,[res.parsedResponse class]);
  [self showMessage:@"Failed" message:res.rawResponseAsString];
};
[authRequest execAsyncWithSuccess:success AndFailure:failure];

認証ポリシーのタイプが OAuth の場合、UI コンポーネントが起動して OAuth プロバイダーの認証ページが表示されます。OAuth プロセスが終了するとこれを検知して自動的に閉じ、結果を success または failure 関数に渡します。これを有効にするには、アプリケーションの UIViewController インスタンスで FHAuthRequest インスタンスの parentViewController プロパティーを設定します。

FHAuthReqeust * authRequest = [FH buildAuthRequest];
[authRequest authWithPolicyId:@"MyOAuthPolicy"]; //"MyOAuthPolicy" should be replaced with policy id you created
authRequest.parentViewController = viewController; //Important, this will enable the built-in OAuth hanlder
void (^success)(FHResponse *)=^(FHResponse * res){
  NSLog(@"parsed response %@ type=%@",res.parsedResponse,[res.parsedResponse class]);
  if ([[[res parsedResponse] valueForKey:@"status"] isEqualToString:@"error"]) {
    [self showMessage:@"Failed" message:%5Bres.parsedResponse valueForKey:@"message"]];
  } else {
    [self showMessage:@"Success" message:%5Bres.parsedResponse JSONString]];
  }
};
void (^failure)(FHResponse *)=^(FHResponse* res){
  NSLog(@"parsed response %@ type=%@",res.parsedResponse,[res.parsedResponse class]);
[self showMessage:@"Failed" message:res.rawResponseAsString];
};

[authRequest execAsyncWithSuccess:success AndFailure:failure]

parentViewController プロパティーが設定されていない場合は、自身のコードでこれを処理することができます。例を示します。

FHAuthReqeust* authRequest = [FH buildAuthRequest];
[authRequest authWithPolicyId:@"MyOAuthPolicy"]; //"MyOAuthPolicy" should be replaced with policy id you created
void (^success)(FHResponse *)=^(FHResponse * res){
  NSLog(@"parsed response %@ type=%@",res.parsedResponse,[res.parsedResponse class]);
  //because the parentViewController is not set, the reponse will contain a URL which should be used for user to login. Normally it should be loaded into a WebView
  NSString* oauthUrl = [res.parsedResponse valueForKey:@"url"];
  NSURL* request = [NSURL URLWithString:oauthUrl];
  // load the url in a WebView, and then a seriers of redirects will happen
  // the last url will contain a string "status=complete"
  // and there will be a query parameter called "authResponse" in that url
  // the value of that parameter is the data returned from the OAuth provided (JSON stringified and URL encoded)
};
void (^failure)(FHResponse *)=^(FHResponse* res){
  NSLog(@"parsed response %@ type=%@",res.parsedResponse,[res.parsedResponse class]);
  [self showMessage:@"Failed" message:res.rawResponseAsString];
};

[authRequest execAsyncWithSuccess:success AndFailure:failure];

iOS (Swift)

//Example to authenticate user using username and password
FH.auth("MyFeedHenryPolicy", userName: "me", password: "password", completionHandler: { (response: Response, error: NSError?) -> Void in
  if let error = error {
    print("Error \(error)")
    return
  }
  if let response = response.parsedResponse as? [String: String]{
    if let status = response["status"] where status == "ok" {
      print("Response \(response)")
    } else if let status = response["status"] where status == "error" {
      let message = response["message"] ?? ""
      print("OAuth failed \(message)")
    }
  }
})

認証ポリシーのタイプが OAuth の場合、UI コンポーネントが起動して OAuth プロバイダーの認証ページが読み込まれます。OAuth プロセスが終了するとこれを検知して自動的に閉じ、結果を success または failure 関数に渡します。これを有効にするには、アプリケーションの UIViewController インスタンスで AuthRequest インスタンスの parentViewController プロパティーを設定します。

let request = FH.authRequest("MyOAuthPolicy") //"MyOAuthPolicy" should be replaced with policy id you created
request.parentViewController = viewController //Important, this will enable the built-in OAuth handler
request.exec({ (response: Response, error: NSError?) -> Void in
  if let error = error {
    print("Error connecting \(error)")
    return
  }
  if let response = response.parsedResponse as? [String: String] {
    if let status = response["status"] where status == "ok" {
      print("Response \(response)")
    } else if let status = response["status"] where status == "error" {
      let message = response["message"] ?? ""
      print("OAuth failed \(message)")
    }
  }
})

parentViewController プロパティーが設定されていない場合は、自身のコードでこれを処理することができます。例を示します。

let request = FH.authRequest("MyOAuthPolicy") //"MyOAuthPolicy" should be replaced with policy id you created
request.exec({ (response: Response, error: NSError?) -> Void in
  if let error = error {
    print("Error connecting \(error)")
    return
  }
  if let response = response.parsedResponse as? [String: String] {
    if let status = response["status"] where status == "ok" {
      print("Response \(response)")
      // because the parentViewController is not set, the response will contain a URL which
      // should be used for user to login. Normally it should be loaded into a WebView
      if let urlString = response["url"] {
        let url = NSURL(string: urlString)
        // load the url in a WebView, and then a series of redirects will happen
        // the last url will contain a string "status=complete"
        // and there will be a query parameter called "authResponse" in that url
        // the value of that parameter is the data returned from the OAuth provided (JSON stringified and URL encoded).
      }    } else if let status = response["status"] where status == "error" {
let message = response["message"] ?? ""
print("OAuth failed \(message)")
}
}
})

 .NET (C#)

//Example to authenticate user using username and password
string authPolicy = "MyFeedHenryPolicy"; //"MyFeedHenryPolicy" should be replaced with policy id you created
string username = this.usernameField.Text;
string password = this.passwordField.Text;

FHResponse authRes = await FH.Auth(authPolicy, username, password);
if (null == authRes.Error)
{
    //user successfully logged in
}
else
{
    //login failed, show error
    ShowMessage(authRes.Error.Message);
}

認証ポリシーのタイプが OAuth の場合、UI コンポーネントが起動して OAuth プロバイダーの認証ページが読み込まれます。OAuth プロセスが終了するとこれを検知して自動的に閉じ、結果を success または failure 関数に渡します。

string authPolicy = "TestGooglePolicy"; //"TestGooglePolicy" should be replaced with policy id you created
//When next line is executed, the user will be prompted with a new view to
//allow them enter their credentials on the OAuth provider's login page,
//and the result will be returned in FHResponse
FHResponse res = await FH.Auth(authPolicy);
if (null == res.Error)
{
    //user successfully logged in
}
else
{
    //login failed, show error
    ShowMessage(res.Error.Message);
}

SDK が提供するデフォルトの OAuth ログインハンドラーを使用したくない場合は、独自の実装を提供することが可能です。IOAuthClientHandlerService インターフェース用の実装を作成し、以下のように使用します、

//create a new instance of the custom IOAuthClientHandlerService
IOAuthClientHandlerService authHandler = new MyOAuthHandler();
//create a new auth request
FHAuthRequest authRequest = new FHAuthRequest();
authRequest.SetAuthPolicyId(policyId);
//set the request to use the custome oauth handler
authRequest.SetOAuthHandler(authHandler);
FHResponse res = await authRequest.execAsync();

1.2. セッションの確認

重要

この機能を使用する際には、クライアントとクラウド SDK で以下のバージョンが使用されていることを確認してください。

  • fh-js-sdk: >= 2.6.0
  • fh-ios-sdk: >= 2.2.8
  • fh-android-sdk: >= 2.2.0
  • fh-dotnet-sdk: >= 1.2.0
  • fh-mbaas-api: >=4.10.0

認証 API が返す sessionToken はデバイス上で保持され、後で自動的に全 cloud API コールに追加されます。

クライアント側では、新規 API がセッションの操作をサポートするために追加されます。

JavaScript

//To check if user is already authenticated
$fh.auth.hasSession(function(err, exist){
  if(err) {
    console.log('Failed to check session');
    return;
  }
  if(exist){
    //user is already authenticated
    //optionally we can also verify the session is actually valid from client. This requires network connection.
    $fh.auth.verify(function(err, valid){
      if(err){
        console.log('failed to verify session');
        return;
      }
      if(valid){
        console.log('session is valid');
      } else {
        console.log('session is not valid');
      }
    });
  } else {
    //user is not authenticated
  }
});

//When the user is logging out, the session should be cleared
$fh.auth.clearSession(function(err){

});

Java

//To check if user is already authenticated
boolean exists = FHAuthSession.exists();
if (exists) {
    //user is already authenticated
    //optionally we can also verify the session is actually valid from client. This requires network connection.
    FHAuthSession.verify(new FHAuthSession.Callback() {
      @Override
      public void handleSuccess(final boolean isValid) {
        if (isValid) {
            //The session is valid, notify the application
            //You may now access the session token using FHAuthSession.getToken()
        } else {
            //The session is not valid. Clear the application's
            //state and authenticate again
          }
}


      @Override
      public void handleError(FHResponse resp) {
         //Something went wrong with the network call.
      }
  }, false);


} else {
    //Not logged in, notify the application.
}

プラットフォームからクライアントをログアウトするには、FHAuthSession.clear(boolean synchronous) を使用します。このメソッドはネットワークアクセスを実行することに留意してください。メインの looper から呼び出す場合は、synchronous 引数を false に設定して、ネットワーク操作が looper スレッドをブロックしないようにし、Android が NetworkOnMainThreadException をスローすることを防ぎます。

FHAuthSession.clear(false);
//To check if user is already authenticated
BOOL hasSession = [FH hasAuthSession];
if(hasSession) {
//optionally we can also verify the session is acutally valid from client. This requires network connection.
[FH verifyAuthSessionWithSuccess:nil AndFailure:nil];
}
//When the user is logging out, the session should be cleared
[FH clearAuthSessionWithSuccess:nil AndFailure:nil];

 .NET (C#)

//To check if user is already authenticated
FHAuthSession session = FH.GetAuthSession();
Boolean exists = session.Exists();
//optionally we can also verify the session is actually valid from client. This requires network connection.
if(exists) {
  bool valid = await session.Verify();
}

//When the user is logging out, the session should be cleared
session.Clear();

fh-mbaas-api モジュールでは、リクエストの sessionToken を検証するミドルウェアも提供されています。これは、リクエストが認証済みユーザーからのものかどうかの判断を容易にします。必要となるのは、以下のものだけです。

var mbaasExpress = require('fh-mbaas-api').mbaasExpress();
var express = require('express');
var router = new express.Router();
//This will protect the router and only accept requests from authenticated users.
//If a sessionToken is valid, you can choose to cache it so that it doesn't need to be checked again.
router.use(mbaasExpress.fhauth({cache: true, expire: 60*60}));

1.3. 独自認証プロバイダーの作成

mBaaS 認証ポリシータイプ が導入されたことで、独自の認証プロバイダーを作成することが可能になっています。

これは、以下を実行する mBaaS サービス を作成することで可能になります。

  • 認証の実行
  • sessionToken キーを含む JSON 応答の回答

上記の説明にあったように、クライアント SDK により(X-FH-SESSIONTOKEN ヘッダー経由で) sessionToken がすべてのクラウドコールに追加されます。ただし、sessionToken は mBaaS サービスが生成していることから、fh-mbaas-api で提供されているセッション確認のミドルウェアは機能しなくなります。sessionToken の値を確認するために独自のミドルウェアを提供する必要があります。しかし、これは、リクエストオブジェクトにユーザー情報を設定するなど、確認プロセス中にリクエストにさらなる情報を追加できることにもなります。