IdentityServer4 с аутентификацией Google и почтальоном - PullRequest
0 голосов
/ 11 апреля 2019

Я использую IdentityServer4 с IdentityServer4.UI с authorization_code и Google authentication.

Это мой Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    // ...
    const string connectionString = @"Data Source=.\SQLEXPRESS;database=Is4.LearnIs4;trusted_connection=yes;";
    var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

    services
        .AddIdentityServer()
        .AddDeveloperSigningCredential()
        //.AddProfileService<IdentityServerProfileService>()
        //.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
        // this adds the config data from DB (clients, resources)
        .AddConfigurationStore(options =>
        {
            options.ConfigureDbContext = builder =>
            {
                builder.UseSqlServer(connectionString,
                    sql => sql.MigrationsAssembly(migrationsAssembly));
            };
        })
        // this adds the operational data from DB (codes, tokens, consents)
        .AddOperationalStore(options =>
        {
            options.ConfigureDbContext = builder =>
                builder.UseSqlServer(connectionString,
                    sql => sql.MigrationsAssembly(migrationsAssembly));
            // this enables automatic token cleanup. this is optional.
            options.EnableTokenCleanup = true;
        });

    // Add jwt validation.
    services
        .AddAuthentication()
        .AddGoogle("Google", options =>
        {
            options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

            options.ClientId = "<my-client-id>";
            options.ClientSecret = "<my-secret>";

            options.AccessType = "offline";
        })
        .AddOpenIdConnect("demoidsrv", "IdentityServer", options =>
        {
            options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
            options.SignOutScheme = IdentityServerConstants.SignoutScheme;

            options.Authority = "http://localhost:57547";
            options.ClientId = "implicit";
            options.ResponseType = "id_token";
            options.SaveTokens = true;
            options.CallbackPath = new PathString("/signin-idsrv");
            options.SignedOutCallbackPath = new PathString("/signout-callback-idsrv");
            options.RemoteSignOutPath = new PathString("/signout-idsrv");
            options.RequireHttpsMetadata = false;

            options.TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = "name",
                RoleClaimType = "role"
            };
        });
    // ...
}

И это мои конфигурации клиента:


/// <summary>
/// Seed database.
/// </summary>
/// <param name="app"></param>
public static void Seed(IApplicationBuilder app)
{
    using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
    {
        serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();

        var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
        context.Database.Migrate();
        if (!context.Clients.Any())
        {
            foreach (var client in LoadClients())
                context.Clients.Add(client.ToEntity());
            context.SaveChanges();
        }

        if (!context.IdentityResources.Any())
        {
            foreach (var resource in LoadIdentityResources())
                context.IdentityResources.Add(resource.ToEntity());
            context.SaveChanges();
        }

        if (!context.ApiResources.Any())
        {
            foreach (var resource in LoadApiResources())
                context.ApiResources.Add(resource.ToEntity());
            context.SaveChanges();
        }
    }
}

/// <summary>
/// Load pre-defined identity resource.
/// </summary>
/// <returns></returns>
private static IEnumerable<IdentityResource> LoadIdentityResources()
{
    var identityResources = new List<IdentityResource>();
    identityResources.Add(new IdentityResources.OpenId());
    identityResources.Add(new IdentityResources.Profile());

    return identityResources;
}

/// <summary>
/// Load pre-defined api resources.
/// </summary>
/// <returns></returns>
private static IEnumerable<ApiResource> LoadApiResources()
{
    var apiResources = new List<ApiResource>();

    var api1Resource = new ApiResource("api1", "My API");
    api1Resource.ApiSecrets = new List<Secret>();
    api1Resource.ApiSecrets.Add(new Secret("secret".Sha256()));
    apiResources.Add(api1Resource);

    return apiResources;
}

