C # web api using auth1.0a with OAuthAuthorizationServerProvider

I set up authentication based on the JWT token using OAuthAuthorizationServerProvider some time ago. The provider is as follows:

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

This works well, and for the most part, this is normal. My manager, as now asked me to enable authentication for other applications, using the key and secret . I would like to use OAuthAuthorizationServerProvider , but I can not find any documentation on how to do this.

I read and found a method that can be overridden: GrantCustomExtension and thought that maybe I could use it to configure authentication, but as I mentioned, I have no idea how to set it up.

Has anyone had experience? If they are, can they help me by providing a sample code or by providing a link to a resource that I can read? Any help would be greatly appreciated.

+7
authentication c # asp.net-web-api oauth asp.net-web-api2
source share
1 answer

I recommend moving away from the Asp.net identifier and using IdentityServer .

IdentityServer4 is the OpenID Connect and OAuth 2.0 platform for the ASP.NET core. and IdentityServer3 for Asp.Net Classic (although you can use IdentityServer4 with Asp.net classics)

It is very easy to set up and very current project.

It has several functions such as

  • Authentication as a Service
  • Single entry / exit
  • Access Control for API
  • Federation Gateway

and for the most important part - free and open.

+1
source share

All Articles