如何使用oauth2授权端点

x7rlezfr  于 2023-06-21  发布在  其他
关注(0)|答案(1)|浏览(104)

我在做一个网络项目。有4个API。一个是身份服务器,它是用openiddict实现的。下面您可以看到身份服务器项目启动类

//startup.cs
public class Startup
{
    public Startup(IConfiguration configuration)
         => Configuration = configuration;

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<MailSettings1>(Configuration.GetSection("MailSettings1"));
        services.AddTransient<IEmailSender, Services.MailService>();

        services.AddControllersWithViews();

        services.Configure<DataProtectionTokenProviderOptions>(o =>
                o.TokenLifespan = TimeSpan.FromMinutes(5));

        services.ConfigureApplicationCookie(o =>
        {
            o.ExpireTimeSpan = TimeSpan.FromDays(1);
            o.SlidingExpiration = true;
        });
        services.AddDbContext<ApplicationDbContext>(options =>
        {
              // Configure the context to use Microsoft SQL Server.
              options.UseNpgsql(
              Configuration.GetConnectionString("identitydb"),
                    opt =>
                    {
                        opt.EnableRetryOnFailure(
                            maxRetryCount: 10,
                            maxRetryDelay: TimeSpan.FromSeconds(30),
                            errorCodesToAdd: new List<string>() { });

                        opt.UseAdminDatabase("postgres");
                    });

                options.UseOpenIddict();
            });

        services.AddIdentity<ApplicationUser, IdentityRole>(options =>
        {
             options.Lockout.MaxFailedAccessAttempts = 4;
             options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
             options.Password.RequiredLength = 8;
             options.Password.RequireLowercase = true;
             options.Password.RequireUppercase = true;
             options.Password.RequireNonAlphanumeric = false;
             options.Password.RequireDigit = true;
        })
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

        services.Configure<IdentityOptions>(options =>
        {
            options.ClaimsIdentity.UserNameClaimType = Claims.Name;
            options.ClaimsIdentity.UserIdClaimType = Claims.Subject;
            options.ClaimsIdentity.RoleClaimType = Claims.Role;
            options.ClaimsIdentity.EmailClaimType = Claims.Email;
        });

        services.AddQuartz(options =>
        {
            options.UseMicrosoftDependencyInjectionJobFactory();
            options.UseSimpleTypeLoader();
            options.UseInMemoryStore();
        });

        services.AddQuartzHostedService(options => options.WaitForJobsToComplete = true);
        services.Configure<CookieTempDataProviderOptions>(options =>
        {
            options.Cookie.IsEssential = true;
        });

        services.AddSession();
        services.AddOpenIddict()

            // Register the OpenIddict core components.
            .AddCore(options =>
            {
              
                options.UseEntityFrameworkCore()
                           .UseDbContext<ApplicationDbContext>();

              
                options.UseQuartz();
            })

            // Register the OpenIddict server components.
            .AddServer(options =>
            {
                // Enable the authorization, device, logout, token, userinfo and verification endpoints.
                options.SetAuthorizationEndpointUris("/connect/authorize")
                           .SetDeviceEndpointUris("/connect/device")
                           .SetLogoutEndpointUris("/connect/logout")
                           .SetTokenEndpointUris("/connect/token")
                           .SetUserinfoEndpointUris("/connect/userinfo")
                           .SetVerificationEndpointUris("/connect/verify");

                // Note: this sample uses the code, device code, password and refresh token flows, but you
                // can enable the other flows if you need to support implicit or client credentials.
                options.AllowAuthorizationCodeFlow()
                           .AllowDeviceCodeFlow()
                           .AllowPasswordFlow()
                           .AllowRefreshTokenFlow();

                // Mark the "email", "profile", "roles" and "demo_api" scopes as supported scopes.
                options.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles, "demo_api");

                // Register the signing and encryption credentials.
                options.AddDevelopmentEncryptionCertificate()
                           .AddDevelopmentSigningCertificate();

                // Force client applications to use Proof Key for Code Exchange (PKCE).
                options.RequireProofKeyForCodeExchange();

                // Register the ASP.NET Core host and configure the ASP.NET Core-specific options.
                options.UseAspNetCore()
                           .EnableStatusCodePagesIntegration()
                           .EnableAuthorizationEndpointPassthrough()
                           .EnableLogoutEndpointPassthrough()
                           .EnableTokenEndpointPassthrough()
                           .EnableUserinfoEndpointPassthrough()
                           .EnableVerificationEndpointPassthrough()
                           .DisableTransportSecurityRequirement(); // During development, you can disable the HTTPS requirement.

                // Note: if you don't want to specify a client_id when sending
                // a token or revocation request, uncomment the following line:
                //
                // options.AcceptAnonymousClients();

                // Note: if you want to process authorization and token requests
                // that specify non-registered scopes, uncomment the following line:
                //
                // options.DisableScopeValidation();

                // Note: if you don't want to use permissions, you can disable
                // permission enforcement by uncommenting the following lines:
                //
                // options.IgnoreEndpointPermissions()
                //        .IgnoreGrantTypePermissions()
                //        .IgnoreResponseTypePermissions()
                //        .IgnoreScopePermissions();

                // Note: when issuing access tokens used by third-party APIs
                // you don't own, you can disable access token encryption:
                //
                // options.DisableAccessTokenEncryption();
            })

            // Register the OpenIddict validation components.
            .AddValidation(options =>
            {
               
                options.AddAudiences("resource_server");

             
                options.UseLocalServer();

                options.UseAspNetCore();

            
            });

        // services.AddTransient<IEmailSender, AuthMessageSender>();
        services.AddTransient<ISmsSender, AuthMessageSender>();
        services.AddCustomDaprClient();

        // Register the worker responsible of seeding the database with the sample clients.
        // Note: in a real world application, this step should be part of a setup script.
        services.AddHostedService<Worker>();
        services.AddSession(options =>
        {
            options.IdleTimeout = TimeSpan.FromSeconds(10);
            options.Cookie.HttpOnly = true;
            options.Cookie.IsEssential = true;
        });

        services.AddCors();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseDeveloperExceptionPage();

        app.UseStaticFiles();

        app.UseStatusCodePagesWithReExecute("/error");

        app.UseRouting();

        app.UseCors(x => x
                .AllowAnyMethod()
                .AllowAnyHeader()
                .SetIsOriginAllowed(origin => true) // allow any origin
                .AllowCredentials()); // allow credentials

        app.UseSession();

        app.UseRequestLocalization(options =>
        {
            options.AddSupportedCultures("en-US", "fr-FR");
            options.AddSupportedUICultures("en-US", "fr-FR");
            options.SetDefaultCulture("en-US");
        });

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(options => options.MapControllerRoute(
         name: "default",
         pattern: "{controller=Account}/{action=Register}/{id?}"));
    }
}

现在我想使用这个身份服务器来保护其他API端点。
例如,假设我有一个“预订”API。我想保护某个端点。当从UI发送请求时,它在报头中包括承载令牌(已经实现)。使用下一个js for UI框架)。我需要验证访问令牌并检查它是否未过期。

[HttpGet("name")]
[Authorize]
public async Task<ActionResult<ResponseVM>> IsBooked(string name)
{
    return await _mediator.Send(new GetBookingDetailsByHotelNameQuery(name));
}

像上面我们可以使用Authorize标签来保护。有人可以告诉我如何检查如果令牌是valide从这个“预订”API使用身份服务器
身份服务器url -http://localhost:5001我们可以从这个url“http://localhost:5001/. well-known/openid-configuration”获取打开的ID配置
下面你可以看到我添加了身份验证中间件到“预订”API项目
startup.cs

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                   .AddJwtBearer(options =>
                   {
                       options.Authority = "http://localhost:5003";
                       options.RequireHttpsMetadata = false;
    
                       options.TokenValidationParameters = new TokenValidationParameters
                       {
                           ValidateAudience = false
                       };
                   });

但我得到了这个错误

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
fail: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[3]
Exception occurred while processing message.
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String'.
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HMR7VA4R2D46", Request id "0HMR7VA4R2D46:00000003": An unhandled exception was thrown by the application.
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String'.
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/1.1 GET http://localhost:5005/api/Practice/uukuk - - - 500 0 - 12.5820ms
kpbpu008

kpbpu0081#

您可以创建自定义中间件并使用JWTSecurityTokenHandler类。参考https://learn.microsoft.com/en-us/dotnet/api/system.identitymodel.tokens.jwt.jwtsecuritytokenhandler?view=msal-web-dotnet-latest
代码参考:

var token = httpContext.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
                    var tokenHandler = new JwtSecurityTokenHandler();
                    if (token != null && tokenHandler.CanReadToken(token))
                    {
                        var tokenPayload = tokenHandler.ReadJwtToken(token).Payload;
                        var issuer = tokenPayload.Iss;
                        var jsonKeyString = GetJsonKeyString(issuer);
                        tokenHandler.ValidateToken(token, new TokenValidationParameters
                        {
                            IssuerSigningKey = new JsonWebKey(jsonKeyString),
                            ValidateAudience = false,
                            ValidateIssuer = false,
                            ValidateIssuerSigningKey = true,
                            ValidateLifetime = Convert.ToBoolean(_configuration["JWT:validateLifetime"])
                        }, out SecurityToken validatedToken);

                        await _next(httpContext);````

相关问题