2016-09-08 14 views
0

私はAsp.NetコアRESTサービスを書いて、基本的なJWTサポートを行っています。どのようにしてBEARERトークンを送信するようにスワッガーテストページを取得しますか?Asp.netコアのSwaggerUIでのJWTサポート?

リクエストを送信するためにフィドラーを使用する必要があるのは厄介な種類です。スガッガーを持つことの全ポイントを破る。

答えて

5

ConfigureSwaggerDocument()拡張メソッドでは、SecurityDefinitionsをSwaggerDocumentOptionsに追加できます。例:

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>(); 

ApplyOAuth2Securityは、許可のあなたの方法を使用するように闊歩を設定伝えるために使用されIDocumentFilterとIOperationFilterを実装するカスタムクラスです。例は続けた:あなたは完全にあなた自身のニーズにIDocumentFilerとIOperationFilterの実装を調整する必要があることに注意してください

Visual of authorization input

public class ApplyOAuth2Security : IDocumentFilter, IOperationFilter 
{ 
    public void Apply(Operation operation, OperationFilterContext context) 
    { 
     var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors; 
     var isAuthorized = filterPipeline.Select(f => f.Filter).Any(f => f is AuthorizeFilter); 
     var authorizationRequired = context.ApiDescription.GetControllerAttributes().Any(a => a is AuthorizeAttribute); 
     if (!authorizationRequired) authorizationRequired = context.ApiDescription.GetActionAttributes().Any(a => a is AuthorizeAttribute); 

     if (isAuthorized && authorizationRequired) 
     { 
      operation.Parameters.Add(new NonBodyParameter() 
      { 
       Name = "Authorization", 
       In = "header", 
       Description = "JWT security token obtained from Identity Server.", 
       Required = true, 
       Type = "string" 
      }); 
     } 
    } 

    public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context) 
    { 
     IList<IDictionary<string, IEnumerable<string>>> security = swaggerDoc.SecurityDefinitions.Select(securityDefinition => new Dictionary<string, IEnumerable<string>> 
     { 
      {securityDefinition.Key, new string[] {"yourapi"}} 
     }).Cast<IDictionary<string, IEnumerable<string>>>().ToList(); 


     swaggerDoc.Security = security; 
    } 
} 

は次のように闊歩-UIに見えます。

+0

おかげでダニーをお楽しみください、テキストボックスがポップアップし、私はシオマネキでチェックし、その送信を許可:ABC(私は入れテキストボックスにはabc)。必要な "BEARER"の前に追加する方法はありますか? – SledgeHammer

+0

NonBodyParameterには、デフォルト値を設定できるDefaultプロパティがあります(例:Default = "BEARER") –

+0

はい、ユーザーはそれを削除することができますので、 "BEARER"を自動的にシーンの背後にあるテキストボックスのテキストが可能ですか?私は、実際のテキストボックスを隠して新しいものを作成し、隠された本物のものをバックグラウンドで同期させるいくつかのソリューションを見てきましたが、古いソリューションのための解決策としてはまだまだ機能しませんでした。 – SledgeHammer

0

.NETのコア1.0とJWTベアラートークン認証と闊歩UI

ステップ1: WebAPIのプロジェクトのルートにオプションのフォルダを作成し、名前を「JwtIssuerOptions.cs」とそれにクラスを作成します。 ステップ2:それに ペースト次のコード...

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; } 
} 

ステップ3:Startup.csファイルに ペースト次のコード...

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"); 
    } 
} 

}

手順4: コントローラでJWTController.csを作成するフォルダ。そして、次のようにコードを変更:

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") 
      })); 
    } 
} 

}

ステップ5: を使用すると、次のように許可するすべてのコントローラーを飾る:

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... 
    } 
} 

ステップ6: を結論:今あなたが直接apiを実行すると、あなたに401-Unauthorizeが与えられます。したがって、JWTController APIを最初に呼び出してそこからトークンを生成し、そのトークンをHeaderのAuhtorizationパラメータのBearer + WhiteSpace + Tokenという単語で渡す必要があります。そして実行し、それはあなたが望ましい結果を得られます...

はJWT ...

関連する問題