Question

Starting with the ASP.NET 5 Web App Template using Individual User Accounts I have managed to get external authentication working with Microsoft accounts. When users click Login they are redirected to ExternalLogin in AccountController like this

<form asp-controller="Account" asp-action="ExternalLogin" method="post" asp-route-returnurl="@ViewData["ReturnUrl"]" class="nav navbar-right">
    <button type="submit" class="btn btn-null nav navbar-nav navbar-right" name="provider" value="Microsoft" title="Log in"><span class="fa fa-sign-in"/>&nbsp; Log In</button>
</form>

That gets them logged in using thier Microsoft account and all seems to work nicely. But how do I intercept direct attempts to access privileged actions [Authorize] so that the user is redirected to ExternalLogin? Can a default action be set in Startup.cs?

EDIT 1 Attempting to follow the advice of @Yves I have created CustomAutorizationFilter in a Filters folder. It doesn't check for any conditions

public class CustomAutorizationFilter : IAuthorizationFilter
{
    public void OnAuthorization(Microsoft.AspNet.Mvc.Filters.AuthorizationContext context)
    {
        //if (...) // Check you conditions here
        //{
            context.Result = new RedirectToActionResult("ExternalLogin", "Account", null);
        //}
    }
}

and have edited ConfigureServices as below

        services.AddMvc(config =>
        {
            config.Filters.Add(typeof(Filters.CustomAutorizationFilter));
        });

When I run the app locally it no longer goes to the Home page. It returns a blank http://localhost:52711/Account/ExternalLogin

Obviously there is much I do not understand.

Edit 2: Here is the signature of ExternalLogin

 // POST: /Account/ExternalLogin
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public IActionResult ExternalLogin(string provider, string returnUrl = null)

This is how ExternalLogin comes out of the box in the ASP.Net 5 Web App Template.

Accepted Answer

As I was unable to get CustomAuthorizationFilter working as suggested by @Yves I have resorted to a nasty hack. I have modified AccountController Login as below

     // GET: /Account/Login
    [HttpGet]
    [AllowAnonymous]
    public IActionResult Login(string returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
        return RedirectToAction(nameof(ExternalLogin), new { provider = "Microsoft", returnUrl = returnUrl });
        //return View();
    }

This seems to work but I'd appreciate any feedback or advice if there is a better way.


Popular Answer

You can register an IAuthorizationFilter or an IActionFilter implementations to accomplish this. In these filters you can check if the request is trying to access a privileged action, if the user is logged in or have enough permission to do it.

If you are using AutorizeAttribute, I suggest you to use AutorizationFilter. If you go with your own custom attributes, then use ActionFilter.

Here is an example:

MVC calls IAuthorizationFilter.OnAuthorization method before every action execution.

public class CustomAuthorizationFilter : IAuthorizationFilter
{
    public void OnAuthorization(Microsoft.AspNet.Mvc.Filters.AuthorizationContext context)
    {
        if (...) // Check you conditions here
        {
            context.Result = new RedirectToActionResult("ExternalLogin", "Account", null);
        }
    }
}

To register this filter, in Startup.cs edit your ConfigureServices method:

services.AddMvc(config =>
{
    config.Filters.Add(typeof(CustomAuthorizationFilter ));
});

Or if you wan to use your own attributes you can use ActionFilter's OnActionExecuting method to check if everything is happening as you wish...



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why