ASP.NET Core 1.0 Web API의 간단한 JWT 인증
ASP.NET Core (일명 ASP.NET 5)에서 인증을 위해 JWT를 사용하는 Web API 서버를 설정하는 가장 간단한 방법을 찾고 있습니다. 이 프로젝트 ( blog post / github )는 내가 찾고있는 것을 정확히 수행하지만 ASP.NET 4를 사용합니다.
나는 단지 다음을 할 수 있기를 원합니다.
JWT 토큰을 생성하고 헤더에 반환 할 수있는 로그인 경로를 설정합니다. 사용자 이름과 비밀번호가 유효한지 알려주는 기존 RESTful 서비스와 통합하고 있습니다. ASP.NET 4 프로젝트에서 https://github.com/stewartm83/Jwt-WebApi/blob/master/src/JwtWebApi/Controllers/AccountController.cs#L24- 경로를 사용하여 수행 할 수 있습니다. L54
승인이 필요한 경로에 대한 수신 요청을 가로 채고 헤더에 들어오는 JWT 토큰을 해독 및 검증하고 JWT 토큰 페이로드의 사용자 정보를 경로에 액세스 할 수 있도록합니다. 예 : https://github.com/stewartm83/Jwt-WebApi/blob/master/src/JwtWebApi/App_Start/AuthHandler.cs
ASP.NET Core에서 본 모든 예제는 매우 복잡하며 피하고 싶은 OAuth, IS, OpenIddict 및 EF의 일부 또는 전부에 의존합니다.
누구든지 ASP.NET Core에서이 작업을 수행하는 방법에 대한 예제를 알려줄 수 있습니까?
편집 : 대답 나는이 대답을 사용하여 끝났습니다 : https://stackoverflow.com/a/33217340/373655
참고 / 업데이트 :
아래 코드는 .NET Core 1.1 용입니다.
.NET Core 1은 매우 RTM이므로 .NET Core 1에서 2.0으로의 점프와 함께 인증이 변경되었습니다 (일명 변경 사항으로 [부분적으로?] 수정 됨).
이것이 벨로우즈 코드가 .NET Core 2.0에서 더 이상 작동하지 않는 이유입니다.
그러나 여전히 유용한 읽기가 될 것입니다.
2018 업데이트
한편, 내 github 테스트 저장소에서 ASP.NET Core 2.0 JWT-Cookie-Authentication의 작동 예제를 찾을 수 있습니다 . BouncyCastle과 함께 MS-RSA & MS-ECDSA 추상 클래스 구현 및 RSA & ECDSA 용 키 생성기가 포함되어 있습니다.
네크 로맨싱.
나는 JWT를 더 깊이 파고 들었다. 내 결과는 다음과 같습니다.
Microsoft.AspNetCore.Authentication.JwtBearer를 추가해야합니다.
그런 다음 설정할 수 있습니다
app.UseJwtBearerAuthentication(bearerOptions);
Startup.cs => 구성
bearerOptions는 사용자에 의해 정의됩니다. 예 :
var bearerOptions = new JwtBearerOptions()
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = tokenValidationParameters,
Events = new CustomBearerEvents()
};
// Optional
// bearerOptions.SecurityTokenValidators.Clear();
// bearerOptions.SecurityTokenValidators.Add(new MyTokenHandler());
여기서 CustomBearerEvents는 httpContext / Route에 토큰 데이터를 추가 할 수있는 곳입니다.
// https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/JwtBearerEvents.cs
public class CustomBearerEvents : Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents
{
/// <summary>
/// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed.
/// </summary>
public Func<AuthenticationFailedContext, Task> OnAuthenticationFailed { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked when a protocol message is first received.
/// </summary>
public Func<MessageReceivedContext, Task> OnMessageReceived { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked after the security token has passed validation and a ClaimsIdentity has been generated.
/// </summary>
public Func<TokenValidatedContext, Task> OnTokenValidated { get; set; } = context => Task.FromResult(0);
/// <summary>
/// Invoked before a challenge is sent back to the caller.
/// </summary>
public Func<JwtBearerChallengeContext, Task> OnChallenge { get; set; } = context => Task.FromResult(0);
Task IJwtBearerEvents.AuthenticationFailed(AuthenticationFailedContext context)
{
return OnAuthenticationFailed(context);
}
Task IJwtBearerEvents.Challenge(JwtBearerChallengeContext context)
{
return OnChallenge(context);
}
Task IJwtBearerEvents.MessageReceived(MessageReceivedContext context)
{
return OnMessageReceived(context);
}
Task IJwtBearerEvents.TokenValidated(TokenValidatedContext context)
{
return OnTokenValidated(context);
}
}
그리고 tokenValidationParameters는 사용자가 정의합니다.
var tokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
// The signing key must match!
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
// Validate the JWT Issuer (iss) claim
ValidateIssuer = true,
ValidIssuer = "ExampleIssuer",
// Validate the JWT Audience (aud) claim
ValidateAudience = true,
ValidAudience = "ExampleAudience",
// Validate the token expiry
ValidateLifetime = true,
// If you want to allow a certain amount of clock drift, set that here:
ClockSkew = TimeSpan.Zero,
};
그리고 MyTokenHandler는 토큰 유효성 검사를 사용자 정의하려는 경우 선택적으로 정의합니다.
// https://gist.github.com/pmhsfelix/4151369
public class MyTokenHandler : Microsoft.IdentityModel.Tokens.ISecurityTokenValidator
{
private int m_MaximumTokenByteSize;
public MyTokenHandler()
{ }
bool ISecurityTokenValidator.CanValidateToken
{
get
{
// throw new NotImplementedException();
return true;
}
}
int ISecurityTokenValidator.MaximumTokenSizeInBytes
{
get
{
return this.m_MaximumTokenByteSize;
}
set
{
this.m_MaximumTokenByteSize = value;
}
}
bool ISecurityTokenValidator.CanReadToken(string securityToken)
{
System.Console.WriteLine(securityToken);
return true;
}
ClaimsPrincipal ISecurityTokenValidator.ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
// validatedToken = new JwtSecurityToken(securityToken);
try
{
tokenHandler.ValidateToken(securityToken, validationParameters, out validatedToken);
validatedToken = new JwtSecurityToken("jwtEncodedString");
}
catch (Exception ex)
{
System.Console.WriteLine(ex.Message);
throw;
}
ClaimsPrincipal principal = null;
// SecurityToken validToken = null;
validatedToken = null;
System.Collections.Generic.List<System.Security.Claims.Claim> ls =
new System.Collections.Generic.List<System.Security.Claims.Claim>();
ls.Add(
new System.Security.Claims.Claim(
System.Security.Claims.ClaimTypes.Name, "IcanHazUsr_éèêëïàáâäåãæóòôöõõúùûüñçø_ÉÈÊËÏÀÁÂÄÅÃÆÓÒÔÖÕÕÚÙÛÜÑÇØ 你好,世界 Привет\tмир"
, System.Security.Claims.ClaimValueTypes.String
)
);
//
System.Security.Claims.ClaimsIdentity id = new System.Security.Claims.ClaimsIdentity("authenticationType");
id.AddClaims(ls);
principal = new System.Security.Claims.ClaimsPrincipal(id);
return principal;
throw new NotImplementedException();
}
}
까다로운 부분은 암호화 형식의 상호 운용성이 필요하기 때문에 rsaCryptoServiceProvider를 전달하지 않기 때문에 AsymmetricSecurityKey를 얻는 방법입니다.
창조는
// System.Security.Cryptography.X509Certificates.X509Certificate2 cert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(byte[] rawData);
System.Security.Cryptography.X509Certificates.X509Certificate2 cert2 =
DotNetUtilities.CreateX509Cert2("mycert");
Microsoft.IdentityModel.Tokens.SecurityKey secKey = new X509SecurityKey(cert2);
예 : DER 인증서의 BouncyCastle 사용 :
// http://stackoverflow.com/questions/36942094/how-can-i-generate-a-self-signed-cert-without-using-obsolete-bouncycastle-1-7-0
public static System.Security.Cryptography.X509Certificates.X509Certificate2 CreateX509Cert2(string certName)
{
var keypairgen = new Org.BouncyCastle.Crypto.Generators.RsaKeyPairGenerator();
keypairgen.Init(new Org.BouncyCastle.Crypto.KeyGenerationParameters(
new Org.BouncyCastle.Security.SecureRandom(
new Org.BouncyCastle.Crypto.Prng.CryptoApiRandomGenerator()
)
, 1024
)
);
Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keypair = keypairgen.GenerateKeyPair();
// --- Until here we generate a keypair
var random = new Org.BouncyCastle.Security.SecureRandom(
new Org.BouncyCastle.Crypto.Prng.CryptoApiRandomGenerator()
);
// SHA1WITHRSA
// SHA256WITHRSA
// SHA384WITHRSA
// SHA512WITHRSA
// SHA1WITHECDSA
// SHA224WITHECDSA
// SHA256WITHECDSA
// SHA384WITHECDSA
// SHA512WITHECDSA
Org.BouncyCastle.Crypto.ISignatureFactory signatureFactory =
new Org.BouncyCastle.Crypto.Operators.Asn1SignatureFactory("SHA512WITHRSA", keypair.Private, random)
;
var gen = new Org.BouncyCastle.X509.X509V3CertificateGenerator();
var CN = new Org.BouncyCastle.Asn1.X509.X509Name("CN=" + certName);
var SN = Org.BouncyCastle.Math.BigInteger.ProbablePrime(120, new Random());
gen.SetSerialNumber(SN);
gen.SetSubjectDN(CN);
gen.SetIssuerDN(CN);
gen.SetNotAfter(DateTime.Now.AddYears(1));
gen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
gen.SetPublicKey(keypair.Public);
// -- Are these necessary ?
// public static readonly DerObjectIdentifier AuthorityKeyIdentifier = new DerObjectIdentifier("2.5.29.35");
// OID value: 2.5.29.35
// OID description: id-ce-authorityKeyIdentifier
// This extension may be used either as a certificate or CRL extension.
// It identifies the public key to be used to verify the signature on this certificate or CRL.
// It enables distinct keys used by the same CA to be distinguished (e.g., as key updating occurs).
// http://stackoverflow.com/questions/14930381/generating-x509-certificate-using-bouncy-castle-java
gen.AddExtension(
Org.BouncyCastle.Asn1.X509.X509Extensions.AuthorityKeyIdentifier.Id,
false,
new Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier(
Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keypair.Public),
new Org.BouncyCastle.Asn1.X509.GeneralNames(new Org.BouncyCastle.Asn1.X509.GeneralName(CN)),
SN
));
// OID value: 1.3.6.1.5.5.7.3.1
// OID description: Indicates that a certificate can be used as an SSL server certificate.
gen.AddExtension(
Org.BouncyCastle.Asn1.X509.X509Extensions.ExtendedKeyUsage.Id,
false,
new Org.BouncyCastle.Asn1.X509.ExtendedKeyUsage(new ArrayList()
{
new Org.BouncyCastle.Asn1.DerObjectIdentifier("1.3.6.1.5.5.7.3.1")
}));
// -- End are these necessary ?
Org.BouncyCastle.X509.X509Certificate bouncyCert = gen.Generate(signatureFactory);
byte[] ba = bouncyCert.GetEncoded();
System.Security.Cryptography.X509Certificates.X509Certificate2 msCert = new System.Security.Cryptography.X509Certificates.X509Certificate2(ba);
return msCert;
}
이후에 JWT-Bearer를 포함하는 사용자 지정 쿠키 형식을 추가 할 수 있습니다.
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationScheme = "MyCookieMiddlewareInstance",
CookieName = "SecurityByObscurityDoesntWork",
ExpireTimeSpan = new System.TimeSpan(15, 0, 0),
LoginPath = new Microsoft.AspNetCore.Http.PathString("/Account/Unauthorized/"),
AccessDeniedPath = new Microsoft.AspNetCore.Http.PathString("/Account/Forbidden/"),
AutomaticAuthenticate = true,
AutomaticChallenge = true,
CookieSecure = Microsoft.AspNetCore.Http.CookieSecurePolicy.SameAsRequest,
CookieHttpOnly = false,
TicketDataFormat = new CustomJwtDataFormat("foo", tokenValidationParameters)
// DataProtectionProvider = null,
// DataProtectionProvider = new DataProtectionProvider(new System.IO.DirectoryInfo(@"c:\shared-auth-ticket-keys\"),
//delegate (DataProtectionConfiguration options)
//{
// var op = new Microsoft.AspNet.DataProtection.AuthenticatedEncryption.AuthenticatedEncryptionOptions();
// op.EncryptionAlgorithm = Microsoft.AspNet.DataProtection.AuthenticatedEncryption.EncryptionAlgorithm.AES_256_GCM:
// options.UseCryptographicAlgorithms(op);
//}
//),
});
CustomJwtDataFormat은
public class CustomJwtDataFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly string algorithm;
private readonly TokenValidationParameters validationParameters;
public CustomJwtDataFormat(string algorithm, TokenValidationParameters validationParameters)
{
this.algorithm = algorithm;
this.validationParameters = validationParameters;
}
// This ISecureDataFormat implementation is decode-only
string ISecureDataFormat<AuthenticationTicket>.Protect(AuthenticationTicket data)
{
return MyProtect(data, null);
}
string ISecureDataFormat<AuthenticationTicket>.Protect(AuthenticationTicket data, string purpose)
{
return MyProtect(data, purpose);
}
AuthenticationTicket ISecureDataFormat<AuthenticationTicket>.Unprotect(string protectedText)
{
return MyUnprotect(protectedText, null);
}
AuthenticationTicket ISecureDataFormat<AuthenticationTicket>.Unprotect(string protectedText, string purpose)
{
return MyUnprotect(protectedText, purpose);
}
private string MyProtect(AuthenticationTicket data, string purpose)
{
return "wadehadedudada";
throw new System.NotImplementedException();
}
// http://blogs.microsoft.co.il/sasha/2012/01/20/aggressive-inlining-in-the-clr-45-jit/
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
private AuthenticationTicket MyUnprotect(string protectedText, string purpose)
{
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
ClaimsPrincipal principal = null;
SecurityToken validToken = null;
System.Collections.Generic.List<System.Security.Claims.Claim> ls =
new System.Collections.Generic.List<System.Security.Claims.Claim>();
ls.Add(
new System.Security.Claims.Claim(
System.Security.Claims.ClaimTypes.Name, "IcanHazUsr_éèêëïàáâäåãæóòôöõõúùûüñçø_ÉÈÊËÏÀÁÂÄÅÃÆÓÒÔÖÕÕÚÙÛÜÑÇØ 你好,世界 Привет\tмир"
, System.Security.Claims.ClaimValueTypes.String
)
);
//
System.Security.Claims.ClaimsIdentity id = new System.Security.Claims.ClaimsIdentity("authenticationType");
id.AddClaims(ls);
principal = new System.Security.Claims.ClaimsPrincipal(id);
return new AuthenticationTicket(principal, new AuthenticationProperties(), "MyCookieMiddlewareInstance");
try
{
principal = handler.ValidateToken(protectedText, this.validationParameters, out validToken);
JwtSecurityToken validJwt = validToken as JwtSecurityToken;
if (validJwt == null)
{
throw new System.ArgumentException("Invalid JWT");
}
if (!validJwt.Header.Alg.Equals(algorithm, System.StringComparison.Ordinal))
{
throw new System.ArgumentException($"Algorithm must be '{algorithm}'");
}
// Additional custom validation of JWT claims here (if any)
}
catch (SecurityTokenValidationException)
{
return null;
}
catch (System.ArgumentException)
{
return null;
}
// Validation passed. Return a valid AuthenticationTicket:
return new AuthenticationTicket(principal, new AuthenticationProperties(), "MyCookieMiddlewareInstance");
}
}
또한 Microsoft.IdentityModel.Token을 사용하여 JWT 토큰을 만들 수도 있습니다.
// https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/IJwtBearerEvents.cs
// http://codereview.stackexchange.com/questions/45974/web-api-2-authentication-with-jwt
public class TokenMaker
{
class SecurityConstants
{
public static string TokenIssuer;
public static string TokenAudience;
public static int TokenLifetimeMinutes;
}
public static string IssueToken()
{
SecurityKey sSKey = null;
var claimList = new List<Claim>()
{
new Claim(ClaimTypes.Name, "userName"),
new Claim(ClaimTypes.Role, "role") //Not sure what this is for
};
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
SecurityTokenDescriptor desc = makeSecurityTokenDescriptor(sSKey, claimList);
// JwtSecurityToken tok = tokenHandler.CreateJwtSecurityToken(desc);
return tokenHandler.CreateEncodedJwt(desc);
}
public static ClaimsPrincipal ValidateJwtToken(string jwtToken)
{
SecurityKey sSKey = null;
var tokenHandler = new JwtSecurityTokenHandler();
// Parse JWT from the Base64UrlEncoded wire form
//(<Base64UrlEncoded header>.<Base64UrlEncoded body>.<signature>)
JwtSecurityToken parsedJwt = tokenHandler.ReadToken(jwtToken) as JwtSecurityToken;
TokenValidationParameters validationParams =
new TokenValidationParameters()
{
RequireExpirationTime = true,
ValidAudience = SecurityConstants.TokenAudience,
ValidIssuers = new List<string>() { SecurityConstants.TokenIssuer },
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
IssuerSigningKey = sSKey,
};
SecurityToken secT;
return tokenHandler.ValidateToken("token", validationParams, out secT);
}
private static SecurityTokenDescriptor makeSecurityTokenDescriptor(SecurityKey sSKey, List<Claim> claimList)
{
var now = DateTime.UtcNow;
Claim[] claims = claimList.ToArray();
return new Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Issuer = SecurityConstants.TokenIssuer,
Audience = SecurityConstants.TokenAudience,
IssuedAt = System.DateTime.UtcNow,
Expires = System.DateTime.UtcNow.AddMinutes(SecurityConstants.TokenLifetimeMinutes),
NotBefore = System.DateTime.UtcNow.AddTicks(-1),
SigningCredentials = new SigningCredentials(sSKey, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.EcdsaSha512Signature)
};
}
}
쿠키와 http-headers (Bearer) 또는 지정한 다른 인증 방법에서 다른 사용자를 제공 할 수 있기 때문에 실제로 둘 이상의 사용자를 가질 수 있습니다!
이것을보십시오 :
https://stormpath.com/blog/token-authentication-asp-net-core
정확히 당신이 찾고있는 것이어야합니다.
다음 두 가지도 있습니다.
그리고 이것은
http://blog.novanet.no/hooking-up-asp-net-core-1-rc1-web-api-with-auth0-bearer-tokens/
그리고 JWT-Bearer 소스 https://github.com/aspnet/Security/tree/master/src/Microsoft.AspNetCore.Authentication.JwtBearer
매우 높은 보안이 필요한 경우 각 요청에 대해 티켓을 갱신하여 재생 공격으로부터 보호하고, 특정 시간 초과 후 및 사용자 로그 아웃 후 (유효 만료 후뿐만 아니라) 이전 티켓을 무효화해야합니다.
Google을 통해 여기에서 끝나는 사람들을 위해 자신의 JWT 버전을 사용하려는 경우 쿠키 인증에서 TicketDataFormat을 구현할 수 있습니다.
애플리케이션을 보호해야했기 때문에 작업을 위해 JWT를 조사해야했습니다.
.NET 2.0을 사용해야했기 때문에 자체 라이브러리를 작성해야했습니다.
이번 주말에 그 결과를 .NET Core로 포팅했습니다. 여기에서 찾을 수 있습니다 : https://github.com/ststeiger/Jwt_Net20/tree/master/CoreJWT
데이터베이스를 사용하지 않으며 JWT 라이브러리의 작업이 아닙니다.
DB 데이터를 얻고 설정하는 것이 당신의 일입니다.
라이브러리는 IANA JOSE 할당에 나열된 JWT RFC에 지정된 모든 알고리즘을 사용하여 .NET Core에서 JWT 권한 부여 및 확인을 허용 합니다 .
파이프 라인에 권한을 추가하고 경로에 값을 추가하는 방법은 별도로 수행해야하는 두 가지 작업이며 직접 수행하는 것이 가장 좋습니다.
ASP.NET Core에서 사용자 지정 인증을 사용할 수 있습니다. docs.asp.net에서 문서
의 "보안"범주를 살펴보십시오 .
또는 ASP.NET ID없이 쿠키 미들웨어 나 사용자 지정 정책 기반 권한 부여를 살펴볼 수 있습니다 .
또한 github 의 인증 워크숍 이나 소셜 로그인 섹션 또는 이 채널 9 비디오 자습서 에서 자세히 알아볼 수 있습니다 .
다른 모든 방법이 실패하면 asp.net 보안의 소스 코드는 github에 있습니다.
내 라이브러리가 파생 된 .NET 3.5의 원래 프로젝트는 다음과 같습니다.
https://github.com/jwt-dotnet/jwt
LINQ + 확장 메서드에 대한 모든 참조는 .NET에서 지원되지 않기 때문에 제거했습니다. 2.0. 소스 코드에 LINQ 또는 ExtensionAttribute를 포함하면 경고없이 .NET 런타임을 변경할 수 없습니다. 그래서 완전히 제거했습니다.
또한 CoreJWT 프로젝트가 BouncyCastle에 의존하는 이유 때문에 RSA + ECSD JWS 방법을 추가했습니다.
HMAC-SHA256 + HMAC-SHA384 + HMAC-SHA512로 제한하는 경우 BouncyCastle을 제거 할 수 있습니다.
JWE는 (아직) 지원되지 않습니다.
사용법은 jwt-dotnet / jwt와 비슷 하지만 네임 스페이스 JWT를 CoreJWT로 변경했습니다 .
또한 PetaJSON의 내부 복사본을 serializer로 추가 했으므로 다른 사람의 프로젝트 종속성에 간섭이 없습니다.
JWT 토큰 생성 :
var payload = new Dictionary<string, object>()
{
{ "claim1", 0 },
{ "claim2", "claim2-value" }
};
var secretKey = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
string token = JWT.JsonWebToken.Encode(payload, secretKey, JWT.JwtHashAlgorithm.HS256);
Console.WriteLine(token);
JWT 토큰 확인 :
var token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjbGFpbTEiOjAsImNsYWltMiI6ImNsYWltMi12YWx1ZSJ9.8pwBI_HtXqI3UgQHQ_rDRnSQRxFL1SR8fbQoS-5kM5s";
var secretKey = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
try
{
string jsonPayload = JWT.JsonWebToken.Decode(token, secretKey);
Console.WriteLine(jsonPayload);
}
catch (JWT.SignatureVerificationException)
{
Console.WriteLine("Invalid token!");
}
RSA 및 ECSA의 경우 secretKey 대신 (BouncyCastle) RSA / ECSD 개인 키를 전달해야합니다.
namespace BouncyJWT
{
public class JwtKey
{
public byte[] MacKeyBytes;
public Org.BouncyCastle.Crypto.AsymmetricKeyParameter RsaPrivateKey;
public Org.BouncyCastle.Crypto.Parameters.ECPrivateKeyParameters EcPrivateKey;
public string MacKey
{
get { return System.Text.Encoding.UTF8.GetString(this.MacKeyBytes); }
set { this.MacKeyBytes = System.Text.Encoding.UTF8.GetBytes(value); }
}
public JwtKey()
{ }
public JwtKey(string macKey)
{
this.MacKey = macKey;
}
public JwtKey(byte[] macKey)
{
this.MacKeyBytes = macKey;
}
public JwtKey(Org.BouncyCastle.Crypto.AsymmetricKeyParameter rsaPrivateKey)
{
this.RsaPrivateKey = rsaPrivateKey;
}
public JwtKey(Org.BouncyCastle.Crypto.Parameters.ECPrivateKeyParameters ecPrivateKey)
{
this.EcPrivateKey = ecPrivateKey;
}
}
}
BouncyCastle을 사용하여 RSA / ECSD 키를 생성 / 내보내기 / 가져 오는 방법은 동일한 저장소에서 "BouncyCastleTests"라는 프로젝트를 참조하십시오. 자신의 RSA / ECSD 개인 키를 안전하게 저장하고 검색 할 수 있도록 맡깁니다.
JWT.io를 사용하여 HMAC-ShaXXX 및 RSA-XXX에 대한 내 라이브러리의 결과를 확인했습니다. 괜찮은 것 같습니다.
ECSD도 괜찮을 것입니다. 그러나 나는 그것을 아무것도 테스트하지 않았습니다.
어쨌든 광범위한 테스트를 실행하지 않았습니다.
지금까지 찾은 가장 쉬운 옵션은 OpenIddict 입니다. Entity Framework와 OpenIddict를 피하고 싶다고 말합니다. 그러면 많은 코딩을 직접 수행하여 OpenIddict와 ASOS (OpenIddict가 사용하는)의 일부를 효과적으로 다시 작성 하여 어쨌든 수행하는 작업을 수행합니다.
OpenIddict를 사용해도 괜찮다면 아래에서 필요한 모든 구성이 사실상 전부입니다. 아주 간단합니다.
EF를 사용하고 싶지 않다면 OpenIddict로 가능합니다. 방법은 잘 모르겠지만 그게 당신이 알아 내야 할 부분입니다.
ConfigureServices :
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddOpenIddictCore<Application>(config => config.UseEntityFramework()); // this line is for OpenIddict
구성
app.UseOpenIddictCore(builder =>
{
// tell openiddict you're wanting to use jwt tokens
builder.Options.UseJwtTokens();
// NOTE: for dev consumption only! for live, this is not encouraged!
builder.Options.AllowInsecureHttp = true;
builder.Options.ApplicationCanDisplayErrors = true;
});
// use jwt bearer authentication
app.UseJwtBearerAuthentication(options =>
{
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
options.RequireHttpsMetadata = false;
// these urls must match the value sent in the payload posted from the client side during login
options.Audience = "http://localhost:58292/";
options.Authority = "http://localhost:58292/";
});
DbContext가 .NET에서 파생해야하는 것과 같은 다른 사소한 사항이 하나 또는 두 개 있습니다 OpenIddictContext<ApplicationUser, Application, ApplicationRole, string>
.
이 블로그 게시물 ( http://capesean.co.za/blog/asp-net-5-jwt-tokens/ )에서 전체 길이 설명 (github 저장소에 대한 링크 포함)을 볼 수 있습니다 .
외부 OAuth / OpenID 공급자 (예 : Google, GitHub, Facebook, Microsoft 계정 등)에 대한 인증 만 있으면 타사 도구가 필요하지 않습니다.
가장 일반적으로 사용되는 OAuth 및 OpenID 공급자에 대한 인증 공급자는 이미 Microsoft.AspNetCore.Authorization.*
패키지의 ASP.NET Core와 함께 제공 됩니다. " 보안 "저장소 의 GitHub 저장소에 제공된 샘플을 확인하십시오.
고유 한 JWT 토큰을 생성해야하는 경우 OAuth / OpenID 서버가 필요합니다. OpenIddict는 설정하기 쉬운 권한 부여 서버입니다. 이를 위해서는 외부 공급자가 사람을 인증하는 데 사용되기 때문에 데이터베이스 형식이 필요하지만 인증 서버에 계정이 있어야합니다.
더 많은 사용자 지정과 흐름 제어가 더 필요한 경우 ASOS 또는 IdentityServer4를 사용해야합니다 (현재 전체 .NET Framework 또는 Mono에 대해 작업 할 때 ASP.NET Core에서만 지원됩니다. 코어 런타임은 내가 아는 한 아직 지원되지 않음) .
https://gitter.im/openiddict/core 에 OpenIddict 용 Gitter Chatroom 과 ASOS 용 https://gitter.im/aspnet-contrib/AspNet.Security.OpenIdConnect.Server도 있습니다.
ASP.NET Core + JWT Auth + SQL Server + Swagger에 대한 전체 예제가 있습니다 : https://github.com/wilsonwu/netcoreauth
이것이 당신을 도울 수 있기를 바랍니다.
확보 ASP.NET 코어 2.0 웹 API 와 표준 JWT 무기명 토큰 기반 인증
& 다음과 같이 인증 필터를 적용하십시오.
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
다음은 패키지입니다.
- Asp Net Core 2.0+ 앱에 JWT Bearer 토큰 보안을 쉽게 통합 할 수 있습니다!
- Azure Active Directory 인증 통합.
- Facebook 인증 통합.
- 또한 Swagger UI 통합!
AspNetCore.Security.Jwt 라고 합니다.
GitHub :
https://github.com/VeritasSoftware/AspNetCore.Security.Jwt
이 패키지는 JWT 전달자 토큰을 아래와 같이 앱에 통합합니다.
1. 앱에서 IAuthentication 인터페이스 구현
using AspNetCore.Security.Jwt;
using System.Threading.Tasks;
namespace XXX.API
{
public class Authenticator : IAuthentication
{
public async Task<bool> IsValidUser(string id, string password)
{
//Put your id authenication here.
return true;
}
}
}
2. Startup.cs에서
using AspNetCore.Security.Jwt;
using Swashbuckle.AspNetCore.Swagger;
.
.
public void ConfigureServices(IServiceCollection services)
{
.
.
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "XXX API", Version = "v1" });
});
services.AddSecurity<Authenticator>(this.Configuration, true);
services.AddMvc().AddSecurity();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
.
.
.
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "XXX API V1");
});
app.UseSecurity(true);
app.UseMvc();
}
3. appsettings.json에서
참고 :-사용자 비밀 관리 메뉴 (프로젝트를 마우스 오른쪽 버튼으로 클릭)를 사용하여 이러한 설정을 Secret Manager에 넣을 수 있습니다.
{
"SecuritySettings": {
"Secret": "a secret that needs to be at least 16 characters long",
"Issuer": "your app",
"Audience": "the client of your app",
"IdType": "Name",
"TokenExpiryInHours" : 2
},
.
.
.
}
그런 다음 자동으로 엔드 포인트를 얻습니다.
/토큰
/ 페이스 북
이러한 엔드 포인트를 호출하고 성공적으로 인증되면 JWT Bearer 토큰을 다시 받게됩니다.
보안하려는 컨트롤러에서
다음과 같은 Authorize 속성으로 보호하려는 컨트롤러 또는 작업을 표시해야합니다.
using Microsoft.AspNetCore.Mvc;
.
.
.
namespace XXX.API.Controllers
{
using Microsoft.AspNetCore.Authorization;
[Authorize]
[Route("api/[controller]")]
public class XXXController : Controller
{
.
.
.
}
}
Swagger UI에서는 이러한 엔드 포인트가 자동으로 표시됩니다.
참조 URL : https://stackoverflow.com/questions/35307143/simple-jwt-authentication-in-asp-net-core-1-0-web-api
'IT TIP' 카테고리의 다른 글
호스트 Mac OS에서 VirtualBox의 게스트 Linux 시스템으로 폴더 공유 (0) | 2020.12.25 |
---|---|
표준 라이브러리는 std :: swap을 어떻게 구현합니까? (0) | 2020.12.25 |
스레드 컨텍스트 전환 오버 헤드를 추정하는 방법은 무엇입니까? (0) | 2020.12.25 |
WCF 서비스에 대한 전역 예외 처리기를 어떻게 만듭니 까? (0) | 2020.12.25 |
Git 하위 모듈 내에 추가 된 .gitignore 파일 (0) | 2020.12.25 |