web-dev-qa-db-ja.com

Identity Server4およびASP.NETIdentityを使用した外部ログインの追加

ASP.NETIdentityでIdentityServer 4を使用して認証機能を追加した後、ユーザーが自分のgoogle +アカウントでログインできるようにGoogleプロバイダーを追加する予定です。フロントエンドとしてAngularを使用し、バックエンドとしてASP.NET Web Api(コア)を使用しています。

// Login client
public login(email: string, password: string): Observable<any> {
    let body: any = this.encodeParams({ /* cliend_id, grant_type, username, password, scope */ });

    return this.http.post("http://localhost:64023/connect/token", body, this.options)
        .map((res: Response) => {
            const body: any = res.json();
                if (typeof body.access_token !== "undefined") {
                    // Set localStorage with id_token,..
                }
        }).catch((error: any) => { /**/ );
}

// Register Web API
[HttpPost("Create")]
[AllowAnonymous]
public async Task<IActionResult> Create([FromBody]CreateUserViewModel model)
{
    var user = new ApplicationUser
    {
        FirstName = model.FirstName,
        LastName = model.LastName,
        AccessFailedCount = 0,
        Email = model.Email,
        EmailConfirmed = false,
        LockoutEnabled = true,
        NormalizedEmail = model.Email.ToUpper(),
        NormalizedUserName = model.Email.ToUpper(),
        TwoFactorEnabled = false,
        UserName = model.Email
    };

    var result = await _userManager.CreateAsync(user, model.Password);

    if (result.Succeeded)
    {
        await addToRole(model.Email, "user");
        await addClaims(model.Email);
    }

    return new JsonResult(result);
}

// Identity Server Startup 
app.UseGoogleAuthentication(new GoogleOptions
{
    AuthenticationScheme = "Google",
    DisplayName = "Google",
    SignInScheme = "Identity.External",
    // ClientId, ClientSecret,..
});

ユーザーがログインすると、localStorageが設定され、安全なコントローラーを保護できるようになります。 Googleプロバイダーのために、追加のボタンと次の方法を追加しました。

initGoogleAPI() {
    let self = this;
    gapi.load('auth2', function () {
        self.auth2 = gapi.auth2.init({ /* client_id, cookiepolicy, scope */ });
        self.externalLogin(document.getElementById('google-button'));
    });
}

externalLogin(element) {
    let self = this;
    this.auth2.attachClickHandler(element, {},
        function (googleUser) {
            // retrieved the id_token, name, email,...
        }, function (error) {
        alert(JSON.stringify(error, undefined, 2));
    });
}

私はいくつかの解決策を見つけましたが、MVCアプリケーションのみであり、クライアントサイドフレームワークを使用するSPAではありません。外部ログインを機能させるには、次にどのような手順を実行する必要がありますか?ユーザーが外部プロバイダーを使用して初めてサインインするときに、AspNetUsersテーブルに新しいレコードを作成する必要がありますか?

17
Sam

このリポジトリを確認できます。ids4サーバープロジェクトを無視して、angularクライアントを確認してください。openidクライアントを使用してこれを行う必要があります。そうすると、クライアントはids4プロジェクトのログインページにリダイレクトされます。ログインすると、後で使用できるように保存したトークンが返されます

https://github.com/nertilpoci/Aspnetcore-identityserver4-webapi-angular

https://github.com/nertilpoci/Aspnetcore-identityserver4-webapi-angular/tree/master/ClientApp

4
npo

ログインはidentityServer4によって処理される必要があります。ローカルログインやサードパーティに関係なく、同様のトークンをWebアプリに返す必要があります。

Web APIバックエンドでユーザーデータが必要な場合は、クレームとして渡す必要があります。

IdentityServer4クイックスタートはコードに役立つ場合があります。IdentityServerに追加する 外部ログイン の例と、 JavaScriptアプリケーション からログインフローを実行する方法があります。

2
Richard Hubley

完璧なユーザーエクスペリエンスの観点からこれに苦労することが多かったので、ここにいくつかの考えを投稿したいと思いました。私はずっと前に手動のアプローチを使用してこれを実装することができました。これがIdentityServerのものであるかどうかはわかりませんが、それでも、IdentityServerと連携してASP.NETIdentityシステムの一部として実装できます。

注:理想的なシナリオは、ユーザーをIDプロバイダーのログインページ(この場合はIdentity Server)に誘導することにより、ユーザーにGoogle/FBへのログイン/登録を許可することです。そこでGoogleまたはFBにログインし、IdentityServerによってアプリケーションにリダイレクトされます。これは、暗黙的またはPKCEフローです。 PKCEには追加の手順がありますが、クレーム処理などはすべてIdSrvコードによって行われます。これは、最も広く文書化されているものです。

最も頻繁に要求されるシナリオ

私は、多くの場合、クライアントは、我々は単にそれに対応するJavaScriptライブラリを経由してJavascriptをGoogleやFBログインを使用することを要求しなければなりませんでした。これはあなたが話しているシナリオです。この場合のフローは次のようになります。

  1. ユーザーがあなたのangularまたはreactアプリページに到達します

  2. Google/FBを使用してサインインします。これにより、「外部アクセストークン」が提供されます。つまり、GoogleとFBのトークン

  3. 次に、このトークン情報を取得して、追加情報(クライアントID、テナントIDなど)とともに、作成できる新しいAPIメソッドに渡すことができます。

APIは、内部的に信憑性のために外部アクセストークンを検証する「ローカル・トークンPOSTのAPI /」と呼ばれる方法を持つことができます。アウト情報をチェックする場合は、ユーザーのアクセストークンベアラー新しいアプリケーションの特定を生成し、Javascriptのアプリへの応答バックとして渡します。 JSアプリは、外部アクセストークン(FB/Google APIリクエスト用)とアプリケーションのアクセストークン(アプリケーションAPIリクエスト用)の両方をCookie /ローカルストレージに保存し、そこから続行できます。

私はこれを非常に簡単に行うことができました。

アクセストークンを生成したい場合、それはかなりstr8フォワードです。これが私のコードの例です。これにより、IdentityServerが生成するのと同様の応答が文字通り生成されます。

  public static async Task<JObject> GenerateLocalAccessTokenResponse(string userName, string role, string userId, string clientId, string provider)
    {

        var tokenExpiration = TimeSpan.FromDays(1);

        var identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);

        identity.AddClaim(new Claim(ClaimTypes.Name, userName));
        identity.AddClaim(new Claim("ClientId", clientId));
        identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId));
        identity.AddClaim(new Claim(ClaimTypes.Role, role));


        var data = new Dictionary<string, string>
        {
            {"userName", userName},
            {"client_id", clientId},
            {"role", role},
            {"provider", provider},
            {"userId", userId}
        };

        var props = new AuthenticationProperties(data);

        var ticket = new AuthenticationTicket(identity, props);

        var accessToken = Startup.OAuthOptions.AccessTokenFormat.Protect(ticket);

        var tokenResponse = new JObject(
            new JProperty("userName", userName),
            new JProperty("client_id", clientId),
            new JProperty("role", role),
            new JProperty("provider", provider),
            new JProperty("userId", userId),
            new JProperty("access_token", accessToken),
            new JProperty("token_type", "bearer"),
            new JProperty("expires_in", tokenExpiration.TotalSeconds.ToString()),
            new JProperty(".issued", ticket.Properties.IssuedUtc.ToString()),
            new JProperty(".expires", ticket.Properties.ExpiresUtc.ToString())
            );

        return tokenResponse;
    }
1
Anup Marwadi