Complete account creation process
This commit is contained in:
parent
13ed90803c
commit
007d56ee32
|
@ -16,11 +16,34 @@ using System.IO;
|
||||||
using Org.BouncyCastle.Crypto;
|
using Org.BouncyCastle.Crypto;
|
||||||
using Org.BouncyCastle.OpenSsl;
|
using Org.BouncyCastle.OpenSsl;
|
||||||
using Org.BouncyCastle.Security;
|
using Org.BouncyCastle.Security;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
|
||||||
namespace FIT5032_Assignment.Controllers
|
namespace FIT5032_Assignment.Controllers
|
||||||
{
|
{
|
||||||
|
// Endpoint Response
|
||||||
|
public class PassageUserReply
|
||||||
|
{
|
||||||
|
public PassageUserReplyUser User { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PassageUserReplyUser
|
||||||
|
{
|
||||||
|
public string Email { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Database
|
||||||
|
public class Database1Entities : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<Users> Users { get; set; }
|
||||||
|
public DbSet<Credentials> Credentials { get; set; }
|
||||||
|
public DbSet<Sessions> Sessions { get; set; }
|
||||||
|
}
|
||||||
public class HomeController : Controller
|
public class HomeController : Controller
|
||||||
{
|
{
|
||||||
|
private static readonly HttpClient httpClient = new HttpClient();
|
||||||
public static RsaSecurityKey LoadRsaSecurityKeyFromPem(string pem)
|
public static RsaSecurityKey LoadRsaSecurityKeyFromPem(string pem)
|
||||||
{
|
{
|
||||||
TextReader textReader = new StringReader(pem);
|
TextReader textReader = new StringReader(pem);
|
||||||
|
@ -102,6 +125,15 @@ namespace FIT5032_Assignment.Controllers
|
||||||
return new string(bytes.Select(x => validChars[x % validChars.Length]).ToArray());
|
return new string(bytes.Select(x => validChars[x % validChars.Length]).ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HomeController()
|
||||||
|
{
|
||||||
|
// if auth token setted, ignore
|
||||||
|
if (httpClient.DefaultRequestHeaders.Authorization == null)
|
||||||
|
{
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "vF4ch1wUf8.1cqOms9JMmUbqMGohlkJLzGDVlbF51D03fJnLfxwkn8kyAaVVjfvySufW9vXb3p3");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ActionResult Index()
|
public ActionResult Index()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
|
@ -125,41 +157,51 @@ namespace FIT5032_Assignment.Controllers
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Trace.WriteLine(sub);
|
var db = new Database1Entities();
|
||||||
|
var credential = db.Credentials.Where(res => (res.uniqueIdCode == sub) && (res.provider == 0));
|
||||||
|
// Register: if no credential, redirect to create account
|
||||||
|
if (credential.Count() == 0)
|
||||||
|
{
|
||||||
|
return RedirectToAction("CompleteProfile");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Successful login
|
||||||
|
return RedirectToAction("Index");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return View();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /CreateAccount
|
// POST /ComplteteProfile
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public ActionResult CreateAccount(Models.CreateAccountForm model)
|
public async Task<ActionResult> CompleteProfile(Models.CompleteProfileForm model)
|
||||||
{
|
{
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError("emailaddress", "Form not valid");
|
ModelState.AddModelError("fullname", "Form not valid");
|
||||||
return View(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Email address is not valid
|
|
||||||
// Use regular expression to verify email address
|
|
||||||
if (!System.Text.RegularExpressions.Regex.IsMatch(model.emailaddress, @"^([a-zA-Z0-9]|\-|_|\.){1,}@([a-zA-Z0-9]|\-|_|){1,}(\.([a-zA-Z0-9]|\-|_){1,}){1,}$"))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("emailaddress", "Email address is not valid");
|
|
||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If email address existed in database
|
// Verify user is logged in
|
||||||
var users = db.Credentials.Where(res => (res.uniqueIdCode == model.emailaddress) && (res.provider == 0));
|
var psg_auth_token = Request.Cookies["psg_auth_token"];
|
||||||
if (users.Count() > 0)
|
var user = loginVerify(psg_auth_token.Value);
|
||||||
|
if (user == null)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError("emailaddress", "Email address existed");
|
return RedirectToAction("Login");
|
||||||
return View(model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get users email from Passage API
|
||||||
|
var app_id = "ZHM5whW5xsZEczTn2loffzjN";
|
||||||
|
var user_id = user;
|
||||||
|
var url = $"https://api.passage.id/v1/apps/{app_id}/users/{user_id}";
|
||||||
|
Trace.WriteLine(url);
|
||||||
|
Trace.WriteLine(httpClient.DefaultRequestHeaders.Authorization);
|
||||||
|
var res = await httpClient.GetStringAsync(url);
|
||||||
|
string emailaddress = JsonConvert.DeserializeObject<PassageUserReply>(res).User.Email;
|
||||||
|
|
||||||
// MD5 hash email to get avatar from gravatar
|
// MD5 hash email to get avatar from gravatar
|
||||||
var md5 = MD5.Create();
|
var md5 = MD5.Create();
|
||||||
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(model.emailaddress);
|
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(emailaddress);
|
||||||
byte[] hash = md5.ComputeHash(inputBytes);
|
byte[] hash = md5.ComputeHash(inputBytes);
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (int i = 0; i < hash.Length; i++)
|
for (int i = 0; i < hash.Length; i++)
|
||||||
|
@ -170,7 +212,7 @@ namespace FIT5032_Assignment.Controllers
|
||||||
|
|
||||||
// Create a new credential and a new user
|
// Create a new credential and a new user
|
||||||
string userUuid = Guid.NewGuid().ToString();
|
string userUuid = Guid.NewGuid().ToString();
|
||||||
Users user = new Users
|
Users newDbUser = new Users
|
||||||
{
|
{
|
||||||
uuid = userUuid,
|
uuid = userUuid,
|
||||||
displayName = model.fullname,
|
displayName = model.fullname,
|
||||||
|
@ -181,47 +223,27 @@ namespace FIT5032_Assignment.Controllers
|
||||||
{
|
{
|
||||||
uuid = Guid.NewGuid().ToString(),
|
uuid = Guid.NewGuid().ToString(),
|
||||||
user = userUuid,
|
user = userUuid,
|
||||||
uniqueIdCode = model.emailaddress,
|
uniqueIdCode = user_id,
|
||||||
provider = 0,
|
provider = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Assign a new session for user
|
|
||||||
// Generate 32-bit random string as session token
|
|
||||||
string token = GenerateRandomString(32);
|
|
||||||
|
|
||||||
// Use bcrypt to hash token
|
|
||||||
string hashedToken = BCryptNet.HashPassword(token);
|
|
||||||
|
|
||||||
string sessionUuid = Guid.NewGuid().ToString();
|
|
||||||
|
|
||||||
Sessions session = new Sessions
|
|
||||||
{
|
|
||||||
uuid = sessionUuid,
|
|
||||||
user = userUuid,
|
|
||||||
token = token,
|
|
||||||
alias = "Web",
|
|
||||||
validFrom = DateTime.Now,
|
|
||||||
validTo = DateTime.Now.AddDays(7)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add them into database
|
// Add them into database
|
||||||
db.Users.Add(user);
|
db.Users.Add(newDbUser);
|
||||||
db.Credentials.Add(credential);
|
db.Credentials.Add(credential);
|
||||||
db.Sessions.Add(session);
|
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
|
|
||||||
// write cookie (`session`)
|
return RedirectToAction("Index");
|
||||||
HttpCookie cookie1 = new HttpCookie("session", sessionUuid + ":" + token);
|
|
||||||
cookie1.Expires = DateTime.Now.AddDays(7);
|
|
||||||
Response.Cookies.Add(cookie1);
|
|
||||||
|
|
||||||
return RedirectToAction("InitialPasskey");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult InitialPasskey()
|
public ActionResult InitialPasskey()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ActionResult CompleteProfile()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -188,7 +188,7 @@
|
||||||
<Compile Include="Models\Appointments.cs">
|
<Compile Include="Models\Appointments.cs">
|
||||||
<DependentUpon>FIT5032-Assignment.tt</DependentUpon>
|
<DependentUpon>FIT5032-Assignment.tt</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Models\CreateAccountForm.cs" />
|
<Compile Include="Models\CompleteProfileForm.cs" />
|
||||||
<Compile Include="Models\Credentials.cs">
|
<Compile Include="Models\Credentials.cs">
|
||||||
<DependentUpon>FIT5032-Assignment.tt</DependentUpon>
|
<DependentUpon>FIT5032-Assignment.tt</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -308,6 +308,7 @@
|
||||||
<Content Include="Views\Test.cshtml" />
|
<Content Include="Views\Test.cshtml" />
|
||||||
<Content Include="Views\Home\InitialPasskey.cshtml" />
|
<Content Include="Views\Home\InitialPasskey.cshtml" />
|
||||||
<Content Include="Views\Home\LoginRedirect.cshtml" />
|
<Content Include="Views\Home\LoginRedirect.cshtml" />
|
||||||
|
<Content Include="Views\Home\CompleteProfile.cshtml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Views\Test\" />
|
<Folder Include="Views\Test\" />
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
<WebStackScaffolding_ControllerDialogWidth>600</WebStackScaffolding_ControllerDialogWidth>
|
<WebStackScaffolding_ControllerDialogWidth>600</WebStackScaffolding_ControllerDialogWidth>
|
||||||
<WebStackScaffolding_LayoutPageFile>
|
<WebStackScaffolding_LayoutPageFile>
|
||||||
</WebStackScaffolding_LayoutPageFile>
|
</WebStackScaffolding_LayoutPageFile>
|
||||||
<WebStackScaffolding_IsLayoutPageSelected>False</WebStackScaffolding_IsLayoutPageSelected>
|
<WebStackScaffolding_IsLayoutPageSelected>True</WebStackScaffolding_IsLayoutPageSelected>
|
||||||
<WebStackScaffolding_IsPartialViewSelected>False</WebStackScaffolding_IsPartialViewSelected>
|
<WebStackScaffolding_IsPartialViewSelected>False</WebStackScaffolding_IsPartialViewSelected>
|
||||||
<WebStackScaffolding_IsReferencingScriptLibrariesSelected>False</WebStackScaffolding_IsReferencingScriptLibrariesSelected>
|
<WebStackScaffolding_IsReferencingScriptLibrariesSelected>True</WebStackScaffolding_IsReferencingScriptLibrariesSelected>
|
||||||
<WebStackScaffolding_DbContextTypeFullName>FIT5032_Assignment.Models.Database1Entities</WebStackScaffolding_DbContextTypeFullName>
|
<WebStackScaffolding_DbContextTypeFullName>FIT5032_Assignment.Models.Database1Entities</WebStackScaffolding_DbContextTypeFullName>
|
||||||
<WebStackScaffolding_IsViewGenerationSelected>False</WebStackScaffolding_IsViewGenerationSelected>
|
<WebStackScaffolding_IsViewGenerationSelected>False</WebStackScaffolding_IsViewGenerationSelected>
|
||||||
<WebStackScaffolding_IsAsyncSelected>False</WebStackScaffolding_IsAsyncSelected>
|
<WebStackScaffolding_IsAsyncSelected>False</WebStackScaffolding_IsAsyncSelected>
|
||||||
|
|
|
@ -6,12 +6,8 @@ using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace FIT5032_Assignment.Models
|
namespace FIT5032_Assignment.Models
|
||||||
{
|
{
|
||||||
public class CreateAccountForm
|
public class CompleteProfileForm
|
||||||
{
|
{
|
||||||
[Required]
|
|
||||||
[Display(Name = "Email address")]
|
|
||||||
public string emailaddress { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
[Display(Name = "Full name")]
|
[Display(Name = "Full name")]
|
||||||
public string fullname { get; set; }
|
public string fullname { get; set; }
|
49
FIT5032-Assignment/Views/Home/CompleteProfile.cshtml
Normal file
49
FIT5032-Assignment/Views/Home/CompleteProfile.cshtml
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
@model FIT5032_Assignment.Models.CompleteProfileForm
|
||||||
|
|
||||||
|
@{
|
||||||
|
ViewBag.Title = "CompleteProfile";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>CompleteProfile</h2>
|
||||||
|
|
||||||
|
|
||||||
|
@using (Html.BeginForm())
|
||||||
|
{
|
||||||
|
@Html.AntiForgeryToken()
|
||||||
|
|
||||||
|
<div class="form-horizontal">
|
||||||
|
<h4>CompleteProfileForm</h4>
|
||||||
|
<hr />
|
||||||
|
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
|
||||||
|
<div class="form-group">
|
||||||
|
@Html.LabelFor(model => model.fullname, htmlAttributes: new { @class = "control-label col-md-2" })
|
||||||
|
<div class="col-md-10">
|
||||||
|
@Html.EditorFor(model => model.fullname, new { htmlAttributes = new { @class = "form-control" } })
|
||||||
|
@Html.ValidationMessageFor(model => model.fullname, "", new { @class = "text-danger" })
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
@Html.LabelFor(model => model.role, htmlAttributes: new { @class = "control-label col-md-2" })
|
||||||
|
<div class="col-md-10">
|
||||||
|
<!--Dropdown Menu-->
|
||||||
|
@Html.DropDownListFor(model => model.role, new List<SelectListItem>
|
||||||
|
{
|
||||||
|
new SelectListItem{ Text="Patient", Value = "1"},
|
||||||
|
new SelectListItem{ Text="Doctor", Value = "2"}
|
||||||
|
}, "Select Role", new { @class = "form-control" })
|
||||||
|
@Html.ValidationMessageFor(model => model.role, "", new { @class = "text-danger" })
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-offset-2 col-md-10">
|
||||||
|
<input type="submit" value="Create" class="btn btn-default" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@Scripts.Render("~/bundles/jqueryval")
|
||||||
|
}
|
|
@ -1,6 +1,4 @@
|
||||||
@model FIT5032_Assignment.Models.CreateAccountForm
|
@{
|
||||||
|
|
||||||
@{
|
|
||||||
ViewBag.Title = "CreateAccount";
|
ViewBag.Title = "CreateAccount";
|
||||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user