将 JWT 身份验证实现从 .net core 2 转移到 asp.net web api 2 [英] transfer JWT Authentication implementation from .net core 2 to asp.net web api 2

查看:24
本文介绍了将 JWT 身份验证实现从 .net core 2 转移到 asp.net web api 2的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 .net core 2 应用程序中实现了 JWT 身份验证,它工作正常.

i have implementation of JWT Authentication in .net core 2 application, it work fine.

我想在 asp.net web api 2 应用程序中使用此实现和结构,但出现错误

i want to use this implementation and structure in asp.net web api 2 application but i get error

我的结构:

JwtTokenBuilder 类:

using System;
using System.Collections.Generic;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Linq;

namespace solution.Authentication
{
  public sealed class JwtTokenBuilder
  {
    private SecurityKey securityKey = null;
    private string subject = "";
    private string issuer = "";
    private string audience = "";
    private Dictionary<string, string> claims = new Dictionary<string, string>();
    private DateTime expireTime = DateTime.UtcNow.AddMinutes(30);

    public JwtTokenBuilder AddSecurityKey(SecurityKey securityKey)
    {
      this.securityKey = securityKey;
      return this;
    }

    public JwtTokenBuilder AddSubject(string subject)
    {
      this.subject = subject;
      return this;
    }

    public JwtTokenBuilder AddIssuer(string issuer)
    {
      this.issuer = issuer;
      return this;
    }

    public JwtTokenBuilder AddAudience(string audience)
    {
      this.audience = audience;
      return this;
    }

    public JwtTokenBuilder AddClaim(string type, string value)
    {
      this.claims.Add(type, value);
      return this;
    }

    public JwtTokenBuilder AddClaims(Dictionary<string, string> claims)
    {
      this.claims.Union(claims);
      return this;
    }

    public JwtTokenBuilder AddExpiry(DateTime expireTime)
    {
      this.expireTime = expireTime;
      return this;
    }

    public JwtToken Build()
    {
      EnsureArguments();

      var claims = new List<Claim>
            {
              new Claim(JwtRegisteredClaimNames.Sub, this.subject),
              new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
            }
      .Union(this.claims.Select(item => new Claim(item.Key, item.Value)));

      var token = new JwtSecurityToken(
                        issuer: this.issuer,
                        audience: this.audience,
                        claims: claims,
                        expires: this.expireTime,
                        signingCredentials: new SigningCredentials(
                                                  this.securityKey,
                                                  SecurityAlgorithms.HmacSha256));

      return new JwtToken(token);
    }

    #region " private "

    private void EnsureArguments()
    {
      if (this.securityKey == null)
        throw new ArgumentNullException("Security Key");

      if (string.IsNullOrEmpty(this.subject))
        throw new ArgumentNullException("Subject");

      if (string.IsNullOrEmpty(this.issuer))
        throw new ArgumentNullException("Issuer");

      if (string.IsNullOrEmpty(this.audience))
        throw new ArgumentNullException("Audience");
    }

    #endregion
  }
}

令牌对象:

using System;
using System.IdentityModel.Tokens.Jwt;

namespace solution.Authentication
{
  public sealed class JwtToken
  {
    private JwtSecurityToken token;

    internal JwtToken(JwtSecurityToken token)
    {
      this.token = token;
    }

    public DateTime ValidTo => token.ValidTo;
    public string access_token => new JwtSecurityTokenHandler().WriteToken(this.token);
  }
}

安全密钥类:

using Microsoft.IdentityModel.Tokens;
using System.Text;

namespace solution.Authentication
{
  public static class JwtSecurityKey
  {
    public static SymmetricSecurityKey Create(string secret)
    {
      return new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secret));
    }
  }
}

我的令牌控制器方法 generate 并返回 token :

my token controller methode for generate and return token :

private JwtToken getToken(User user)
{
  DateTime startTime = DateTime.Now;
  DateTime expireTime = DateTime.Now.AddMinutes(60);

  var token = new JwtTokenBuilder()
                 .AddSecurityKey(JwtSecurityKey.Create("SecurityKey"))
                 .AddSubject("Subject")
                 .AddIssuer("Issuer")
                 .AddAudience("Audience")
                 .AddClaim("Username", user.UserName)
                 .AddExpiry(expireTime)
                 .Build();

  return token;
}

在 .net core 2 应用程序中,我使用 OWIN 启动类来验证我的 token 用于所有具有 Authorize 属性.

in .net core 2 application i use OWIN Startup class to validate my token for all controllers which have Authorize attribute.

控制器示例:

namespace solution.Controllers
{
  public class ExampleController : ApiController
  {
    [HttpPost]
    [Route("api/Example")]
    [Authorize(Policy = "Session")]
    public void Run()
    {
       // do something;
    }
  }  
}

用于验证 JWT 令牌的我的 owin 启动类:

my owin startup class for validating JWT token :

using System;
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Threading.Tasks;

