Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Asp.net核心的SwiggerUI中的JWT支持?_C#_Asp.net Core_Jwt_Swagger Ui - Fatal编程技术网

C# Asp.net核心的SwiggerUI中的JWT支持?

C# Asp.net核心的SwiggerUI中的JWT支持?,c#,asp.net-core,jwt,swagger-ui,C#,Asp.net Core,Jwt,Swagger Ui,我编写了一个Asp.Net核心REST服务,并获得了一些基本的JWT支持。我如何让招摇过市测试页面发送承载令牌 使用Fiddler发送请求有点烦人。击败了拥有Swagger的全部意义。在ConfigureSwaggerDocument()扩展方法中,您可以向SwaggerDocumentOptions添加SecurityDefinitions。例如: options.SecurityDefinitions.Add("yourapi_oauth2", new OAuth2Scheme()

我编写了一个Asp.Net核心REST服务,并获得了一些基本的JWT支持。我如何让招摇过市测试页面发送承载令牌


使用Fiddler发送请求有点烦人。击败了拥有Swagger的全部意义。

在ConfigureSwaggerDocument()扩展方法中,您可以向SwaggerDocumentOptions添加SecurityDefinitions。例如:

options.SecurityDefinitions.Add("yourapi_oauth2", new OAuth2Scheme()
            {
                Description = "OAuth2 client credentials flow",
                Type = "oauth2",
                Flow = "clientcredentials",
                AuthorizationUrl = Configuration["OpenId:authority"],
                TokenUrl = Configuration["OpenId:authority"] + "/connect/token",
                Scopes = new Dictionary<string, string>() { { "yourapi", "your api resources"} }
            } );
            options.OperationFilter<ApplyOAuth2Security>();
            options.DocumentFilter<ApplyOAuth2Security>();
