나는 DotNet 코어 2.0에서 JWT를 작동시키기 위해 꽤 모험을 해왔습니다 (현재 최종 릴리스에 도달했습니다). 거기입니다 톤 문서는 있지만, 모든 샘플 코드는 사용되지 않는 API를 사용하고, 긍정적으로 그것을 구현해야하는데 방법을 정확하게 파악하는 현기증의 핵심에 신선한 오는 것 같다. 나는 Jose를 사용해 보았지만 앱. UseJwtBearerAuthentication은 더 이상 사용되지 않으며 다음에 수행 할 작업에 대한 문서가 없습니다.
누구든지 인증 헤더에서 JWT를 구문 분석하고 HS256으로 인코딩 된 JWT 토큰에 대한 요청을 인증 할 수있는 dotnet core 2.0을 사용하는 오픈 소스 프로젝트가 있습니까?
아래 클래스는 예외를 던지지 않지만 승인 된 요청이 없으며 승인되지 않은 이유 를 알 수 없습니다 . 응답은 비어있는 401이므로 예외가 없었지만 비밀이 일치하지 않는다는 것을 나타냅니다.
한 가지 이상한 점은 내 토큰이 HS256 알고리즘으로 암호화되어 있지만 어디서나 해당 알고리즘을 사용하도록 지시하는 표시기가 없다는 것입니다.
지금까지 내가 가진 수업은 다음과 같습니다.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json.Linq;
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace Site.Authorization
{
public static class SiteAuthorizationExtensions
{
public static IServiceCollection AddSiteAuthorization(this IServiceCollection services)
{
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("SECRET_KEY"));
var tokenValidationParameters = new TokenValidationParameters
{
// The signing key must match!
ValidateIssuerSigningKey = true,
ValidateAudience = false,
ValidateIssuer = false,
IssuerSigningKeys = new List<SecurityKey>{ signingKey },
// Validate the token expiry
ValidateLifetime = true,
};
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
o.IncludeErrorDetails = true;
o.TokenValidationParameters = tokenValidationParameters;
o.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = c =>
{
c.NoResult();
c.Response.StatusCode = 401;
c.Response.ContentType = "text/plain";
return c.Response.WriteAsync(c.Exception.ToString());
}
};
});
return services;
}
}
}
답변
다음은 컨트롤러를 사용하여 완전히 작동하는 최소 샘플입니다. Postman 또는 JavaScript 호출을 사용하여 확인할 수 있기를 바랍니다.
-
appsettings.json, appsettings.Development.json. 섹션을 추가하십시오. Key는 다소 길어야하며 Issuer는 서비스의 주소입니다.
... ,"Tokens": { "Key": "Rather_very_long_key", "Issuer": "http://localhost:56268/" } ...
!!! 실제 프로젝트에서는 appsettings.json 파일에 Key를 보관하지 마십시오. 환경 변수에 보관되어야하며 다음과 같이 처리해야합니다.
Environment.GetEnvironmentVariable("JWT_KEY");
업데이트 : .net 코어 설정이 어떻게 작동하는지 확인하면 환경에서 정확히 가져올 필요가 없습니다. 설정을 사용할 수 있습니다. 그러나 대신이 변수를 프로덕션 환경 변수에 쓸 수 있습니다. 그러면 코드가 구성 대신 환경 변수를 선호합니다.
-
AuthRequest.cs : 로그인 및 비밀번호 전달을위한 값 유지 :
public class AuthRequest { public string UserName { get; set; } public string Password { get; set; } }
-
app.UseMvc () 전에 Configure () 메서드의 Startup.cs :
app.UseAuthentication();
-
ConfigureServices ()의 Startup.cs :
services.AddAuthentication() .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"])) }; });
-
컨트롤러 추가 :
[Route("api/[controller]")] public class TokenController : Controller { private readonly IConfiguration _config; private readonly IUserManager _userManager; public TokenController(IConfiguration configuration, IUserManager userManager) { _config = configuration; _userManager = userManager; } [HttpPost("")] [AllowAnonymous] public IActionResult Login([FromBody] AuthRequest authUserRequest) { var user = _userManager.FindByEmail(model.UserName); if (user != null) { var checkPwd = _signInManager.CheckPasswordSignIn(user, model.authUserRequest); if (checkPwd) { var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, user.UserName), new Claim(JwtRegisteredClaimNames.Jti, user.Id.ToString()), }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Tokens:Key"])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken(_config["Tokens:Issuer"], _config["Tokens:Issuer"], claims, expires: DateTime.Now.AddMinutes(30), signingCredentials: creds); return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) }); } } return BadRequest("Could not create token"); }}
그게 다야! 건배!
업데이트 : 사람들은 현재 사용자를 얻는 방법을 묻습니다. 할 것:
-
ConfigureServices ()의 Startup.cs에서 추가
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
-
컨트롤러에서 생성자에 추가 :
private readonly int _currentUser; public MyController(IHttpContextAccessor httpContextAccessor) { _currentUser = httpContextAccessor.CurrentUser(); }
-
확장을 어딘가에 추가하고 컨트롤러에서 사용합니다 (… 사용).
public static class IHttpContextAccessorExtension { public static int CurrentUser(this IHttpContextAccessor httpContextAccessor) { var stringId = httpContextAccessor?.HttpContext?.User?.FindFirst(JwtRegisteredClaimNames.Jti)?.Value; int.TryParse(stringId ?? "0", out int userId); return userId; } }
답변
내 tokenValidationParameters
작품은 다음과 같습니다.
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = GetSignInKey(),
ValidateIssuer = true,
ValidIssuer = GetIssuer(),
ValidateAudience = true,
ValidAudience = GetAudience(),
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
과
static private SymmetricSecurityKey GetSignInKey()
{
const string secretKey = "very_long_very_secret_secret";
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
return signingKey;
}
static private string GetIssuer()
{
return "issuer";
}
static private string GetAudience()
{
return "audience";
}
또한 다음과 같이 options.RequireHttpsMetadata = false를 추가하십시오.
.AddJwtBearer(options =>
{
options.TokenValidationParameters =tokenValidationParameters
options.RequireHttpsMetadata = false;
});
수정 :
전화하는 것을 잊지 마세요
app.UseAuthentication();
Startup.cs에서 -> 구성 방법 전에 app.UseMvc ();
답변
Web Api 데모를 통한 Asp.net Core 2.0 JWT Bearer 토큰 인증 구현
” Microsoft.AspNetCore.Authentication.JwtBearer ” 패키지 추가
Startup.cs ConfigureServices ()
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = "me",
ValidAudience = "you",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("rlyaKithdrYVl6Z80ODU350md")) //Secret
};
});
Startup.cs Configure ()
// ===== Use Authentication ======
app.UseAuthentication();
User.cs // 예를 들어 모델 클래스입니다. 그것은 무엇이든 될 수 있습니다.
public class User
{
public Int32 Id { get; set; }
public string Username { get; set; }
public string Country { get; set; }
public string Password { get; set; }
}
UserContext.cs // 그냥 컨텍스트 클래스입니다. 그것은 무엇이든 될 수 있습니다.
public class UserContext : DbContext
{
public UserContext(DbContextOptions<UserContext> options) : base(options)
{
this.Database.EnsureCreated();
}
public DbSet<User> Users { get; set; }
}
AccountController.cs
[Route("[controller]")]
public class AccountController : Controller
{
private readonly UserContext _context;
public AccountController(UserContext context)
{
_context = context;
}
[AllowAnonymous]
[Route("api/token")]
[HttpPost]
public async Task<IActionResult> Token([FromBody]User user)
{
if (!ModelState.IsValid) return BadRequest("Token failed to generate");
var userIdentified = _context.Users.FirstOrDefault(u => u.Username == user.Username);
if (userIdentified == null)
{
return Unauthorized();
}
user = userIdentified;
//Add Claims
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.UniqueName, "data"),
new Claim(JwtRegisteredClaimNames.Sub, "data"),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("rlyaKithdrYVl6Z80ODU350md")); //Secret
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken("me",
"you",
claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
return Ok(new
{
access_token = new JwtSecurityTokenHandler().WriteToken(token),
expires_in = DateTime.Now.AddMinutes(30),
token_type = "bearer"
});
}
}
UserController.cs
[Authorize]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
private readonly UserContext _context;
public UserController(UserContext context)
{
_context = context;
if(_context.Users.Count() == 0 )
{
_context.Users.Add(new User { Id = 0, Username = "Abdul Hameed Abdul Sattar", Country = "Indian", Password = "123456" });
_context.SaveChanges();
}
}
[HttpGet("[action]")]
public IEnumerable<User> GetList()
{
return _context.Users.ToList();
}
[HttpGet("[action]/{id}", Name = "GetUser")]
public IActionResult GetById(long id)
{
var user = _context.Users.FirstOrDefault(u => u.Id == id);
if(user == null)
{
return NotFound();
}
return new ObjectResult(user);
}
[HttpPost("[action]")]
public IActionResult Create([FromBody] User user)
{
if(user == null)
{
return BadRequest();
}
_context.Users.Add(user);
_context.SaveChanges();
return CreatedAtRoute("GetUser", new { id = user.Id }, user);
}
[HttpPut("[action]/{id}")]
public IActionResult Update(long id, [FromBody] User user)
{
if (user == null)
{
return BadRequest();
}
var userIdentified = _context.Users.FirstOrDefault(u => u.Id == id);
if (userIdentified == null)
{
return NotFound();
}
userIdentified.Country = user.Country;
userIdentified.Username = user.Username;
_context.Users.Update(userIdentified);
_context.SaveChanges();
return new NoContentResult();
}
[HttpDelete("[action]/{id}")]
public IActionResult Delete(long id)
{
var user = _context.Users.FirstOrDefault(u => u.Id == id);
if (user == null)
{
return NotFound();
}
_context.Users.Remove(user);
_context.SaveChanges();
return new NoContentResult();
}
}
다른 웹 서비스의 헤더에 TokenType 및 AccessToken을 전달합니다.
행운을 빌어 요! 나는 단지 초보자입니다. asp.net 코어 학습을 시작하는 데 1 주일 밖에 걸리지 않았습니다.
답변
여기에 해결책이 있습니다.
startup.cs에서 먼저 서비스로 구성하십시오.
services.AddAuthentication().AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = "somethong",
ValidAudience = "something",
:
};
});
둘째, 구성에서이 서비스를 호출하십시오.
app.UseAuthentication();
이제 속성을 추가하여 컨트롤러에서 사용할 수 있습니다.
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet]
public IActionResult GetUserInfo()
{
답변
.Net Core 2.0 API에 대한 구현은 다음과 같습니다.
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
// Add framework services
services.AddMvc(
config =>
{
// This enables the AuthorizeFilter on all endpoints
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
}
).AddJsonOptions(opt =>
{
opt.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
});
services.AddLogging();
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Audience = Configuration["AzureAD:Audience"];
options.Authority = Configuration["AzureAD:AADInstance"] + Configuration["AzureAD:TenantId"];
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseAuthentication(); // THIS METHOD MUST COME BEFORE UseMvc...() !!
app.UseMvcWithDefaultRoute();
}
appsettings.json :
{
"AzureAD": {
"AADInstance": "https://login.microsoftonline.com/",
"Audience": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"Domain": "mydomain.com",
"TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
},
...
}
위의 코드는 모든 컨트롤러에서 인증을 활성화합니다. 익명 액세스를 허용하려면 전체 컨트롤러를 장식 할 수 있습니다.
[Route("api/[controller]")]
[AllowAnonymous]
public class AnonymousController : Controller
{
...
}
또는 단일 엔드 포인트를 허용하도록 메소드를 장식하십시오.
[AllowAnonymous]
[HttpPost("anonymousmethod")]
public async Task<IActionResult> MyAnonymousMethod()
{
...
}
메모:
-
AD 인증에 대한 첫 번째 시도입니다. 잘못된 것이 있으면 알려주세요!
-
Audience
클라이언트가 요청한 리소스 ID 와 일치해야합니다 . 우리의 경우 클라이언트 (Angular 웹앱)는 Azure AD에 별도로 등록되었으며 API에서 Audience로 등록한 클라이언트 ID를 사용했습니다. -
ClientId
API에 대한 앱 등록의 응용 프로그램 ID 인 Azure Portal에서 응용 프로그램 ID 라고 합니다 (왜 ??). -
TenantId
라고 디렉토리 ID를 아래에있는 푸른 포털 (왜?)에 푸른 액티브 디렉토리> 속성 -
API를 Azure 호스팅 웹앱으로 배포하는 경우 애플리케이션 설정을 설정해야합니다.
예. AzureAD : 청중 / xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
답변
@alerya의 우수한 답변을 업데이트하기 위해 도우미 클래스를 다음과 같이 수정해야했습니다.
public static class IHttpContextAccessorExtension
{
public static string CurrentUser(this IHttpContextAccessor httpContextAccessor)
{
var userId = httpContextAccessor?.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
return userId;
}
}
그런 다음 서비스 계층에서 userId를 얻을 수 있습니다. 나는 그것이 컨트롤러에서 쉽다는 것을 알고 있지만, 더 아래로 도전합니다.