Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent users without confirmed email from logging in ASP.NET MVC Web API Identity (OWIN Security)

I have a MVC and a web API projects, authenticated using ASP.NET MVC Web API Identity (OWIN Security).

I added an email confirmation to the Register function that works properly but I'm not sure how to check if emailConfirmed = true before logging in because there is no an explicit Login function on Web API Identity, it's implicit.

I know Microsoft has a good reason to deeply encapsulate the authorization functionality, but isn't there a way to achieve that?

Please advise.

This is my Register function:

[AllowAnonymous]
[Route("Register")]
 public async Task<IHttpActionResult> Register(RegisterBindingModel model)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };

        IdentityResult result = await UserManager.CreateAsync(user, model.Password);

        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

        try
        {
            var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);

            var callbackUrl = new Uri(Url.Link("ConfirmEmailRoute", new { userId = user.Id, code = code }));

            var email = new Email();
            email.To = user.Email;
            email.From = "[email protected]";
            email.Subject = "Please confirm your account";
            email.Body = "Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>";

            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            var data = JsonConvert.SerializeObject(email);

            WebClient client = new WebClient();
            client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
            var resp = client.UploadString(@"http:...", data);
        }
        catch (Exception ex)
        {
            throw new Exception(ex.ToString());
        }
        return Ok();
    }
like image 984
user3378165 Avatar asked Jul 17 '16 09:07

user3378165


1 Answers

After a lot of researches I have found the answer.

I added the following code that checks if the emailconfirmed = true:

var userid = userManager.FindByEmail(context.UserName).Id;
        if (!userManager.IsEmailConfirmed(userid))
        {
            context.SetError("invalid_grant", "Email registration wasn't confirmed.");
            return;
        }

To the GrantResourceOwnerCredentials function in the ApplicationOAuthProvider.cs class (under the Provider folder).

This is the entire function:

   public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

        ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);

        if (user == null)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return;
        }
        ////Added code here
        var userid = userManager.FindByEmail(context.UserName).Id;
        if (!userManager.IsEmailConfirmed(userid))
        {
            context.SetError("invalid_grant", "Email registration wasn't confirmed.");
            return;
        }
        ////
        ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
           OAuthDefaults.AuthenticationType);
        ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
            CookieAuthenticationDefaults.AuthenticationType);

        AuthenticationProperties properties = CreateProperties(user.UserName);
        AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
        context.Validated(ticket);
        context.Request.Context.Authentication.SignIn(cookiesIdentity);
    }

That works perfectly and prevents the user from logging in before he confirmed the registration email.

like image 198
user3378165 Avatar answered Nov 13 '22 01:11

user3378165