0

I want to allow an user to access some site areas only if he activates his account (email confirmation, etc).

I want to allow him to login, but if he didn't activates his account (I have a user.confirmed property) I want to redirect him to a page that reminds him to confirm his account.

How can I do that? I can not place an if in each controller method to check that.

Fabricio
  • 7,705
  • 9
  • 52
  • 87
  • actually when you create a mvc project with empty read/write actions it has this functionality already built in, in the LogOnPartial page. – Jonesopolis Jun 17 '13 at 12:15
  • @Dan: Nothing. I dont know how to proceed. I thought about create an AuthorizeAttribute but someone told me I cant check for a specific user attribute login inside that. – Fabricio Jun 17 '13 at 12:15

1 Answers1

5

You could write your own AuthorizeAttribute and redirect the user from there which means it's as simple as decorating your action i.e.

public class ConfirmedUsersOnly: AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var loggedInUser = // pull user from storage
        return httpContext.User.Identity.IsAuthenticated && loggedInUser.confirmed;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (!filterContext.HttpContext.Request.IsAuthenticated)
        {
            // handle normal unauthorized redirect (e.g. login page)
            base.HandleUnauthorizedRequest(filterContext);
        }
        else
        {
            // redirect users who are logged in but not confirmed
            filterContext.HttpContext.Response.Redirect("NotConfirmedUrl");
        }
    }
}

Usage

[ConfirmedUsersOnly]
public ActionResult ConfirmedAccountAction()
{
    ...
}
James
  • 80,725
  • 18
  • 167
  • 237
  • 1
    How can I access an attribute of the current logged user inside that AuthorizeAttribute, like `user.confirmed`? – Fabricio Jun 17 '13 at 12:17
  • How can I `// handle users who haven't confirmed` ? Thats my problem! sorry. I dont know how to access there the user property `user.confirmed`. – Fabricio Jun 17 '13 at 12:23
  • @Fabricio to answer your first comment - that's all dependent on your current setup i.e. what sort of backend are you using? What sort of information about the current logged in user do you have during a session? The "*handle users who haven't confirmed*" is just a comment to indicate that any users who haven't confirmed will be redirected to whichever URL you put there....I have updated the example to be more clear as to what is going on. – James Jun 17 '13 at 12:26
  • I'm using model-first entity-framework. I just dont know how to access the current logged user properties inside an AuthorizeAttribute. – Fabricio Jun 17 '13 at 12:29
  • @Fabricio Are you using forms authentication? – James Jun 17 '13 at 12:34
  • I don't think so. I don't even know whats that. The user just sends its info (login and password) via POST and I get that in a controller method then I look for him inside the database, like `User user = myContext.Users.FirstOrDefault(delegate(User u) { return u.Email == email && u.Password.Equals(pass); });` – Fabricio Jun 17 '13 at 12:37
  • Oh and I log the user in with that: `FormsAuthentication.SetAuthCookie(user.Fullname, remember);` I think you are talk about that.. (hehe.. sorry, I'm still learning.. be patient) – Fabricio Jun 17 '13 at 12:45
  • @Fabricio by storing an auth cookie you could the way you are, if you accessed the `User.Identity.Name` property it would give you the `Fullname` of the logged in user - but obviously that isn't going to be unique enough to look up the user. You have a couple of options, the cleanest being to create a custom principal object for when the user logs in and then it's literally just a case of casting `User.Identity` to your own class. Alternatively, as you are already storing an authentication ticket, you could expand it to include the email address which you can pull out in the attribute. – James Jun 17 '13 at 12:53
  • See this [answer](http://stackoverflow.com/questions/1064271/asp-net-mvc-set-custom-iidentity-or-iprincipal/10524305#10524305) for an example of how to create a custom `IPrincipal` object, and see [MSDN](http://msdn.microsoft.com/en-us/library/system.web.security.formsauthenticationticket.aspx) for an example of how to store more information with your authentication ticket (in particular look at the `userData` field). – James Jun 17 '13 at 12:55
  • Oh nice! Now I feel I'm on my way! Thank you :D – Fabricio Jun 17 '13 at 12:56