After following an online tutorial to use token based authentication using OWIN, I managed to get my test app authenticating against a hard coded username/password, as the demo did.
However, now I want my model from my web application to be used.
My authentication happens, as the demo said, in this bit of code.
namespace UI { public class AuthorisationServerProvider : OAuthAuthorizationServerProvider { public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); // Means I have validated the client. } public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { // Here we validate the user... var identity = new ClaimsIdentity(context.Options.AuthenticationType); if (context.UserName == "user" && context.Password == "password") { identity.AddClaim(new Claim(ClaimTypes.Role, "admin")); identity.AddClaim(new Claim("username", "user")); identity.AddClaim(new Claim(ClaimTypes.Name, "My Full Name")); context.Validated(identity); } else { context.SetError("Invalid grant", "Username or password are incorrect"); return; } } } }
I have a WebAPI controller, which I receive a model from, and ... not sure how to call the above code, from my webapi controller. At the moment, the code above expects a call to myurl/token - that was defined in the startup code.
public class Startup { public void Configuration(IAppBuilder app) { // Enables cors origin requests. app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); // Config OAuth authorisation server; var myProvider = new AuthorisationServerProvider(); OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions { AllowInsecureHttp = true, // Live version should use HTTPS... TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), Provider = myProvider }; app.UseOAuthAuthorizationServer(options); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); HttpConfiguration config = new HttpConfiguration(); WebApiConfig.Register(config); } }
So, I'm guessing the url from my webapi call should be /token? So, in my (Knockout View model) code on my UI, I tried this:
Login() { var data = { username : this.login.emailAddress(), password : this.login.password(), RememberMe: this.login.rememberMe(), grant_type: "password" } return $.ajax({ type: "POST", data: data ? JSON.stringify(data) : null, dataType: "json", url: "/token", contentType: "application/json" }).done((reply) => { alert("Done!"); }); }
But, I get an exception:
“error”: “unsupported_grant_type”
In 'Postman', I am able to authenticate the hard coded username/password.
But I am not sure how to wire up my api call from my UI, to authenticate.
I was hoping to create a 'Login' method on my api controller (ASP.Net WebAPI), like this:
[Route("login"), HttpPost, AllowAnonymous] public ReplyDto Login(LoginRequest login) { ReplyDto reply = _userService.Login(login.Email, login.Password); return reply; }
So, my _userService checks if the user is in the database... if so, call my OAuth authentication here passing a few parameters. But not sure that's possible. Can I call my authentication from this api method? I'd need to remove the /token bit though.
2 Answers
Answers 1
You don't need to create a Login method since you already have it. It's http://localhost:1234/token. This is will generate a token if the user exists and if the password is correct. But get this behaviour you need to implement your own AuthServerProvider by deriving from OAuthAuthorizationServerProvider
public class DOAuthServerProvider : OAuthAuthorizationServerProvider
and then you would override a method to implement your logic:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { try { string allowedOrigin = context.OwinContext.Get<string>(DOAuthStatic.ALLOWED_CORS_ORIGINS_KEY); if (allowedOrigin != null) { context.OwinContext.Response.Headers[DOAuthStatic.CORS_HEADER] = allowedOrigin; } DAuthenticationResponse authResponse = await _authRepository.Authenticate(context.UserName, context.Password); if (!authResponse.IsAuthenticated) { context.SetError(OAuthError.InvalidGrant, $"{(int)authResponse.AuthenticateResult}:{authResponse.AuthenticateResult}"); return; } if (authResponse.User.ChangePasswordOnLogin) { _userAuthenticationProvider.GeneratePasswordResetToken(authResponse.User); } IDictionary<string, string> props = new Dictionary<string, string> { { DOAuthStatic.CLIENT_NAME_KEY, context.ClientId ?? string.Empty } }; ValidateContext(context, authResponse, props); } catch (Exception ex) { DLogOAuth.LogException(ex, "DCO0407E", "OAuthServerProvider - Error validating user"); throw; } }
You are almost there, you just need to do two more steps:
- Add the AuthorizeAttribute on your method or controller to restrict access for unauthenticated users.
- Add the access token you request header. If you skip this step you should get a 401 HTTP status code, meaning unauthorized. This is how you can confirm that the authorise attribute that you added in step one works.
Here is a great series of tutorials that explains everything really well: Token based authentication (way better than I have :) )
Answers 2
Change the Content Type "application/json" to "application/www-form-urlencoded"
You are Sended Data in Postman "application/www-form-urlencoded" format. But in Your Code Using "application/Json" the Content Type Mismatch. So,the Data is Not Send Proper Format.
You Can Change If it's Working Fine.
0 comments:
Post a Comment