JWT 不记名令牌授权应用于 .NET Core 中的现有 MVC Web 应用程序

Posted

技术标签:

【中文标题】JWT 不记名令牌授权应用于 .NET Core 中的现有 MVC Web 应用程序【英文标题】:JWT bearer token authorization being applied on exisitng MVC web appication in .NET Core 【发布时间】:2019-08-02 13:42:46 【问题描述】:

我正在 .net 核心中试用 Web API。我已将 API 控制器添加到现有的 .net 核心 MVC Web 应用程序中。

我正在使用 JWT 令牌进行授权。我是通过启动类来做这个的。

API 工作正常。

但正如预期的那样,授权正在应用于整个 MVC 应用程序。

有没有一种方法可以通过不记名令牌启用身份验证,仅适用于 API 控制器,而不适用于 Web 应用程序控制器?

Startup.cs:

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Project.Data;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

namespace Project

    public class Startup
    
        public Startup(IConfiguration configuration)
        
            Configuration = configuration;
        

        public IConfiguration Configuration  get; 
        public bool ValidateAudience  get; private set; 

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

            services.AddIdentity<IdentityUser,IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            services.Configure<CookiePolicyOptions>(options =>
            
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;

            );

            services.ConfigureApplicationCookie(options =>
            
                options.Cookie.HttpOnly = true;
                options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
                options.LoginPath = "/Identity/Account/Login"; 
                options.LogoutPath = "/Identity/Account/Logout"; 
                options.AccessDeniedPath = "/Identity/Account/AccessDenied"; 
                options.SlidingExpiration = true;
            );

            services.AddCors();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddAuthentication(option =>
            
                option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            ).AddJwtBearer(options =>
            
                options.SaveToken = true;
                options.RequireHttpsMetadata = true;
                options.TokenValidationParameters = new TokenValidationParameters()
                
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidAudience = Configuration["Jwt:Site"],
                    ValidIssuer = Configuration["Jwt:Site"],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SigningKey"]))
                ;
            );

        

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        
            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            
            else
            
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseAuthentication();

            app.UseMvc(routes =>
            
                routes.MapRoute(
                    name: "default",
                    template: "Controller=Startup/action=Login/id?");
            );
        
    

appsettings.json:


  "ConnectionStrings": 
    "DefaultConnection": " Data Source=Server; Database = db;Trusted_Connection=True;MultipleActiveResultSets=true"
  ,
  "Jwt": 
    "Site": "www.signinkey.com",
    "SigningKey": "ConstantSigningKey",
    "ExpiryInMinutes": "30"
  ,
  "Logging": 
    "LogLevel": 
      "Default": "Warning"
    
  ,
  "AllowedHosts": "*"

API 控制器:

namespace Project.Controllers

    [Route("api/[controller]/[action]")]
    public class AuthController : BaseController
    
        protected IConfiguration _configuration;

        public AuthController(UserManager<IdentityUser> userManager, IConfiguration configuration)
        
            _userManager = userManager;
            _configuration = configuration;
        

        public string GenerateToken(int size = 32)
        
            var randomNumber = new byte[size];
            using (var rng = RandomNumberGenerator.Create())
            
                rng.GetBytes(randomNumber);
                return Convert.ToBase64String(randomNumber);
            
        

        [HttpGet("")]
        [Route("modelList")]
        [Authorize]
        public IEnumerable<ModelList> SupervisorList(string username)
        
             return db.modelList.Select(x => x).ToList();
        

        [Route("register")]
        [HttpPost]
        public async Task<ActionResult> Register([FromBody] InputModel reg)
        
            var user = new IdentityUser  UserName = reg.Email, Email = reg.Email, SecurityStamp = Guid.NewGuid().ToString() ;
            var result = await _userManager.CreateAsync(user, reg.Password);
            if (result.Succeeded)
            
                await _userManager.AddToRoleAsync(user, "Admin");
            
            return Ok(new  Username = user.UserName );

        

        [Route("login")]
        [HttpPost]
        public async Task<ActionResult> Login([FromBody] InputModel login)
        
            var user = await _userManager.FindByNameAsync(login.Email);
            if (user != null && await _userManager.CheckPasswordAsync(user, login.Password))
            

                var claim = new[]
                
                    new Claim(JwtRegisteredClaimNames.Sub, user.UserName)
                ;
                var signinKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SigningKey"]));

                int expiryInMinutes = Convert.ToInt32(_configuration["Jwt:ExpiryInMinutes"]);

                var token = new JwtSecurityToken(
                    issuer: _configuration["Jwt:Site"],
                    audience: _configuration["Jwt:Site"],
                    expires: DateTime.UtcNow.AddMinutes(expiryInMinutes),
                    signingCredentials: new SigningCredentials(signinKey, SecurityAlgorithms.HmacSha256)
                    );


                return Ok(
                    new
                    
                        token = new JwtSecurityTokenHandler().WriteToken(token),
                        expiration = token.ValidTo
                    );


            
            return Unauthorized();
        
    

由于在启动类中启用了 JWT Token 认证;当我尝试访问非 api 控制器操作时,我也收到了 401 未经授权的代码。

我正在尝试的是:

    将 API 控制器添加到现有的 .net core mvc Web 应用程序。

    仅对 API 方法使用 JWT 令牌身份验证,而不是 Web 应用程序方法。

    以上可能吗?这是一个好习惯吗?如何实现?

需要方向。谢谢:)

【问题讨论】:

【参考方案1】:

您可以在 .NET 中编写自己的授权属性。像 [CustomAuthorization] 而不是内置的属性器。当然是学习阶段。

【讨论】:

【参考方案2】:

详细文章

Using Multiple Authentication/Authorization Providers in ASP.NET Core

是的,您可以在这里执行几个步骤

    在 Startup.cs 中设置多个身份验证方案 按控制器使用方案 为 Web 应用程序指定策略并在 Web 应用程序控制器中使用该策略 [Authorize(Policy = "WebApp")]

    在 Web API 控制器中,只需使用 JWT 身份验证方案

    [授权(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

启动代码

        .AddCookie(options =>
        
            // You cookie auth setup 
        )
        .AddJwtBearer(options =>
        
          // Your JWt setup
        )

政策设置

services.AddAuthorization(options =>
        
            options.AddPolicy("WebApp",
                              policy => policy.Requirements.Add(new WebAppRequirement()));
        );

【讨论】:

以上是关于JWT 不记名令牌授权应用于 .NET Core 中的现有 MVC Web 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET Core 2.1 Web 客户端中存储不记名令牌的位置

JWT 不记名令牌不适用于 ASP.Net Core 3.1 + Identity Server 4

ASP.NET Core API 使用 JWT 不记名令牌进行身份验证

.Net Core 2.1 过期的 JWT 令牌响应 [发布与获取]

添加基于策略的授权会跳过 JWT 不记名令牌身份验证检查吗?

Asp.net core 2 - 不记名令牌出现 401 错误