简体   繁体   中英

Generate local user based access token by validating external token (Facebook, Twitter etc)

I m building a native mobile application and multiple web APIs to support the functionality of a native app, Im having all requests for my web APIs authenticated,so Im using IdentityServer3 with ASP.Net Identity

I want to use social login providers for my native app ( Twitter and Digits), and I want the native app to take care of authenticating with Twitter, once authenticated an external access token from Twitter will be available to the native app. Now, i want provide end points in my Identity Server 3 setup to support validating external access token and generating a local access token based on user?

What would be the best way to achieve this with asp.net identity and identity server 3?

This author of this blog post, seems to be explaining exactly what I m trying to achieve, but, he is not using identityserver3 http://bitoftech.net/2014/08/11/asp-net-web-api-2-external-logins-social-logins-facebook-google-angularjs-app/

Here is some code which use IdentityServer3 to claim base login (OAuth2) you can find external login and openId login on the identityServer Website

Server:

Scope:

             new Scope
             {
                 Name ="morhipo",
                  Type = ScopeType.Resource,
                  Claims = new List<ScopeClaim>
                {
                    new ScopeClaim(Constants.ClaimTypes.Name),
                    new ScopeClaim(Constants.ClaimTypes.Email),
                    new ScopeClaim(Constants.ClaimTypes.FamilyName),
                    new ScopeClaim(Constants.ClaimTypes.GivenName),
                    new ScopeClaim(Constants.ClaimTypes.Gender),
                    new ScopeClaim(Constants.ClaimTypes.Id),
                    new ScopeClaim(Constants.ClaimTypes.PhoneNumber),
                    new ScopeClaim(Constants.ClaimTypes.Subject),
                    new ScopeClaim(Constants.ClaimTypes.AccessTokenHash),
                    new ScopeClaim(Constants.ClaimTypes.Role)
                }
             }

User:

        new InMemoryUser{ Subject = "bob", Username = "bob", Password = "bob", 
            Claims = new Claim[]
            {
                new Claim(Constants.ClaimTypes.GivenName, "Bob"),
                new Claim(Constants.ClaimTypes.Role, "Admin"),
                new Claim(Constants.ClaimTypes.Role, "User"),
                new Claim(Constants.ClaimTypes.FamilyName, "Smith"),
                new Claim(Constants.ClaimTypes.Email, "BobSmith@email.com"),
                new Claim(Constants.ClaimTypes.Name, "Bob Smith"),
            }
        },

Client:

        new Client
        {
            ClientName = "Silicon on behalf of Carbon Client",
            ClientId = "carbon",
            Enabled = true,
            AccessTokenType = AccessTokenType.Jwt,

            Flow = Flows.ResourceOwner,

            ClientSecrets = new List<Secret>
            {
                new Secret("21B5F798-BE55-42BC-8AA8-0025B903DC3B".Sha256())
            },


             AllowedScopes = new List<string>
            {
                Constants.StandardScopes.OpenId,
                Constants.StandardScopes.Profile,
                Constants.StandardScopes.Email,
                Constants.StandardScopes.Roles,
                Constants.StandardScopes.OfflineAccess,
                "read",
                "write",
                "api1",
                "morhipo"
            },



        }

MVC Client :

Startup:

public void ConfigureAuth(IAppBuilder app)
{
    AntiForgeryConfig.UniqueClaimTypeIdentifier = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier";
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        LoginPath = new PathString("/account/login"),
        AuthenticationType = "Cookies"
    });
}

AccountController :

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    TokenResponse token = await GetToken(model.Email, model.Password);

    await SignInAsync(token);

    return View(model);
}

private async Task<TokenResponse> GetToken(string user, string password)
{
    var client = new TokenClient(
       "https://localhost:44333/core/connect/token",
       "carbon",
       "21B5F798-BE55-42BC-8AA8-0025B903DC3B");

    var result = await client.RequestResourceOwnerPasswordAsync(user, password, "morhipo api1 offline_access");
    return result;

}
public async Task SignInAsync(TokenResponse token)
{
    var claims = await ValidateIdentityTokenAsync(token);

    var id = new ClaimsIdentity(claims, "Cookies");
    id.AddClaim(new Claim("access_token", token.AccessToken));
    id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(token.ExpiresIn).ToLocalTime().ToString()));
    id.AddClaim(new Claim("refresh_token", token.RefreshToken));
    Request.GetOwinContext().Authentication.SignIn(id);
}