/// <summary>
/// Load pre-defined clients.
/// </summary>
/// <returns></returns>
private static IEnumerable<Client> LoadClients()
{
    var clients = new List<Client>();

    var clientCredentialClient = new Client();
    clientCredentialClient.ClientId = "client";
    clientCredentialClient.AllowedGrantTypes = GrantTypes.ClientCredentials;
    clientCredentialClient.ClientSecrets = new List<Secret>();
    clientCredentialClient.ClientSecrets.Add(new Secret("secret".Sha256()));
    clientCredentialClient.AllowedScopes = new List<string>();
    clientCredentialClient.AllowedScopes.Add("api1");
    clients.Add(clientCredentialClient);

    var resourceOwnerPasswordClient = new Client();
    resourceOwnerPasswordClient.ClientId = "ro.client";
    resourceOwnerPasswordClient.AllowedGrantTypes = new List<string>();
    resourceOwnerPasswordClient.AllowedGrantTypes.Add(GrantType.ResourceOwnerPassword);
    resourceOwnerPasswordClient.AllowedGrantTypes.Add("refresh_token");
    resourceOwnerPasswordClient.ClientSecrets = new List<Secret>();
    resourceOwnerPasswordClient.ClientSecrets.Add(new Secret("secret".Sha256()));
    resourceOwnerPasswordClient.AllowedScopes = new List<string>();
    resourceOwnerPasswordClient.AllowedScopes.Add("api1");
    resourceOwnerPasswordClient.AllowOfflineAccess = true;
    resourceOwnerPasswordClient.RefreshTokenExpiration = TokenExpiration.Sliding;
    resourceOwnerPasswordClient.RefreshTokenUsage = TokenUsage.ReUse;
    resourceOwnerPasswordClient.SlidingRefreshTokenLifetime = 3600;
    clients.Add(resourceOwnerPasswordClient);

    var authorizationCodeClient = new Client();
    authorizationCodeClient.ClientId = "mvc";
    authorizationCodeClient.ClientName = "MVC Client";
    authorizationCodeClient.AllowedGrantTypes = new List<string>();
    authorizationCodeClient.AllowedGrantTypes.Add(GrantType.AuthorizationCode);
    authorizationCodeClient.ClientSecrets = new List<Secret>();
    authorizationCodeClient.ClientSecrets.Add(new Secret("secret".Sha256()));
    authorizationCodeClient.RedirectUris = new List<string>();
    authorizationCodeClient.RedirectUris.Add("http://localhost:4300");
    authorizationCodeClient.PostLogoutRedirectUris = new List<string>();
    authorizationCodeClient.PostLogoutRedirectUris.Add("http://localhost:5002/signout-callback-oidc");
    authorizationCodeClient.RequirePkce = false;
    authorizationCodeClient.AllowedScopes = new List<string>();
    authorizationCodeClient.AllowedScopes.Add(IdentityServerConstants.StandardScopes.OpenId);
    authorizationCodeClient.AllowedScopes.Add(IdentityServerConstants.StandardScopes.Profile);
    authorizationCodeClient.AllowedScopes.Add("api1");
    authorizationCodeClient.AllowOfflineAccess = true;
    authorizationCodeClient.RequireConsent = false;
    clients.Add(authorizationCodeClient);

    var codeClient = new Client();
    codeClient.ClientId = "js";
    codeClient.ClientName = "JavaScript Client";
    codeClient.AllowedGrantTypes = GrantTypes.Code;
    codeClient.RequirePkce = true;
    codeClient.RequireClientSecret = false;
    codeClient.RedirectUris = new List<string>();
    codeClient.RedirectUris.Add("http://localhost:5003/callback.html");
    codeClient.PostLogoutRedirectUris = new List<string>();
    codeClient.PostLogoutRedirectUris.Add("http://localhost:5003/index.html");
    codeClient.AllowedCorsOrigins = new List<string>();
    codeClient.AllowedCorsOrigins.Add("http://localhost:5003");
    codeClient.AllowedScopes = new List<string>();
    codeClient.AllowedScopes.Add(IdentityServerConstants.StandardScopes.OpenId);
    codeClient.AllowedScopes.Add(IdentityServerConstants.StandardScopes.Profile);
    codeClient.AllowedScopes.Add("api1");
    clients.Add(codeClient);

    return clients;
}

Я сделал запрос к IdentityServer4 , как показано на рисунке ниже:

enter image description here

Отображается одно всплывающее окно:

enter image description here

Если я войду, используя username и password, я могуполучите access_token.Но когда я нажал кнопку Google в Account/Login, я не смогу получить access token.

Вот что я получил в Visual Studio ouput:

IdentityServer4.EntityFramework.Stores.PersistedGrantStore:Debug: P+z5g2/MhMzrbCEGMZOgx06VKeB38F1yx/y3C08vZlo= found in database: False
IdentityServer4.Stores.DefaultAuthorizationCodeStore:Debug: authorization_code grant with value: 4/KQGa0Oj2BztGi86v5SbFD0oVvnXIV8dZWFAQS16O-tyFVOcZXWvRQbByFb18Hhco5SgmkAQtPvk1ZD8lY8eLN9Q not found in store.
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 338.1411ms 500 text/html; charset=utf-8
IdentityServer4.Validation.TokenRequestValidator:Error: Invalid authorization code{ code = 4/KQGa0Oj2BztGi86v5SbFD0oVvnXIV8dZWFAQS16O-tyFVOcZXWvRQbByFb18Hhco5SgmkAQtPvk1ZD8lY8eLN9Q }, details: {
  "ClientId": "mvc",
  "ClientName": "MVC Client",
  "GrantType": "authorization_code",
  "AuthorizationCode": "4/KQGa0Oj2BztGi86v5SbFD0oVvnXIV8dZWFAQS16O-tyFVOcZXWvRQbByFb18Hhco5SgmkAQtPvk1ZD8lY8eLN9Q",
  "Raw": {
    "grant_type": "authorization_code",
    "code": "4/KQGa0Oj2BztGi86v5SbFD0oVvnXIV8dZWFAQS16O-tyFVOcZXWvRQbByFb18Hhco5SgmkAQtPvk1ZD8lY8eLN9Q",
    "redirect_uri": "http://localhost:57547/signin-idsrv",
    "client_id": "mvc",
    "client_secret": "***REDACTED***"
  }
}

Я делаючто-то не так?

Спасибо.

1 Ответ

0 голосов
/ 13 апреля 2019

Кажется, что authorization_code грант не подходит для этой ситуации.Когда я изменил authorization_code на hybrid грант, он работает.

На самом деле я изменил:

authorizationCodeClient.AllowedGrantTypes = new List<string>();
authorizationCodeClient.AllowedGrantTypes.Add(GrantType.AuthorizationCode);

На

authorizationCodeClient.AllowedGrantTypes = GrantTypes.Hybrid;

Использование https://oidcdebugger.com/ для генерации строки запроса:

http://localhost:57547/connect/authorize?client_id=mvc&redirect_uri=http%3A%2F%2Flocalhost%3A4300&scope=api1%20offline_access%20openid&response_type=code%20token%20id_token&response_mode=fragment&nonce=556bs2pazg2.

Магическим образом, я могу войти в систему, используя учетную запись и пароль и учетную запись Google .

Надеюсь, что это поможет кому-то застрять в IdentityServer4 , как я сделал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...