options.SecurityDefinitions.Add(“yourapi_oauth2”,新的OAuth2Scheme()
{
Description=“OAuth2客户端凭据流”,
Type=“oauth2”,
Flow=“clientcredentials”,
AuthorizationUrl=配置[“OpenId:authority”],
TokenUrl=Configuration[“OpenId:authority”]+“/connect/token”,
Scopes=newdictionary(){{“yourapi”,“yourapi资源”}
} );
选项。操作筛选器


请记住,您需要根据自己的需要完全调整IDocumentFiler和IOperationFilter的实现。

在ConfigureSwaggerDocument()扩展方法中,您可以向SwaggerDocumentOptions添加SecurityDefinitions。例如:

options.SecurityDefinitions.Add("yourapi_oauth2", new OAuth2Scheme()
            {
                Description = "OAuth2 client credentials flow",
                Type = "oauth2",
                Flow = "clientcredentials",
                AuthorizationUrl = Configuration["OpenId:authority"],
                TokenUrl = Configuration["OpenId:authority"] + "/connect/token",
                Scopes = new Dictionary<string, string>() { { "yourapi", "your api resources"} }
            } );
            options.OperationFilter<ApplyOAuth2Security>();
            options.DocumentFilter<ApplyOAuth2Security>();
options.SecurityDefinitions.Add(“yourapi_oauth2”,新的OAuth2Scheme()
{
Description=“OAuth2客户端凭据流”,
Type=“oauth2”,
Flow=“clientcredentials”,
AuthorizationUrl=配置[“OpenId:authority”],
TokenUrl=Configuration[“OpenId:authority”]+“/connect/token”,
Scopes=newdictionary(){{“yourapi”,“yourapi资源”}
} );
选项。操作筛选器


请记住,您需要完全根据自己的需要调整IDocumentFiler和IOperationFilter的实现。

使用.NET Core 1.0和Swagger UI的JWT承载令牌身份验证

第1步: 在WebAPI项目的根目录中创建选项文件夹,并在其中创建一个名为“jwtissueoptions.cs”的类。 第二步: 将以下代码粘贴到其中

using Microsoft.IdentityModel.Tokens;
using System;
using System.Threading.Tasks;
public class JwtIssuerOptions
{
    /// <summary>
    /// "iss" (Issuer) Claim
    /// </summary>
    /// <remarks>The "iss" (issuer) claim identifies the principal that issued the
    ///   JWT.  The processing of this claim is generally application specific.
    ///   The "iss" value is a case-sensitive string containing a StringOrURI
    ///   value.  Use of this claim is OPTIONAL.</remarks>
    public string Issuer { get; set; }

    /// <summary>
    /// "sub" (Subject) Claim
    /// </summary>
    /// <remarks> The "sub" (subject) claim identifies the principal that is the
    ///   subject of the JWT.  The claims in a JWT are normally statements
    ///   about the subject.  The subject value MUST either be scoped to be
    ///   locally unique in the context of the issuer or be globally unique.
    ///   The processing of this claim is generally application specific.  The
    ///   "sub" value is a case-sensitive string containing a StringOrURI
    ///   value.  Use of this claim is OPTIONAL.</remarks>
    public string Subject { get; set; }

    /// <summary>
    /// "aud" (Audience) Claim
    /// </summary>
    /// <remarks>The "aud" (audience) claim identifies the recipients that the JWT is
    ///   intended for.  Each principal intended to process the JWT MUST
    ///   identify itself with a value in the audience claim.  If the principal
    ///   processing the claim does not identify itself with a value in the
    ///   "aud" claim when this claim is present, then the JWT MUST be
    ///   rejected.  In the general case, the "aud" value is an array of case-
    ///   sensitive strings, each containing a StringOrURI value.  In the
    ///   special case when the JWT has one audience, the "aud" value MAY be a
    ///   single case-sensitive string containing a StringOrURI value.  The
    ///   interpretation of audience values is generally application specific.
    ///   Use of this claim is OPTIONAL.</remarks>
    public string Audience { get; set; }

    /// <summary>
    /// "nbf" (Not Before) Claim (default is UTC NOW)
    /// </summary>
    /// <remarks>The "nbf" (not before) claim identifies the time before which the JWT
    ///   MUST NOT be accepted for processing.  The processing of the "nbf"
    ///   claim requires that the current date/time MUST be after or equal to
    ///   the not-before date/time listed in the "nbf" claim.  Implementers MAY
    ///   provide for some small leeway, usually no more than a few minutes, to
    ///   account for clock skew.  Its value MUST be a number containing a
    ///   NumericDate value.  Use of this claim is OPTIONAL.</remarks>
    public DateTime NotBefore => DateTime.UtcNow;

    /// <summary>
    /// "iat" (Issued At) Claim (default is UTC NOW)
    /// </summary>
    /// <remarks>The "iat" (issued at) claim identifies the time at which the JWT was
    ///   issued.  This claim can be used to determine the age of the JWT.  Its
    ///   value MUST be a number containing a NumericDate value.  Use of this
    ///   claim is OPTIONAL.</remarks>
    public DateTime IssuedAt => DateTime.UtcNow;

    /// <summary>
    /// Set the timespan the token will be valid for (default is 5 min/300 seconds)
    /// </summary>
    public TimeSpan ValidFor { get; set; } = TimeSpan.FromMinutes(5);

    /// <summary>
    /// "exp" (Expiration Time) Claim (returns IssuedAt + ValidFor)
    /// </summary>
    /// <remarks>The "exp" (expiration time) claim identifies the expiration time on
    ///   or after which the JWT MUST NOT be accepted for processing.  The
    ///   processing of the "exp" claim requires that the current date/time
    ///   MUST be before the expiration date/time listed in the "exp" claim.
    ///   Implementers MAY provide for some small leeway, usually no more than
    ///   a few minutes, to account for clock skew.  Its value MUST be a number
    ///   containing a NumericDate value.  Use of this claim is OPTIONAL.</remarks>
    public DateTime Expiration => IssuedAt.Add(ValidFor);

    /// <summary>
    /// "jti" (JWT ID) Claim (default ID is a GUID)
    /// </summary>
    /// <remarks>The "jti" (JWT ID) claim provides a unique identifier for the JWT.
    ///   The identifier value MUST be assigned in a manner that ensures that
    ///   there is a negligible probability that the same value will be
    ///   accidentally assigned to a different data object; if the application
    ///   uses multiple issuers, collisions MUST be prevented among values
    ///   produced by different issuers as well.  The "jti" claim can be used
    ///   to prevent the JWT from being replayed.  The "jti" value is a case-
    ///   sensitive string.  Use of this claim is OPTIONAL.</remarks>
    public Func<Task<string>> JtiGenerator =>
      () => Task.FromResult(Guid.NewGuid().ToString());

    /// <summary>
    /// The signing key to use when generating tokens.
    /// </summary>
    public SigningCredentials SigningCredentials { get; set; }
}
使用Microsoft.IdentityModel.Tokens;
使用制度;
使用System.Threading.Tasks;
公共类JwtIssuerOptions
{
/// 
///“iss”(发行人)索赔
/// 
///“iss”(发行人)索赔确定了发行债券的委托人
///本权利要求的处理通常是特定于应用的。
///“iss”值是包含StringOrURI的区分大小写的字符串
///值。此声明的使用是可选的。
公共字符串颁发者{get;set;}
/// 
///“次级”(主题)索赔
/// 
///“sub”(subject)索赔确定了作为
///JWT的主题。JWT中的权利要求通常是声明
///关于主题。主题值的作用域必须为
///在发行人的上下文中是本地唯一的,或者是全球唯一的。
///此索赔的处理通常是特定于应用程序的
///“sub”值是包含StringOrURI的区分大小写的字符串
///值。此声明的使用是可选的。
公共字符串主题{get;set;}
/// 
///“澳元”(观众)索赔
/// 
///“aud”(受众)声明标识了JWT所属的接收者
///拟用于。拟处理JWT的每个委托人必须
///用受众声明中的值标识自己。如果主体
///处理声明时,不会使用
///“aud”索赔如果存在该索赔,则JWT必须
///拒绝。在一般情况下,“aud”值是大小写数组-
///敏感字符串,每个字符串都包含StringOrURI值
///特殊情况下,当JWT有一个受众时,“aud”值可能是
///包含StringOrURI值的单个区分大小写的字符串
///受众价值观的解释通常是特定于应用的。
///此声明的使用是可选的。
公共字符串访问群体{get;set;}
/// 
///“nbf”(非之前)索赔(默认值为UTC NOW)
/// 
///“nbf”(非之前)声明确定了JWT
///不得接受处理。“nbf”的处理
///索赔要求当前日期/时间必须晚于或等于
///不在“nbf”声明中列出的日期/时间之前。实现者可以
///提供一些小的回旋余地,通常不超过几分钟,以便
///时钟偏移的帐户。其值必须是包含
///NumericDate值。此声明的使用是可选的。
public DateTime NotBefore=>DateTime.UtcNow;
/// 
///“iat”(在发出时)索赔(默认值为UTC NOW)
/// 
///“iat”(于发布)索赔确定了JWT的发布时间
///此声明可用于确定JWT的年龄。其
///值必须是包含NumericDate值的数字。使用此
///索赔是可选的。
public DateTime IssuedAt=>DateTime.UtcNow;
/// 
///设置令牌有效的时间跨度(默认值为5分钟/300秒)
/// 
公共TimeSpan ValidFor{get;set;}=TimeSpan.FromMinutes(5);
/// 
///“exp”(到期时间)索赔(返回IssuedAt+ValidFor)
/// 
///“exp”(过期时间)声明标识上的过期时间
///或之后,不得接受JWT进行处理
///处理“exp”索赔要求当前日期/时间
///必须在“exp”索赔中列出的到期日期/时间之前。
///实施者可能会提供一些小的回旋余地,通常不超过
///几分钟,以说明时钟偏移。其值必须是一个数字
///包含NumericDate值。此声明的使用是可选的。
公共日期时间到期=>IssuedAt.Add(ValidFor);
///
using Swashbuckle.AspNetCore.Swagger;
using System;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using WebAPI.Options;

namespace WebAPI
{
    public class Startup
    {
         public static string ConnectionString { get; private set; }
         private const string SecretKey = "getthiskeyfromenvironment";
         private readonly SymmetricSecurityKey _signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));
         public Startup(IHostingEnvironment env)
         {
            var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build(); 

        ConnectionString = Configuration.GetSection("ConnectionStrings").GetSection("<Your DB Connection Name>").Value;
    }

    public static IConfigurationRoot Configuration { get; private set; }

    // This method gets called by the runtime. Use this method to add services to the container
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        // ********************
        // Setup CORS
        // ********************
        var corsBuilder = new CorsPolicyBuilder();
        corsBuilder.AllowAnyHeader();
        corsBuilder.AllowAnyMethod();
        corsBuilder.AllowAnyOrigin(); // For anyone access.
        //corsBuilder.WithOrigins("http://localhost:12345"); // for a specific url. Don't add a forward slash on the end!
        corsBuilder.AllowCredentials();

        services.AddCors(options =>
        {
            options.AddPolicy("<YourCorsPolicyName>", corsBuilder.Build());
        });

        var xmlPath = GetXmlCommentsPath();

        // Register the Swagger generator, defining one or more Swagger documents
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new Info { Title = "XYZ API", Version = "v1", Description = "This is a API for XYZ client applications.", });
            c.IncludeXmlComments(xmlPath);
            c.AddSecurityDefinition("Bearer", new ApiKeyScheme() { In = "header", Description = "Please paste JWT Token with Bearer + White Space + Token into field", Name = "Authorization", Type = "apiKey" });
        });

        // Add framework services.
        services.AddOptions();

        // Use policy auth.
        services.AddAuthorization(options =>
        {
            options.AddPolicy("AuthorizationPolicy",
                              policy => policy.RequireClaim("DeveloperBoss", "IAmBoss"));
        });

        // Get options from app settings
        var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));

        // Configure JwtIssuerOptions
        services.Configure<JwtIssuerOptions>(options =>
        {
            options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
            options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
            options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
        var tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],

            ValidateAudience = true,
            ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],

            ValidateIssuerSigningKey = true,
            IssuerSigningKey = _signingKey,

            RequireExpirationTime = true,
            ValidateLifetime = true,

            ClockSkew = TimeSpan.Zero
        };

        app.UseJwtBearerAuthentication(new JwtBearerOptions
        {
            AutomaticAuthenticate = true,
            AutomaticChallenge = true,
            TokenValidationParameters = tokenValidationParameters
        });

        //loggerFactory.AddLambdaLogger(Configuration.GetLambdaLoggerOptions());

        app.UseMvc();

        app.UseStaticFiles();

        // Shows UseCors with CorsPolicyBuilder.
        app.UseCors("<YourCorsPolicyName>");

        // Enable middleware to serve generated Swagger as a JSON endpoint.
        app.UseSwagger();

       // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
        app.UseSwaggerUi(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "XYZ API V1");
        });
    }

    private string GetXmlCommentsPath()
    {
        var app = PlatformServices.Default.Application;
        return System.IO.Path.Combine(app.ApplicationBasePath, "WebAPI.xml");
    }
}
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using Newtonsoft.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Security.Claims;
using System.IdentityModel.Tokens.Jwt;
using WebAPI.Options;
using System.Security.Principal;