private async Task<IEnumerable<Claim>> ValidateIdentityTokenAsync(TokenResponse token)
{
    return await Task.Run<IEnumerable<Claim>>(() =>
    {
        JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();

        var certString = "MIIDBTCCAfGgAwIBAgIQNQb+T2ncIrNA6cKvUA1GWTAJBgUrDgMCHQUAMBIxEDAOBgNVBAMTB0RldlJvb3QwHhcNMTAwMTIwMjIwMDAwWhcNMjAwMTIwMjIwMDAwWjAVMRMwEQYDVQQDEwppZHNydjN0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqnTksBdxOiOlsmRNd+mMS2M3o1IDpK4uAr0T4/YqO3zYHAGAWTwsq4ms+NWynqY5HaB4EThNxuq2GWC5JKpO1YirOrwS97B5x9LJyHXPsdJcSikEI9BxOkl6WLQ0UzPxHdYTLpR4/O+0ILAlXw8NU4+jB4AP8Sn9YGYJ5w0fLw5YmWioXeWvocz1wHrZdJPxS8XnqHXwMUozVzQj+x6daOv5FmrHU1r9/bbp0a1GLv4BbTtSh4kMyz1hXylho0EvPg5p9YIKStbNAW9eNWvv5R8HN7PPei21AsUqxekK0oW9jnEdHewckToX7x5zULWKwwZIksll0XnVczVgy7fCFwIDAQABo1wwWjATBgNVHSUEDDAKBggrBgEFBQcDATBDBgNVHQEEPDA6gBDSFgDaV+Q2d2191r6A38tBoRQwEjEQMA4GA1UEAxMHRGV2Um9vdIIQLFk7exPNg41NRNaeNu0I9jAJBgUrDgMCHQUAA4IBAQBUnMSZxY5xosMEW6Mz4WEAjNoNv2QvqNmk23RMZGMgr516ROeWS5D3RlTNyU8FkstNCC4maDM3E0Bi4bbzW3AwrpbluqtcyMN3Pivqdxx+zKWKiORJqqLIvN8CT1fVPxxXb/e9GOdaR8eXSmB0PgNUhM4IjgNkwBbvWC9F/lzvwjlQgciR7d4GfXPYsE1vf8tmdQaY8/PtdAkExmbrb9MihdggSoGXlELrPA91Yce+fiRcKY3rQlNWVd4DOoJ/cPXsXwry8pWjNCo5JD8Q+RQ5yZEy7YPoifwemLhTdsBz3hlZr28oCGJ3kbnpW0xGvQb3VHSTVVbeei0CfXoW6iz1";
        var cert = new X509Certificate2(Convert.FromBase64String(certString));
        TokenValidationParameters validationParameters = new TokenValidationParameters
        {
            ValidAudience = "https://localhost:44333/core/resources",
            ValidIssuer = "https://localhost:44333/core",
            NameClaimType ="name",

            IssuerSigningTokens = new X509CertificateSecurityTokenProvider(
                     "https://localhost:44333/core",
                     cert).SecurityTokens
        };

        SecurityToken t;
        ClaimsPrincipal id = tokenHandler.ValidateToken(token.AccessToken, validationParameters, out t);
        var claimList =id.Claims.ToList();
        claimList.Add(new Claim(ClaimTypes.Name, id.Identity.Name));
        return claimList.AsEnumerable();
    });

}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
    Request
   .GetOwinContext()
   .Authentication
   .SignOut("Cookies");
    return RedirectToAction("Index", "Home");
}

You need to make Identity Server aware of the social login providers. You do this by registering them as IdentityProviders on the AuthenticationOptions of the IdentityServerOptions.

For example to add Facebook authentication;

Install-Package Microsoft.Owin.Security.Facebook -Version 2.1.0
public static void Configuration(IAppBuilder appBuilder)
{
    appBuilder.Map("/core", builder =>
        {
            builder
                .UseIdentityServer(new IdentityServerOptions
                {
                    AuthenticationOptions = new AuthenticationOptions
                    {
                        IdentityProviders = (app, signInAsType) => 
                            app.UseFaceBookAuthentication(
                                new FacebookAuthenticationOptions
                                {
                                    AuthenticationType = "Facebook",
                                    Caption = "Facebook",
                                    SignInAsAuthenticationType = signInAsType,
                                    AppId = "...",
                                    AppSecret = "..."
                                }
                    }
                }));
        }
}

Setting the SignInAsAuthenticationType property on the provider to the signInAsType is the key part as this establishes the link between the signed in prinicipal and the identity server.

There's some more information on this here;

https://identityserver.github.io/Documentation/docsv2/configuration/identityProviders.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM