如何在 asp.net core 2.2 中实现 Cookie 基本身份验证和 jwt?

时间:2023-03-27
本文介绍了如何在 asp.net core 2.2 中实现 Cookie 基本身份验证和 jwt?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我想在我的程序中同时使用基于 cookie 的身份验证和 jwt,使用身份验证用户通过登录和 JWT 访问 mvc 控制器来访问 WebApi 资源.

I want to use both cookie based authentication and jwt in my program, used authentication user to access mvc controller with login and JWT to access WebApi resource.

我尝试使用其中两个 首先,我的客户端可以使用用户名和密码登录并使用 cookie 进行身份验证.使用带有令牌承载的 WebApi 的应用程序的第二次访问资源,但出现错误!

I tried using two of them First, my client can login and authenticate with the cookie using username and password. Second access resource from Application with WebApi with Token Bearer but I get an error!

在我的 startup.cs 文件中,我有:

In my startup.cs file I have:

public void ConfigureServices(IServiceCollection services)
        {


            services.Configure<CookiePolicyOptions>(options =>
            {
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
                options.ConsentCookie.Name = "Cookie";
            });
            services.ConfigureApplicationCookie(options =>
            {
                options.Cookie.Name = "Cookie";
                options.ClaimsIssuer = Configuration["Authentication:ClaimsIssuer"];
            });

            services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));

            services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultUI(UIFramework.Bootstrap4)
                .AddDefaultTokenProviders();

            services.Configure<IdentityOptions>(options =>
            {
                // Password settings.
                options.Password.RequireDigit = true;
                options.Password.RequireLowercase = true;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireUppercase = false;
                options.Password.RequiredLength = 5;
                options.Password.RequiredUniqueChars = 1;

                // Lockout settings.
                options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
                options.Lockout.MaxFailedAccessAttempts = 5;
                options.Lockout.AllowedForNewUsers = true;

                // User settings.
                options.User.AllowedUserNameCharacters =
                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
                options.User.RequireUniqueEmail = false;

                //Token
            });

            services.AddAuthentication(options =>
            {
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;

            })
                .AddCookie(options =>
                {
                    options.Cookie.Name = "Cookie";
                    options.ClaimsIssuer = Configuration["Authentication:ClaimsIssuer"];
                })
                .AddMicrosoftAccount(microsoftOptions =>
                 {
                     microsoftOptions.ClientId = Configuration["Authentication:Microsoft:ApplicationId"];
                     microsoftOptions.ClientSecret = Configuration["Authentication:Microsoft:Password"];
                 })
                .AddGoogle(googleOptions => 
                {
                    googleOptions.ClientId = "XXXXXXXXXXX.apps.googleusercontent.com";
                    googleOptions.ClientSecret = "g4GZ2#...GD5Gg1x";
                    googleOptions.Scope.Add("https://www.googleapis.com/auth/plus.login");
                    googleOptions.ClaimActions.MapJsonKey(ClaimTypes.Gender, "gender");
                    googleOptions.SaveTokens = true;
                    googleOptions.Events.OnCreatingTicket = ctx =>
                    {
                        List<AuthenticationToken> tokens = ctx.Properties.GetTokens()
                            as List<AuthenticationToken>;
                        tokens.Add(new AuthenticationToken()
                        {
                            Name = "TicketCreated",
                            Value = DateTime.UtcNow.ToString()
                        });
                        ctx.Properties.StoreTokens(tokens);
                        return Task.CompletedTask;
                    };
                })
                .AddJwtBearer(options =>
                {
                    options.ClaimsIssuer = Configuration["Authentication:ClaimsIssuer"];
                    options.SaveToken = true;
                    options.Authority = Configuration["Authentication:Authority"];
                    options.Audience = Configuration["Authentication:Audience"];
                    options.RequireHttpsMetadata = false;
                    options.TokenValidationParameters = new TokenValidationParameters()
                    {

                        ValidateIssuerSigningKey = true,

                        ValidateIssuer = true,
                        ValidIssuer = Configuration["Authentication:ValidIssuer"],

                        ValidateAudience = true,
                        ValidAudience = Configuration["Authentication:ValidAudience"],

                        ValidateLifetime = true,

                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Authentication:SecurityKey"]))
                    };
                });






            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddSession();

            services.AddSingleton<IConfiguration>(Configuration);

        }

我在这个控制器中得到了一个令牌:

And I got a token in this controller:

[AllowAnonymous]
        [HttpPost]
        public async Task<IActionResult> GetToken(TokenLoginModel model)
        {

            if (!ModelState.IsValid) return BadRequest("Token failed to generate");
            var user = await _usermanager.FindByNameAsync(model.UserName);
            //var user = true;// (model.Password == "password" && model.Username == "username");
            if (user != null && await _usermanager.CheckPasswordAsync(user, model.Password))
            {
                var claims = new[]{
                    new Claim("ClaimsIssuer", _configuration.GetSection("Authentication:ClaimsIssuer").Value),
                new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Sub,user.UserName),
                new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())
            };
                string SecurKey = Startup.StaticConfig.GetSection("Authentication:SecurityKey").Value;
                var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurKey));
                var token = new JwtSecurityToken(
                    issuer: _configuration.GetSection("Authentication:ValidIssuer").Value,
                    audience: _configuration.GetSection("Authentication:Audience").Value,
                    expires: DateTime.UtcNow.AddDays(30),
                    claims: claims,
                    signingCredentials: new Microsoft.IdentityModel.Tokens.SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
                );
                return Ok(new
                {
                    token = new JwtSecurityTokenHandler().WriteToken(token),
                    expiration = token.ValidTo
                });
            }
            return Unauthorized();

        }

我实现了创建令牌的控制,但是当我尝试使用它进行授权时,我得到了这个错误:

I implement control that creates token, but when I tried authorizing with that I get this error:

An unhandled exception occurred while processing the request.

HttpRequestException: Response status code does not indicate success: 404 (Not Found).
System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()

IOException: IDX20804: Unable to retrieve document from: 'https://localhost:44383/oauth2/default/.well-known/openid-configuration'.
Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string address, CancellationToken cancel)

InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://localhost:44383/oauth2/default/.well-known/openid-configuration'.
Microsoft.IdentityModel.Protocols.ConfigurationManager<T>.GetConfigurationAsync(CancellationToken cancel)

推荐答案

为了增加对 JWT 的支持,我们添加了 AddCookie 和 AddJwtBearer.让网站需要标头中的令牌会让人头疼,尤其是对于不是纯粹的 SPA 或 API 的项目.所以我真正想要的是同时支持 Cookie 和 JWT.

In order to add support for JWT, we added the AddCookie and AddJwtBearer. Having websites require the token in the header would be a headache, especially for projects that aren’t purely SPA or API. So what I really wanted was support for both Cookies and JWTs.

在 startup.cs 你有:

In startup.cs you have:

    public class Startup
  {
    public Startup(IConfiguration configuration)
    {
      Configuration = configuration;
    }
    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
      services.AddDbContext<DualAuthContext>(options =>
          options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

      services.AddIdentity<ApplicationUser, IdentityRole>()
          .AddEntityFrameworkStores<DualAuthContext>()
          .AddDefaultTokenProviders();

      // Enable Dual Authentication 
      services.AddAuthentication()
        .AddCookie(cfg => cfg.SlidingExpiration = true)
        .AddJwtBearer(cfg =>
        {
          cfg.RequireHttpsMetadata = false;
          cfg.SaveToken = true;
          cfg.TokenValidationParameters = new TokenValidationParameters()
          {
            ValidIssuer = Configuration["Tokens:Issuer"],
            ValidAudience = Configuration["Tokens:Issuer"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"]))
          };
        });

      // Add application services.
      services.AddTransient<IEmailSender, EmailSender>();
      services.AddMvc();
    }

在配置方法中:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, DataSeeder seeder)
{
  ...
  app.UseAuthentication();
}

在您的控制器中使用 JWT 之后,您应该将 JWT Bearer AuthenticationSchemes 添加到 Authorize 属性,如下所示:

After this in your controller that one you have used JWT, You should add JWT Bearer AuthenticationSchemes to Authorize attribute like this :

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
  [Route("/api/customers")]
  public class ProtectedController : Controller
  {
    public ProtectedController()
    {
    }

    public IActionResult Get()
    {
      return Ok(new[] { "One", "Two", "Three" });
    }
  }

参考:ASP.NET 中的两个 AuthorizationSchemes核心2

使用起来非常简单实用.

It's very simple and helpful to used.

这篇关于如何在 asp.net core 2.2 中实现 Cookie 基本身份验证和 jwt?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:尝试使用 .NET JWT 库生成令牌时出错 下一篇:.NET Core 2.0 身份和 jwt?

相关文章