Skip to content

Commit 2758134

Browse files
committed
Register user, delete user, and email confirmation
1 parent 017e356 commit 2758134

File tree

13 files changed

+349
-26
lines changed

13 files changed

+349
-26
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*.user
77
*.userosscache
88
*.sln.docstates
9+
AppSettings.config
910

1011
# User-specific files (MonoDevelop/Xamarin Studio)
1112
*.userprefs

personal_site_api/Controllers/AccountController.cs

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using Microsoft.AspNet.Identity;
2+
using personal_site_api.Infrastructure;
3+
using System;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using System.Web.Http;
7+
using static personal_site_api.Models.AccountBindingModels;
8+
9+
namespace personal_site_api.Controllers
10+
{
11+
[RoutePrefix("api/accounts")]
12+
public class AccountsController : BaseApiController
13+
{
14+
[Route("users")]
15+
public IHttpActionResult GetUsers()
16+
{
17+
return Ok(AppUserManager.Users.ToList().Select(u => TheModelFactory.Create(u)));
18+
}
19+
20+
[Route("user/{id:guid}", Name = "GetUserById")]
21+
public async Task<IHttpActionResult> GetUser(string Id)
22+
{
23+
var user = await AppUserManager.FindByIdAsync(Id);
24+
25+
if (user != null)
26+
return Ok(TheModelFactory.Create(user));
27+
28+
return NotFound();
29+
}
30+
31+
[Route("create")]
32+
public async Task<IHttpActionResult> CreateUser(CreateUserBindingModel createUserModel)
33+
{
34+
if (!ModelState.IsValid)
35+
return BadRequest(ModelState);
36+
37+
var user = new ApplicationUser()
38+
{
39+
UserName = createUserModel.Username,
40+
Email = createUserModel.Email
41+
};
42+
43+
IdentityResult addUserResult = await AppUserManager.CreateAsync(user, createUserModel.Password);
44+
45+
if (!addUserResult.Succeeded)
46+
return GetErrorResult(addUserResult);
47+
48+
//email configuration
49+
string code = await AppUserManager.GenerateEmailConfirmationTokenAsync(user.Id);
50+
var callbackUrl = new Uri(Url.Link("ConfirmEmailRoute", new { userId = user.Id, code }));
51+
await AppUserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your email by clicking <a href=\"" + callbackUrl + "\">here</a>");
52+
53+
Uri locationHeader = new Uri(Url.Link("GetUserById", new { id = user.Id }));
54+
55+
return Created(locationHeader, TheModelFactory.Create(user));
56+
}
57+
58+
[HttpGet]
59+
[Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
60+
public async Task<IHttpActionResult> ConfirmEmail(string userId = "", string code = "")
61+
{
62+
if (string.IsNullOrWhiteSpace(userId) || string.IsNullOrWhiteSpace(code))
63+
{
64+
ModelState.AddModelError("", "User Id and Code are required");
65+
return BadRequest(ModelState);
66+
}
67+
68+
IdentityResult result = await AppUserManager.ConfirmEmailAsync(userId, code);
69+
70+
if (result.Succeeded)
71+
return Ok();
72+
else
73+
return GetErrorResult(result);
74+
}
75+
76+
[Route("ChangePassword")]
77+
public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
78+
{
79+
if (!ModelState.IsValid)
80+
return BadRequest(ModelState);
81+
82+
var userId = User.Identity.GetUserId();
83+
84+
IdentityResult result = await AppUserManager.ChangePasswordAsync(userId, model.OldPassword, model.NewPassword);
85+
86+
if (!result.Succeeded)
87+
return GetErrorResult(result);
88+
89+
await AppUserManager.SendEmailAsync(userId, "Password Change", "Your password has been changed");
90+
91+
return Ok();
92+
}
93+
94+
[HttpDelete]
95+
[Route("user/{id:guid}")]
96+
public async Task<IHttpActionResult> DeleteUser(string id)
97+
{
98+
var appUser = await AppUserManager.FindByIdAsync(id);
99+
100+
if (appUser == null)
101+
return NotFound();
102+
103+
IdentityResult result = await AppUserManager.DeleteAsync(appUser);
104+
105+
if (!result.Succeeded)
106+
return GetErrorResult(result);
107+
108+
return Ok();
109+
}
110+
}
111+
}

