我之前使用 OAuthAuthorizationServerProvider 设置了基于JWT令牌的身份验证。提供者看起来像这样:
public class OAuthProvider : OAuthAuthorizationServerProvider
{
// Private properties
private readonly IAdvancedEncryptionStandardProvider _helper;
private readonly IUserProvider _userProvider;
// Optional fields
private readonly Lazy<IClientService> _clientService;
/// <summary>
/// Default constructor
/// </summary>
/// <param name="helper"></param>
public OAuthProvider(IAdvancedEncryptionStandardProvider helper, IUserProvider userProvider, Lazy<IClientService> clientService)
{
_helper = helper;
_userProvider = userProvider;
_clientService = clientService;
}
/// <summary>
/// Always validate the client because we are using angular
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Set up our variables
var clientId = string.Empty;
var clientSecret = string.Empty;
Client client = null;
// Try to get our credentials if basic authentication has been used
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
context.TryGetFormCredentials(out clientId, out clientSecret);
// If we have no client id
if (context.ClientId == null)
{
//Remove the comments from the below line context.SetError, and invalidate context
//if you want to force sending clientId/secrects once obtain access tokens.
context.Validated();
//context.SetError("invalid_clientId", "ClientId should be sent.");
return;
}
// Get our client
client = await _clientService.Value.GetAsync(context.ClientId);
// If we have no client, throw an error
if (client == null)
{
context.SetError("invalid_clientId", $"Client '{ context.ClientId }' is not registered in the system.");
return;
}
// Get the application type
if (client.ApplicationType == ApplicationTypes.NativeConfidential)
{
// If we have a client secret
if (string.IsNullOrWhiteSpace(clientSecret))
{
context.SetError("invalid_clientId", "Client secret shoud be sent.");
return;
}
if (client.Secret != _helper.Encrypt(clientSecret))
{
context.SetError("invalid_clientId", "Client secret is invalid.");
return;
}
}
// If the client is inactive, throw an error
if (!client.Active)
{
context.SetError("invalid_clientId", "Client is inactive.");
return;
}
// Set our allowed origin and token expiration
context.OwinContext.Set<string>("as:clientAllowedOrigin", client.AllowedOrigin);
context.OwinContext.Set<string>("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTime.ToString());
// Validate our request
context.Validated();
return;
}
/// <summary>
/// Authorize the request
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// Set our allowed origin
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
if (string.IsNullOrEmpty(allowedOrigin))
allowedOrigin = "*";
// Add our CORS
context.OwinContext.Response.Headers.Remove("Access-Control-Allow-Origin");
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
// Find user by username first
var user = await _userProvider.FindByNameAsync(context.UserName);
// If our user actually exists
if (user != null)
{
// Validate the users credentials
var validCredentials = await _userProvider.FindAsync(context.UserName, context.Password);
var lockoutEnabled = await _userProvider.GetLockoutEnabledAsync(user.Id);
// If lockout is enabled
if (lockoutEnabled)
{
// If the user entered invalid credentials
if (validCredentials == null)
{
// Record the failure which also may cause the user to be locked out
await _userProvider.AccessFailedAsync(user);
// Find out how many attempts are left
var accessFailedCount = await _userProvider.GetAccessFailedCountAsync(user.Id);
var attemptsLeft = Convert.ToInt32(ConfigurationManager.AppSettings["MaxFailedAccessAttemptsBeforeLockout"].ToString()) - accessFailedCount;
// Inform the user of the error
context.SetError("invalid_grant", string.Format(Resources.PasswordInvalid, attemptsLeft));
return;
}
// Check to see if the user is already locked out
var lockedOut = await _userProvider.IsLockedOutAsync(user.Id);
// If the user is lockted out
if (lockedOut)
{
// Inform the user
context.SetError("invalid_grant", string.Format(Resources.UserLocked, ConfigurationManager.AppSettings["DefaultAccountLockoutTimeSpan"].ToString()));
return;
}
// If we get this far, reset the access attempts
await _userProvider.ResetAccessFailedCountAsync(validCredentials);
}
// If the user entered the correct details
if (validCredentials != null)
{
// If the user has not confirmed their account
if (!validCredentials.EmailConfirmed)
{
// Inform the user
context.SetError("invalid_grant", Resources.UserHasNotConfirmed);
return;
}
// Generate our identity
var oAuthIdentity = await _userProvider.CreateIdentityAsync(validCredentials, "JWT");
oAuthIdentity.AddClaims(ExtendedClaimsProvider.GetClaims(validCredentials));
// Create our properties
var properties = new AuthenticationProperties(new Dictionary<string, string>
{
{"as:client_id", string.IsNullOrEmpty(context.ClientId) ? string.Empty : context.ClientId},
{"userName", context.UserName}
});
// Create our ticket and authenticate the user
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
return;
}
}
// Failsafe
context.SetError("invalid_grant", Resources.UserOrPasswordNotFound);
return;
}
/// <summary>
/// Adds additional properties to the response
/// </summary>
/// <param name="context">The current context</param>
/// <returns></returns>
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
context.AdditionalResponseParameters.Add(property.Key, property.Value);
return Task.FromResult<object>(null);
}
/// <summary>
/// Grants a refresh token for the current context
/// </summary>
/// <param name="context">The current context</param>
/// <returns></returns>
public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
{
// Get our client ids
var originalClient = context.Ticket.Properties.Dictionary["as:client_id"];
var currentClient = context.ClientId;
// If we are not the same client
if (originalClient != currentClient)
{
// Set the error and exit the function
context.SetError("invalid_clientId", "Refresh token is issued to a different clientId.");
return Task.FromResult<object>(null);
}
// Change auth ticket for refresh token requests
var newIdentity = new ClaimsIdentity(context.Ticket.Identity);
newIdentity.AddClaim(new Claim("newClaim", "newValue"));
var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties);
context.Validated(newTicket);
return Task.FromResult<object>(null);
}
}
这很好用,大部分都很好。我的经理现在要求我使用密钥和密钥将身份验证用于其他应用程序。 我想使用 OAuthAuthorizationServerProvider 来执行此操作,但我无法找到任何有关如何设置此文档的文档。
我已阅读并找到了一个可以覆盖的方法: GrantCustomExtension 并认为我可以使用它来设置身份验证,但就像我提到的那样,我不知道如何设置它起来。
有没有人有这方面的经验?如果他们有,他们可以通过提供代码示例或给我链接到我可以阅读的资源来帮助我吗? 任何帮助将不胜感激。
答案 0 :(得分:1)
我建议您远离Asp.net身份并使用IdentityServer。
IdentityServer4是ASP.NET Core的OpenID Connect和OAuth 2.0框架。 IdentityServer3适用于Asp.Net Classic(尽管您可以将IdentityServer4与Asp.net classic一起使用)
配置和正在进行的项目非常容易。
它有几个功能,如
而对于最重要的部分,它是免费和开源的。