namespace WebAPI.Controllers
{
    [EnableCors("<YourCorsPolicyName>")]
    [Route("[api/controller]")]
    public class JWTController : Controller
    {
         private readonly JwtIssuerOptions _jwtOptions;
         private readonly ILogger _logger;
         private readonly JsonSerializerSettings _serializerSettings;

         public JWTController(IOptions<JwtIssuerOptions> jwtOptions, ILoggerFactory loggerFactory)
    {
        _jwtOptions = jwtOptions.Value;
        ThrowIfInvalidOptions(_jwtOptions);
        _logger = loggerFactory.CreateLogger<JWTController>();

        _serializerSettings = new JsonSerializerSettings
        {
            Formatting = Formatting.Indented
        };
        _connectionString = Startup.ConnectionString;
    }

    [AllowAnonymous]
    [HttpPost]
    [Route("{username}/{password}")]
    public async Task<IActionResult> Get(string username, string password)
    {
        User user = GetUser(username, password);
        var identity = await GetClaimsIdentity(user);
        if (identity == null)
        {
            _logger.LogInformation($"Invalid username ({username}) or password ({password})");
            return BadRequest("Invalid credentials");
        }

        var claims = new[]
          {
            new Claim("UserID",user.UserId.ToString()),
            new Claim("UserName",user.UserName),
            new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
            new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
            new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
            identity.FindFirst("DeveloperBoss")
          };

        // Create the JWT security token and encode it.
        var jwt = new JwtSecurityToken(
            issuer: _jwtOptions.Issuer,
            audience: _jwtOptions.Audience,
            claims: claims,
            notBefore: _jwtOptions.NotBefore,
            expires: _jwtOptions.Expiration,
            signingCredentials: _jwtOptions.SigningCredentials);

        var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

        // Serialize and return the response
        var response = new
        {
            access_token = encodedJwt,
            expires_in = (int)_jwtOptions.ValidFor.TotalSeconds
        };

        var json = JsonConvert.SerializeObject(response, _serializerSettings);
        return new OkObjectResult(json);
    }