namespace solution
{
  public class Startup
  {
    public void ConfigureServices(IServiceCollection services)
    {
      services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
               .AddJwtBearer(options =>
               {
                 options.TokenValidationParameters = new TokenValidationParameters
                 {
                   ValidateIssuer = true,
                   ValidateAudience = true,
                   ValidateLifetime = true,
                   ValidateIssuerSigningKey = true,

                   ValidIssuer = "Issuer",
                   ValidAudience = "Audience",
                   IssuerSigningKey = JwtSecurityKey.Create("SecurityKey")



                 };

                 options.Events = new JwtBearerEvents
                 {
                   OnAuthenticationFailed = context =>
                   {
                     return Task.CompletedTask;
                   },
                   OnTokenValidated = context =>
                   {
                     return Task.CompletedTask;
                   }
                 };
               });

      services.AddAuthorization(options =>
      {
        options.AddPolicy("Session", policy => policy.RequireClaim("SessionId"));
      });

      services.AddSignalR();
      services.AddCors(options =>
      {
        options.AddPolicy("CorsPolicy",
            builder => builder
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());
      });
      services.AddMvc();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
      loggerFactory.AddConsole();

      if (env.IsDevelopment())
      {
        app.UseDeveloperExceptionPage();
      }

      app.Use(async (context, next) =>
      {
        await next();
        if (context.Response.StatusCode == 404 &&
            !Path.HasExtension(context.Request.Path.Value) &&
            !context.Request.Path.Value.StartsWith("/api/", StringComparison.OrdinalIgnoreCase))
        {
          context.Request.Path = "/index.html";
          await next();
        }
      });

      app.UseDeveloperExceptionPage();
      app.UseAuthentication();
      app.UseMvcWithDefaultRoute();
      app.UseDefaultFiles();
      app.UseStaticFiles();
      app.UseCors(policyName: "CorsPolicy");
      app.UseSignalR(routes =>
      {
      });
    }
  }
}

我想在 asp.net web api 中使用这种结构,只改变 owin 类,可以吗?请帮助我进行任何更改

i want to use this structure in asp.net web api only change owin class, it's possible? please help me for any change

推荐答案

将我的实现从 .net core 2 转移到 asp.net web api 2

structure change for transfer my implementation from .net core 2 to asp.net web api 2

我使用 System.IdentityModel.Tokens.Jwt 命名空间来生成和验证 JWT 令牌.

i use System.IdentityModel.Tokens.Jwt namespace for generate and validate JWT token.

.net core 2 兼容 System.IdentityModel.Tokens.Jwt version="5.1.4" 但 asp.net web api 2 兼容 System.IdentityModel.Tokens.Jwt 版本="4.0.2"

.net core 2 compatible with System.IdentityModel.Tokens.Jwt version="5.1.4" but asp.net web api 2 compatible with System.IdentityModel.Tokens.Jwt version="4.0.2"

包版本中的相同更改对代码进行了更改,我使用 System.IdentityModel.Tokens 命名空间而不是 Microsoft.IdentityModel.Tokens 因为更改了软件包版本.

The same change in the package version made changes to the code, also the part of code i use the System.IdentityModel.Tokens namespace instead of Microsoft.IdentityModel.Tokens because of changing package versions.

代码更改:

JwtTokenBuilder 类:

在这个类中改变SigningCredentials参数设置

in this class change SigningCredentials parameter setting

  var token = new JwtSecurityToken(
                    issuer: this.issuer,
                    audience: this.audience,
                    claims: claims,
                    expires: this.expireTime,
                    signingCredentials: new System.IdentityModel.Tokens.SigningCredentials(
                                              this.securityKey,
                                              Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256Signature
                                            , Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256Signature));

安全密钥类:

更改安全密钥生成方式

using System.IdentityModel.Tokens;
using System.Text;

namespace solution.Authentication
{
  public static class JwtSecurityKey
  {
    public static SymmetricSecurityKey Create(string secret)
    {
      return new InMemorySymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
    }
  }
}

控制器属性:

namespace solution.Controllers
{
  public class ExampleController : ApiController
  {
    [HttpPost]
    [Route("api/Example")]
    [System.Web.Http.Authorize]
    public void Run()
    {
       // do something;
    }
  }  
}

我的主要更改是在 Startup OWIN 类中并将 Microsoft.Owin.Security.Jwt 包版本从3.1.0"更改为3.0.0"以进行验证传入请求的 JWT 令牌.

My main change was in Startup OWIN class and change Microsoft.Owin.Security.Jwt package version from "3.1.0" to "3.0.0" for validate JWT token for incoming requests.

实现:

using Microsoft.Owin;
using Owin;
using System.Web.Http;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Jwt;

[assembly: OwinStartup(typeof(solution.Startup))]

namespace solution
{
  public class Startup
  {
    public void Configuration(IAppBuilder app)
    {
      app.MapSignalR();
      HttpConfiguration config = new HttpConfiguration();
      config.MapHttpAttributeRoutes();
      ConfigureOAuth(app);
      app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
      app.UseWebApi(config);
    }
    public void ConfigureOAuth(IAppBuilder app)
    {
      var issuer = "issuer";
      var audience = "audience";
      var secret = JwtSecurityKey.Create("SecurityKey").GetSymmetricKey();

      // Api controllers with an [Authorize] attribute will be validated with JWT
      var option =
          new JwtBearerAuthenticationOptions
          {
            AuthenticationMode = AuthenticationMode.Active,
            AllowedAudiences = new[] { audience },
            IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
              {
                        new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
              }
          };
      app.UseJwtBearerAuthentication(
            option
        );
    }
  }
}

这篇关于将 JWT 身份验证实现从 .net core 2 转移到 asp.net web api 2的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