personal_site_api/Controllers/BaseApiController.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using Microsoft.AspNet.Identity;
2+
using Microsoft.AspNet.Identity.Owin;
3+
using personal_site_api.Infrastructure;
24
using personal_site_api.Models;
35
using System;
46
using System.Collections.Generic;
@@ -9,17 +11,29 @@
911

1012
namespace personal_site_api.Controllers
1113
{
14+
//extended by account controller
1215
public class BaseApiController : ApiController
1316
{
1417
private ModelFactory _modelFactory;
18+
private ApplicationUserManager _AppUserManager = null;
19+
20+
protected ApplicationUserManager AppUserManager
21+
{
22+
get
23+
{
24+
return _AppUserManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
25+
}
26+
}
27+
28+
public BaseApiController() { }
1529

1630
protected ModelFactory TheModelFactory
1731
{
1832
get
1933
{
2034
if (_modelFactory == null)
2135
{
22-
_modelFactory = new ModelFactory(Request);
36+
_modelFactory = new ModelFactory(Request, AppUserManager);
2337
}
2438
return _modelFactory;
2539
}

personal_site_api/Dtos/UserDto.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Web;
5+
6+
namespace personal_site_api.Dtos
7+
{
8+
//used in ModelFactory
9+
public class UserDto
10+
{
11+
public string Url { get; set; }
12+
public string Id { get; set; }
13+
public string UserName { get; set; }
14+
public string Email { get; set; }
15+
public IList<string> Roles { get; set; }
16+
}
17+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using Microsoft.AspNet.Identity;
2+
using Microsoft.AspNet.Identity.EntityFramework;
3+
using Microsoft.AspNet.Identity.Owin;
4+
using Microsoft.Owin;
5+
using personal_site_api.Services;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Web;
10+
11+
namespace personal_site_api.Infrastructure
12+
{
13+
public class ApplicationUserManager : UserManager<ApplicationUser>
14+
{
15+
public ApplicationUserManager(IUserStore<ApplicationUser> store)
16+
: base(store)
17+
{
18+
}
19+
20+
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
21+
{
22+
var appDbContext = context.Get<ApplicationDbContext>();
23+
var appUserManager = new ApplicationUserManager(new UserStore<ApplicationUser>(appDbContext));
24+
25+
//username validation
26+
appUserManager.UserValidator = new UserValidator<ApplicationUser>(appUserManager) {
27+
AllowOnlyAlphanumericUserNames = true,
28+
RequireUniqueEmail = true
29+
};
30+
31+
//password validation
32+
appUserManager.PasswordValidator = new PasswordValidator
33+
{
34+
RequiredLength = 6,
35+
RequireNonLetterOrDigit = false,
36+
RequireDigit = true,
37+
RequireLowercase = true,
38+
RequireUppercase = true
39+
};
40+
41+
42+
//hook up email service in Services folder
43+
appUserManager.EmailService = new EmailService();
44+
45+
var dataProtectionProvider = options.DataProtectionProvider;
46+
if(dataProtectionProvider != null)
47+
{
48+
appUserManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"))
49+
{
50+
//code for email confirmation and reset password lifetime
51+
TokenLifespan = TimeSpan.FromHours(6)
52+
};
53+
}
54+
55+
return appUserManager;
56+
}
57+
}
58+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel.DataAnnotations;
4+
using System.Linq;
5+
using System.Web;
6+
7+
namespace personal_site_api.Models
8+
{
9+
public class AccountBindingModels
10+
{
11+
public class CreateUserBindingModel
12+
{
13+
[Required]
14+
[EmailAddress]
15+
[Display(Name = "Email")]
16+
public string Email { get; set; }
17+
18+
[Required]
19+
[Display(Name = "Username")]
20+
public string Username { get; set; }
21+
22+
[Display(Name = "Role Name")]
23+
public string RoleName { get; set; }
24+
25+
[Required]
26+
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
27+
[DataType(DataType.Password)]
28+
[Display(Name = "Password")]
29+
public string Password { get; set; }
30+
31+
[Required]
32+
[DataType(DataType.Password)]
33+
[Display(Name = "Confirm Password")]
34+
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
35+
public string ConfirmPassword { get; set; }
36+
}
37+
38+
public class ChangePasswordBindingModel
39+
{
40+
[Required]
41+
[DataType(DataType.Password)]
42+
[Display(Name = "Current Password")]
43+
public string OldPassword { get; set; }
44+
45+
[Required]
46+
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
47+
[DataType(DataType.Password)]
48+
[Display(Name = "New Password")]
49+
public string NewPassword { get; set; }
50+
51+
[Required]
52+
[DataType(DataType.Password)]
53+
[Display(Name = "Confirm Password")]
54+
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
55+
public string ConfirmPassword { get; set; }
56+
}
57+
}
58+
}
Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using System;
1+
using personal_site_api.Dtos;
2+
using personal_site_api.Infrastructure;
3+
using System;
24
using System.Collections.Generic;
35
using System.Net.Http;
46
using System.Web.Http.Routing;
@@ -8,10 +10,25 @@ namespace personal_site_api.Models
810
public class ModelFactory
911
{
1012
private UrlHelper _UrlHelper;
13+
private ApplicationUserManager _AppUserManager;
1114

12-
public ModelFactory(HttpRequestMessage request)
15+
//called in BaseApiController
16+
public ModelFactory(HttpRequestMessage request, ApplicationUserManager appUserManager)
1317
{
1418
_UrlHelper = new UrlHelper(request);
19+
_AppUserManager = appUserManager;
20+
}
21+
22+
public UserDto Create(ApplicationUser appUser)
23+
{
24+
return new UserDto
25+
{
26+
Url = _UrlHelper.Link("GetUserById", new { id = appUser.Id }),
27+
Id = appUser.Id,
28+
UserName = appUser.UserName,
29+
Email = appUser.Email,
30+
Roles = _AppUserManager.GetRolesAsync(appUser.Id).Result
31+
};
1532
}
1633
}
1734
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using Microsoft.AspNet.Identity;
2+
using SendGrid;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Configuration;
6+
using System.Linq;
7+
using System.Net;
8+
using System.Threading.Tasks;
9+
using System.Web;
10+
11+
namespace personal_site_api.Services
12+
{
13+
public class EmailService : IIdentityMessageService
14+
{
15+
public async Task SendAsync(IdentityMessage message) {
16+
await configSendGridAsync(message);
17+
}
18+
19+
public async Task configSendGridAsync(IdentityMessage message)
20+
{
21+
var myMessage = new SendGridMessage();
22+
23+
myMessage.AddTo(message.Destination);
24+
myMessage.From = new System.Net.Mail.MailAddress("craigbartjr@gmail.com", "Craig Bartholomew");
25+
myMessage.Subject = message.Subject;
26+
myMessage.Text = message.Body;
27+
myMessage.Html = message.Body;
28+
29+
var credentials = new NetworkCredential(ConfigurationManager.AppSettings["emailService:Username"],
30+
ConfigurationManager.AppSettings["emailService:Password"]);
31+
32+
var transportWeb = new Web(credentials);
33+
34+
if (transportWeb != null)
35+
{
36+
//send email
37+
await transportWeb.DeliverAsync(myMessage);
38+
} else
39+
{
40+
//errors
41+
await Task.FromResult(0);
42+
}
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)