首页 > 解决方案 > 无法使用“/connect/authorize”端点从 IdentityServer4 获取授权码

问题描述

我正在开发一个 SPA 应用程序,其 Identityserver4 介于 Angular 和 .net API 之间。身份服务器的大部分配置都已完成,唯一的障碍是,当我调用 /connect/authorize 时,我没有获得授权码,我得到了一个带有我提供的数据的编码重定向 URL。我错过了什么吗?我真的无法理解它为什么会有这种行为。

邮递员截图

这是客户端配置

new Client
            {
                ClientId = "Angular",
                ClientName = "Angular Client",
                AlwaysIncludeUserClaimsInIdToken = true,
                AllowedGrantTypes = new List<string> { GrantType.AuthorizationCode },
                RequirePkce =true,
                RequireClientSecret = false,
                RequireConsent = false,
                ClientSecrets =
                {
                  
                    new Secret("secret".Sha512(),"my secret")
                },
                
                AllowedScopes = {"WebAPI","fullcontroll",IdentityServerConstants.StandardScopes.OpenId},
                Claims = new List<ClientClaim>
                {
                    new ClientClaim("clientName", "SPA"),
                  
                },
                RedirectUris = { "https://localhost:6001/login" },
                FrontChannelLogoutUri = "https://localhost:4001/signout-oidc",
                PostLogoutRedirectUris = { "http://localhost:4001/signout-callback-oidc" },
                AllowedCorsOrigins = new List<string>
                {
                    "https://localhost:4001",
                    "https://localhost:5001",
                    "https://localhost:6001",
                },
                AllowOfflineAccess =true,
                AccessTokenLifetime = 3600,
                IdentityTokenLifetime = 300,
                AlwaysSendClientClaims = true,
                Enabled = true
            },

启动.cs

 services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<IdentityServerContext>()
                .AddRoleManager<RoleManager<IdentityRole>>()
                .AddUserManager<UserManager<ApplicationUser>>()
                .AddSignInManager<SignInManager<ApplicationUser>>()         
                .AddDefaultTokenProviders();

        services.ConfigDbContext(Configuration);

        services.InjectClients(Configuration);

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            options.DefaultForbidScheme = OpenIdConnectDefaults.AuthenticationScheme;
            options.RequireAuthenticatedSignIn = true;
        })
        .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
    {
        options.Cookie.Name = "login-vault";
        options.Cookie.SameSite = SameSiteMode.Lax;
        //options.LoginPath = "/identityserver/login";
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
        options.Cookie.SecurePolicy = 0;
        options.SlidingExpiration = true;
        options.Events.OnSigningOut = async e =>
        {
            // revoke refresh token on sign-out
            await e.HttpContext.RevokeUserRefreshTokenAsync();
        };
    })
    .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
    {
        options.Authority = "https://localhost:4001";
        options.ClientId = "Angular";
        options.ClientSecret = "secret";
        options.Resource = "WebAPI";
        options.ResponseType = "code";
        try
        {
            var oidc = Registry.CurrentUser.OpenSubKey(@"Keys", true).OpenSubKey(@"IdentityServer", true).CreateSubKey("OIDC", true);
            options.DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo(oidc.ToString()),
                options =>
                {
                    options.UseCryptographicAlgorithms(
            new AuthenticatedEncryptorConfiguration()
            {
                EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
                ValidationAlgorithm = ValidationAlgorithm.HMACSHA512
            })
               .SetDefaultKeyLifetime(TimeSpan.FromDays(30))
               .PersistKeysToRegistry(Registry.CurrentUser.OpenSubKey(@"Keys", true).OpenSubKey(@"IdentityServer", true).OpenSubKey(@"OIDC", true))
               .ProtectKeysWithDpapi();
                })
            .CreateProtector("WebAPI");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

        options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;          
        options.UseTokenLifetime = true;
        options.GetClaimsFromUserInfoEndpoint = true;
        options.SaveTokens = true;
        options.UsePkce = true;
     
        options.Scope.Clear();
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.Scope.Add("email");
        options.Scope.Add("WebAPI");
        options.Scope.Add("offline_access");
   
        options.CallbackPath = "/signin-odic";
        options.SignedOutRedirectUri = "https://localhost:4001/connect/endsession";

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

        services.AddAccessTokenManagement(options =>
        {
            options.Client.Scheme = OpenIdConnectDefaults.AuthenticationScheme;
            options.User.Scheme = OpenIdConnectDefaults.AuthenticationScheme;
        });

        services.AddClientAccessTokenClient("Angular", configureClient: client =>
            client.BaseAddress = new Uri("https://localhost:5001/api/"));

        services.AddUserAccessTokenClient("ApplicationUsers", client =>
        {
            client.BaseAddress = new Uri("https://localhost:5001/api/");
        });

这是 IdentityServer 配置

services.AddIdentityServer(options =>
        {
            options.Authentication.CookieLifetime = TimeSpan.FromMinutes(5);
            options.Authentication.CookieSameSiteMode = SameSiteMode.Lax;
            options.Authentication.CookieSlidingExpiration = true;
            //options.Authentication.CheckSessionCookieName = "Identity.Session";
            options.EmitStaticAudienceClaim = true;
            options.IssuerUri = "https://localhost:4001";
            options.LowerCaseIssuerUri = true;
            options.Events.RaiseErrorEvents = true;
            options.Events.RaiseInformationEvents = true;
            options.Events.RaiseFailureEvents = true;
            options.Events.RaiseSuccessEvents = true;
            options.EmitScopesAsSpaceDelimitedStringInJwt = false;
            options.Endpoints.EnableCheckSessionEndpoint = true;
            options.Endpoints.EnableEndSessionEndpoint = true;
            options.Endpoints.EnableTokenEndpoint = true;
            options.Endpoints.EnableAuthorizeEndpoint = true;
            options.Endpoints.EnableJwtRequestUri = true;
            options.UserInteraction.LoginUrl = "https://localhost:6001/login";
            options.UserInteraction.LogoutUrl = "https://localhost:6001/logout";
            //options.UserInteraction.ConsentUrl = "";
        })
                .AddAspNetIdentity<ApplicationUser>()
                .AddDeveloperSigningCredential()
                //.AddSigningCredential(new X509Certificate2(Path.Combine(".", "certs", "IdentityServer4Auth.pfx")))
                .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = b => b.UseSqlServer(configuration.GetConnectionString("IdentityServer"),
                        sql => sql.MigrationsAssembly(migrationAssembly));
                })
                .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = b => b.UseSqlServer(configuration.GetConnectionString("IdentityServer"),
                        sql => sql.MigrationsAssembly(migrationAssembly));
                    options.EnableTokenCleanup = false;
                    options.TokenCleanupInterval = 3600;
                });

非常感谢您的帮助!谢谢!

标签: c#asp.net-coreidentityserver4

解决方案


授权端点旨在在浏览器内调用(通常是 GET 请求,但也支持通过表单的 POST)。这样,如果需要交互式身份验证,端点可以重定向到该 UI,然后在完成后继续为请求提供服务。

您的identityserver4实例配置为https://localhost:6001/login用于身份验证,这就是您看到 302 重定向到该 URL 的原因 - 授权端点看到用户未经过身份验证(不存在 cookie)并自动重定向到options.UserInteraction.LoginUrl.


推荐阅读