I am trying to implement OWIN into my application but i hate having login in controllers, so I decided to try to and move the login into my provider.
My controller method looks like this:
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
[AllowAnonymous]
[Route("externallogin", Name = "ExternalLogin")]
public async Task<IHttpActionResult> GetExternalLoginAsync(string provider, string error = null) => await _userProvider.GetExternalLoginAsync(this, User.Identity, provider, error);
and in my UserProvider I have changed the code to this:
public async Task<IHttpActionResult> GetExternalLoginAsync(ApiController controller, IIdentity identity, string provider, string error = null)
{
// If we have an error, return it
if (error != null) throw new Exception(Uri.EscapeDataString(error));
// If the current user is not authenticated
if (!identity.IsAuthenticated) return new ChallengeResult(provider, controller);
// Validate the client and the redirct url
var redirectUri = await ValidateClientAndRedirectUriAsync(controller.Request);
// If we have no validated
if (!string.IsNullOrWhiteSpace(redirectUri)) throw new Exception(redirectUri);
// Get the current users external login
var externalLogin = GetExternalLoginDataFromIdentity(identity as ClaimsIdentity);
// If the current user has no external logins, throw an error
if (externalLogin == null) throw new ObjectNotFoundException();
// if the login provider doesn't match the one specificed
if (externalLogin.LoginProvider != provider)
{
// Sign the user out
AuthenticationManager(controller.Request).SignOut(DefaultAuthenticationTypes.ExternalCookie);
// Challenge the result
return new ChallengeResult(provider, controller);
}
// Get the user
var user = await FindAsync(new UserLoginInfo(externalLogin.LoginProvider, externalLogin.ProviderKey));
// Have they registered
bool hasRegistered = user != null;
// Update our url
redirectUri += $"{redirectUri}#external_access_token={externalLogin.ExternalAccessToken}&provider={externalLogin.LoginProvider}&haslocalaccount={hasRegistered.ToString()}&external_user_name={externalLogin.UserName}";
// Return our url
return new RedirectResult(redirectUri);
}
This wasn't too much of a problem for this particular method, but I would like to be able to use Ok(), BadRequest() and InternalServerError() methods of the controller. Also, I would like to use ModelState.IsValid. The latter can be used by passing the controller into the method and I can simply do:
controller.ModelState.IsValid
But the other methods are internal methods, so I would have to inherit the ApiController in my Provider which I can't do or find another way of doing this.
I found this on stackoverflow which made me think I could do something similar as I was already passing the controller to the method, so I created a static Extension class like this:
public static class ResponseExtensions
{
public static HttpResponseMessage Ok(T content) => new HttpResponseMessage(HttpStatusCode.Accepted, content);
}
In my method I was hoping to do something like this:
return controller.ResponseMessage(ResponseExtensions.Ok());
But the same issue arises in that ResponseMessage is also a protected internal method.
Has anyone come across this before and can give me some direction in how to solve this?