[英]Simple JWT authentication in ASP.NET Core 1.0 Web API
我正在尋找設置 Web API 服務器的最簡單方法,該服務器使用 JWT 在 ASP.NET Core(又名 ASP.NET 5)中進行身份驗證。 這個項目( 博客文章/ 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。
但它仍然是一個有用的閱讀。
同時,您可以在我的 github test repo 上找到 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();
}
}
棘手的部分是如何獲取 AsymmetricSecurityKey,因為您不想傳遞 rsaCryptoServiceProvider,因為您需要加密格式的互操作性。
創作沿着
// 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 的自定義 cookie 格式:
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)
};
}
}
請注意,因為您可以在 cookie 與 http-headers (Bearer) 或您指定的任何其他身份驗證方法中提供不同的用戶,所以您實際上可以擁有超過 1 個用戶!
看看這個:
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
如果您需要超高的安全性,您應該通過在每個請求上更新票證來防止重放攻擊,並在一定超時后和用戶注銷后(不僅僅是在有效期到期后)使舊票證失效。
對於那些通過谷歌從這里結束的人,當您想使用自己的 JWT 版本時,可以在 cookie 身份驗證中實現 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 Identity的Cookie Middleware或Custom Policy-Based Authorization 。
您還可以在 github 上的身份驗證研討會或社交登錄部分或此第 9 頻道視頻教程中了解更多信息。
如果一切都失敗了,asp.net security 的源代碼在 github 上。
.NET 3.5 的原始項目,這是我的庫的來源,在這里:
https://github.com/jwt-dotnet/jwt
我刪除了對 LINQ + 擴展方法的所有引用,因為 .NET 2.0 不支持它們。 如果您在源代碼中包含 LINQ 或 ExtensionAttribute,那么您不能在沒有收到警告的情況下更改 .NET 運行時; 這就是我完全刪除它們的原因。
另外,我添加了 RSA + ECSD JWS 方法,因此 CoreJWT 項目依賴於 BouncyCastle。
如果您將自己限制為 HMAC-SHA256 + HMAC-SHA384 + HMAC-SHA512,則可以刪除 BouncyCastle。
JWE(尚)不受支持。
用法就像 jwt-dotnet/jwt ,只是我將命名空間 JWT 更改為 CoreJWT 。
我還添加了 PetaJSON 的內部副本作為序列化程序,因此不會干擾其他人項目的依賴項。
創建一個 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,您必須傳遞 (BouncyCastle) RSA/ECSD 私鑰而不是 secretKey。
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 。 你說你想避免使用實體框架和 OpenIddict - 然后你自己會做很多編碼,有效地重寫 OpenIddict 和ASOS (OpenIddict 使用的)的部分來做他們正在做的事情。
如果您可以使用 OpenIddict,這實際上就是您需要的所有配置,如下所示。 這很簡單。
如果您不想使用 EF,則可以使用 OpenIddict。 我不確定如何,但這是你必須弄清楚的一點。
配置服務:
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 需要從OpenIddictContext<ApplicationUser, Application, ApplicationRole, string>
派生。
您可以在此博客文章中看到完整的解釋(包括指向 github 存儲庫的鏈接): http : //capesean.co.za/blog/asp-net-5-jwt-tokens/
如果您只需要針對外部 OAuth/OpenID 提供商(例如 Google、GitHub、Facebook、Microsoft 帳戶等)進行身份驗證,那么您就不需要任何第三方工具。
最常用的 OAuth 和 OpenID 提供程序的身份驗證提供程序已在Microsoft.AspNetCore.Authorization.*
包中隨 ASP.NET Core 一起提供。 查看“安全”存儲庫的 GitHub 存儲庫上提供的示例
如果您需要創建自己的 JWT 令牌,那么您需要一個 OAuth/OpenID 服務器。 OpenIddict 是一個易於設置的授權服務器。 為此,您需要某種形式的數據庫,因為外部提供者將用於驗證此人的身份,但您還需要他們在您的授權服務器上擁有一個帳戶。
如果您需要更多的自定義和對流程的更多控制,則必須使用 ASOS 或 IdentityServer4(目前僅在 ASP.NET Core 上支持在針對完整的 .NET Framework 或 Mono 工作時。據我所知,目前尚不支持 Core 運行時.
還有一個用於 OpenIddict 的 Gitter 聊天室https://gitter.im/openiddict/core和https://gitter.im/aspnet-contrib/AspNet.Security.OpenIdConnect.Server for ASOS。
有一個 ASP.NET Core + JWT Auth + SQL Server + Swagger 的完整示例: https : //github.com/wilsonwu/netcoreauth
希望這可以幫到你。
使用基於標准 JWT 承載令牌的身份驗證保護ASP.NET Core 2.0 Web API
& 應用授權過濾器如下
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
這是一個包
它被稱為AspNetCore.Security.Jwt
GitHub:
https://github.com/VeritasSoftware/AspNetCore.Security.Jwt
該軟件包將 JWT 不記名令牌集成到您的應用程序中,如下所示:
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;
}
}
}
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();
}
注意:- 您可以使用“管理用戶機密”菜單(右鍵單擊您的項目)將這些設置放在 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 Token。
您必須使用 Authorize 屬性標記要保護的控制器或操作,例如:
using Microsoft.AspNetCore.Mvc;
.
.
.
namespace XXX.API.Controllers
{
using Microsoft.AspNetCore.Authorization;
[Authorize]
[Route("api/[controller]")]
public class XXXController : Controller
{
.
.
.
}
}
在 Swagger UI 中,您將自動看到這些端點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.