    /// <returns>Date converted to seconds since Unix epoch (Jan 1, 1970, midnight UTC).</returns>

    private static void ThrowIfInvalidOptions(JwtIssuerOptions options)
    {
        if (options == null) throw new ArgumentNullException(nameof(options));

        if (options.ValidFor <= TimeSpan.Zero)
        {
            throw new ArgumentException("Must be a non-zero TimeSpan.", nameof(JwtIssuerOptions.ValidFor));
        }

        if (options.SigningCredentials == null)
        {
            throw new ArgumentNullException(nameof(JwtIssuerOptions.SigningCredentials));
        }

        if (options.JtiGenerator == null)
        {
            throw new ArgumentNullException(nameof(JwtIssuerOptions.JtiGenerator));
        }
    }

    /// <returns>Date converted to seconds since Unix epoch (Jan 1, 1970, midnight UTC).</returns>
    private static long ToUnixEpochDate(DateTime date)
      => (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);

    /// <summary>
    /// IMAGINE BIG RED WARNING SIGNS HERE!
    /// You'd want to retrieve claims through your claims provider
    /// in whatever way suits you, the below is purely for demo purposes!
    /// </summary>
    private static Task<ClaimsIdentity> GetClaimsIdentity(User user)
    {
        if (user == null)
        {
            // Credentials are invalid, or account doesn't exist
            return Task.FromResult<ClaimsIdentity>(null);
        }
        if (user.UserId == 0)
        {
            return Task.FromResult(new ClaimsIdentity(new GenericIdentity(user.UserName, "Token"),
                new Claim[] { }));
        }
        return Task.FromResult(new ClaimsIdentity(new GenericIdentity(user.UserName, "Token"),
          new[]
          {
            new Claim("DeveloperBoss", "IAmBoss")
          }));
    }
}
namespace WebAPI.Controllers
{
    /// <summary>
    /// summary comment here
    /// </summary>
    /// <remarks>
    /// remark comment here
    /// </remarks>
    [EnableCors("<YourCorsPloicyName>")]
    [Authorize(Policy = "AuthorizationPolicy")]
    [Route("api/[controller]")]
    public class AbcController : Controller
    {
         //Your class code goes here...
    }
}