简体   繁体   中英

I can't seem to get a very basic cookie login example to work with MVC5 and OWIN

I've been trying to get my feet wet with ASP.net MVC 5 for 2013, but so far I've failed to get even the most basic authentication working correctly.

I've been reading around for the last few days and I finally stumbled upon ( http://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/ ) which seemed to give the most basic simple example I could find. So I tried that, but it still fails to seem to actually create a session for the user.

Here is my cookie config

public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/FooBar")
        });
    }

Here is my basic custom login.

public class LoginController : ApiController
    {
        private IAuthenticationManager Authentication
        {
            get { return Request.GetOwinContext().Authentication; }
        }

        // POST api/login
        public void Post([FromBody]LoginInfo email)
        {
            var fooBar = Authentication.User;
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, "name")
                ,new Claim(ClaimTypes.Email, "email@email.com")
                ,new Claim(ClaimTypes.Role, "Foo")
            };
            var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);

            Authentication.SignIn(new AuthenticationProperties() { IsPersistent = true }, identity);
        }
    }

If I hit the the login api twice I would have expected the second time that the fooBar variable to be set to a user who is marked as authenticated, but when I check it, it just says it's not authenticated, and it doesn't have any of the claims I would have expected.

I also tried creating a basic service to just check to see if it was authenticated in case I misunderstood how it worked, but this also fails. If I try to go to it, it says I'm not authenticated, it doesn't redirect me as I thought it would.

public class TestController : ApiController
    {
        [Authorize(Roles = "Foo")]
        public int Get()
        {
            return 1;
        }
    }

I'm sure I must just be missing some basic, but so far no matter what I fiddled with and regardless of the various guides and advice I've seen online, nothing has been able to get even this simple scenario working. Any ideas on what I'm doing wrong?

In the following post http://www.khalidabuhakmeh.com/asp-net-mvc-5-authentication-breakdown there is an helpful OWIN examples.

I did a mistake, the correct link is: http://www.khalidabuhakmeh.com/asp-net-mvc-5-authentication-breakdown-part-deux So, here we go with vb approach for basic cookie login:

a) Cookie Config.

Imports Microsoft.AspNet.Identity
Imports Microsoft.Owin
Imports Microsoft.Owin.Security.Cookies
Imports Owin

Partial Public Class Startup

    Public Sub ConfigureAuth(app As IAppBuilder)
        app.UseCookieAuthentication(New CookieAuthenticationOptions() With {
        .AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        .LoginPath = New PathString("/Account/Login")})
    End Sub
End Class

b) Home controller (Home index available for auth users)

<Authorize>
Public Class HomeController
    Inherits System.Web.Mvc.Controller

    <HttpGet>
    Function Index() As ActionResult
        Return View()
    End Function

End Class

c) Account controller (Login)

Imports System.Security.Claims
Imports System.Threading.Tasks
Imports Microsoft.AspNet.Identity
Imports Microsoft.AspNet.Identity.Owin
Imports Microsoft.Owin.Security

<Authorize>
Public Class AccountController
    Inherits Controller

    Private Function AuthenticationManager() As IAuthenticationManager
        Return HttpContext.GetOwinContext().Authentication
    End Function

    <AllowAnonymous>
    Public Function Login(returnUrl As String) As ActionResult
        ViewBag.ReturnUrl = returnUrl
        Return View()
    End Function

    <HttpPost>
    <AllowAnonymous>
    <ValidateAntiForgeryToken>
    Public Function Login(model As LoginViewModel, returnUrl As String) As ActionResult
        If ModelState.IsValid Then

            If model.UsuarioValido Then 'Local authentication, this must be on Repository class
                Dim Identidad = New ClaimsIdentity({New Claim(ClaimTypes.Name, model.UserName)},
                                                   DefaultAuthenticationTypes.ApplicationCookie,
                                                   ClaimTypes.Name,
                                                   ClaimTypes.Role)

                Identidad.AddClaim(New Claim(ClaimTypes.Role, "Invitado"))

                AuthenticationManager.SignIn(New AuthenticationProperties() With {.IsPersistent = model.RememberMe}, Identidad)

                Return RedirectToAction("index", "home")

            End If
        End If

        Return RedirectToAction("login", model)

    End Function

    <HttpGet>
    Public Function LogOff() As ActionResult
        AuthenticationManager.SignOut()
        Return RedirectToAction("login")
    End Function

End Class

d) Account Model

Imports System.ComponentModel.DataAnnotations

Public Class LoginViewModel
    <Required>
    <Display(Name:="Nombre de usuario")>
    Public Property UserName As String

    <Required>
    <DataType(DataType.Password)>
    <Display(Name:="Contraseña")>
    Public Property Password As String

    <Display(Name:="¿Recordar cuenta?")>
    Public Property RememberMe As Boolean

    Public ReadOnly Property UsuarioValido As Boolean
        Get
            Return Password = "secreto" 'Password Here!
        End Get
    End Property

End Class

e) Index view

@Imports Microsoft.AspNet.Identity

@Code
    ViewData("Title") = "Página Inicial"
End Code

<h2>Bienvenido @User.Identity.GetUserName()</h2>

<a href="@Url.Action("LogOff", "Account")">
    Click para salir! (Cerrar Sesión)
</a>

f) Login View

@ModelType LoginViewModel

@Code
    ViewBag.Title = "Iniciar sesión"
End Code

<h2>@ViewBag.Title.</h2>
<div class="row">
    <div class="col-md-8">
        <section id="loginForm">
            @Using Html.BeginForm("Login", "Account", New With { .ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, New With {.class = "form-horizontal", .role = "form"})
                @Html.AntiForgeryToken()
                @<text>
                <h4>Utilice una cuenta local para iniciar sesión.</h4>
                <hr />
                @Html.ValidationSummary(True)
                <div class="form-group">
                    @Html.LabelFor(Function(m) m.UserName, New With {.class = "col-md-2 control-label"})
                    <div class="col-md-10">
                        @Html.TextBoxFor(Function(m) m.UserName, New With {.class = "form-control"})
                        @Html.ValidationMessageFor(Function(m) m.UserName)
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(Function(m) m.Password, New With {.class = "col-md-2 control-label"})
                    <div class="col-md-10">
                        @Html.PasswordFor(Function(m) m.Password, New With {.class = "form-control"})
                        @Html.ValidationMessageFor(Function(m) m.Password)
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <div class="checkbox">
                            @Html.CheckBoxFor(Function(m) m.RememberMe)
                            @Html.LabelFor(Function(m) m.RememberMe)
                        </div>
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <input type="submit" value="Iniciar sesión" class="btn btn-default" />
                    </div>
                </div>
                </text>
            End Using
        </section>
    </div>

</div>
@Section Scripts
    @Scripts.Render("~/bundles/jqueryval")
End Section

I have had similar problems

I could not figure out what was different between my app (I inherited from someone else) and the default sample code.

I discovered that my [Authorize] attribute was not being applied by the framework even when the rest of the user management stack was working.

I realised eventually that AuthorizeAttribute is an example of a Filter and that by adding it explicitly in the FilterConfig it started to be used as expected (even though it is not added by the default sample code):

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new AuthorizeAttribute());
    }
}

and everything as usual in the Application_Start method:

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

Edit:

Although this lets the basic Authorize attribute work, it leads to a problem where the framework isn't instantiating the attribute per-method call with the Roles property set. So I had to figure out what caused the problem. It was due to some Unity setup code:

var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
FilterProviders.Providers.Remove(oldProvider);

Removing this (it was actually unused) fixed the issue, so I no longer needed FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); either

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM