-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16 from umbraco/members
Added macros and Controllers for login and register
- Loading branch information
Showing
10 changed files
with
416 additions
and
9 deletions.
There are no files selected for viewing
180 changes: 180 additions & 0 deletions
180
Umbraco.Docs.Samples.Web/Controllers/UmbAlternativeRegisterController.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Identity; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Umbraco.Cms.Core.Cache; | ||
using Umbraco.Cms.Core.Logging; | ||
using Umbraco.Cms.Core.Models; | ||
using Umbraco.Cms.Core.Routing; | ||
using Umbraco.Cms.Core.Scoping; | ||
using Umbraco.Cms.Core.Security; | ||
using Umbraco.Cms.Core.Services; | ||
using Umbraco.Cms.Core.Web; | ||
using Umbraco.Cms.Infrastructure.Persistence; | ||
using Umbraco.Cms.Web.Common.Filters; | ||
using Umbraco.Cms.Web.Common.Security; | ||
using Umbraco.Cms.Web.Website.Controllers; | ||
using Umbraco.Cms.Web.Website.Models; | ||
|
||
namespace Umbraco.Docs.Samples.Web.Controllers | ||
{ | ||
public class UmbAlternativeRegisterController : SurfaceController | ||
{ | ||
private readonly IMemberManager _memberManager; | ||
private readonly IMemberService _memberService; | ||
private readonly IMemberSignInManager _memberSignInManager; | ||
private readonly ICoreScopeProvider _coreScopeProvider; | ||
|
||
public UmbAlternativeRegisterController( | ||
IMemberManager memberManager, | ||
IMemberService memberService, | ||
IUmbracoContextAccessor umbracoContextAccessor, | ||
IUmbracoDatabaseFactory databaseFactory, | ||
ServiceContext services, | ||
AppCaches appCaches, | ||
IProfilingLogger profilingLogger, | ||
IPublishedUrlProvider publishedUrlProvider, | ||
IMemberSignInManager memberSignInManager, | ||
ICoreScopeProvider coreScopeProvider) | ||
: base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) | ||
{ | ||
_memberManager = memberManager; | ||
_memberService = memberService; | ||
_memberSignInManager = memberSignInManager; | ||
_coreScopeProvider = coreScopeProvider; | ||
} | ||
|
||
[HttpPost] | ||
[ValidateAntiForgeryToken] | ||
[ValidateUmbracoFormRouteString] | ||
public async Task<IActionResult> HandleRegisterMember([Bind(Prefix = "registerModel")] RegisterModel model) | ||
{ | ||
if (ModelState.IsValid == false) | ||
{ | ||
return CurrentUmbracoPage(); | ||
} | ||
|
||
MergeRouteValuesToModel(model); | ||
|
||
IdentityResult result = await RegisterMemberAsync(model); | ||
if (result.Succeeded) | ||
{ | ||
TempData["FormSuccess"] = true; | ||
|
||
|
||
if (model.RedirectUrl.IsNullOrWhiteSpace() == false) | ||
{ | ||
return Redirect(model.RedirectUrl!); | ||
} | ||
|
||
|
||
return RedirectToCurrentUmbracoPage(); | ||
} | ||
|
||
AddErrors(result); | ||
return CurrentUmbracoPage(); | ||
} | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <param name="model"></param> | ||
private void MergeRouteValuesToModel(RegisterModel model) | ||
{ | ||
if (RouteData.Values.TryGetValue(nameof(RegisterModel.RedirectUrl), out var redirectUrl) && redirectUrl != null) | ||
{ | ||
model.RedirectUrl = redirectUrl.ToString(); | ||
} | ||
|
||
if (RouteData.Values.TryGetValue(nameof(RegisterModel.MemberTypeAlias), out var memberTypeAlias) && | ||
memberTypeAlias != null) | ||
{ | ||
model.MemberTypeAlias = memberTypeAlias.ToString()!; | ||
} | ||
|
||
if (RouteData.Values.TryGetValue(nameof(RegisterModel.UsernameIsEmail), out var usernameIsEmail) && | ||
usernameIsEmail != null) | ||
{ | ||
model.UsernameIsEmail = usernameIsEmail.ToString() == "True"; | ||
} | ||
} | ||
|
||
private void AddErrors(IdentityResult result) | ||
{ | ||
foreach (IdentityError? error in result.Errors) | ||
{ | ||
ModelState.AddModelError("registerModel", error.Description); | ||
} | ||
} | ||
|
||
//Here we created a helper Method to assign a MemberGroup to a member. | ||
private void AssignMemberGroup(string email, string group) | ||
{ | ||
try | ||
{ | ||
_memberService.AssignRole(email, group); | ||
} | ||
catch (Exception ex) | ||
{ | ||
//handle the exception | ||
} | ||
|
||
} | ||
|
||
|
||
/// <summary> | ||
|
||
/// </summary> | ||
/// <param name="model">Register member model.</param> | ||
/// <param name="logMemberIn">Flag for whether to log the member in upon successful registration.</param> | ||
/// <returns>Result of registration operation.</returns> | ||
private async Task<IdentityResult> RegisterMemberAsync(RegisterModel model, bool logMemberIn = true) | ||
{ | ||
using ICoreScope scope = _coreScopeProvider.CreateCoreScope(autoComplete: true); | ||
|
||
|
||
if (string.IsNullOrEmpty(model.Name) && string.IsNullOrEmpty(model.Email) == false) | ||
{ | ||
model.Name = model.Email; | ||
} | ||
|
||
model.Username = model.UsernameIsEmail || model.Username == null ? model.Email : model.Username; | ||
|
||
var identityUser = | ||
MemberIdentityUser.CreateNew(model.Username, model.Email, model.MemberTypeAlias, true, model.Name); | ||
IdentityResult identityResult = await _memberManager.CreateAsync( | ||
identityUser, | ||
model.Password); | ||
|
||
if (identityResult.Succeeded) | ||
{ | ||
|
||
IMember? member = _memberService.GetByKey(identityUser.Key); | ||
if (member == null) | ||
{ | ||
|
||
throw new InvalidOperationException($"Could not find a member with key: {member?.Key}."); | ||
} | ||
|
||
foreach (MemberPropertyModel property in model.MemberProperties.Where(p => p.Value != null).Where(property => member.Properties.Contains(property.Alias))) | ||
{ | ||
member.Properties[property.Alias]?.SetValue(property.Value); | ||
} | ||
|
||
//Before we save the member we make sure to assign the group, for this the "Group" must exist in the backoffice. | ||
string memberGroup = "professionals"; | ||
AssignMemberGroup(model.Email, memberGroup); | ||
|
||
_memberService.Save(member); | ||
|
||
if (logMemberIn) | ||
{ | ||
await _memberSignInManager.SignInAsync(identityUser, false); | ||
} | ||
} | ||
|
||
return identityResult; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
Umbraco.Docs.Samples.Web/Views/MacroPartials/Login.cshtml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
@inherits Umbraco.Cms.Web.Common.Macros.PartialViewMacroPage | ||
|
||
|
||
@using Umbraco.Cms.Web.Common.Models | ||
@using Umbraco.Cms.Web.Common.Security | ||
@using Umbraco.Cms.Web.Website.Controllers | ||
@using Umbraco.Cms.Core.Services | ||
@using Umbraco.Extensions | ||
@inject IMemberExternalLoginProviders memberExternalLoginProviders | ||
@inject ITwoFactorLoginService twoFactorLoginService | ||
@{ | ||
var loginModel = new LoginModel(); | ||
// You can modify this to redirect to a different URL instead of the current one | ||
loginModel.RedirectUrl = null; | ||
} | ||
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.0/jquery.validate.min.js"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script> | ||
|
||
|
||
@if (ViewData.TryGetTwoFactorProviderNames(out var providerNames)) | ||
{ | ||
|
||
foreach (var providerName in providerNames) | ||
{ | ||
<div class="2fa-form"> | ||
<h4>Two factor with @providerName.</h4> | ||
<div asp-validation-summary="All" class="text-danger"></div> | ||
@using (Html.BeginUmbracoForm<UmbTwoFactorLoginController>(nameof(UmbTwoFactorLoginController.Verify2FACode))) | ||
{ | ||
|
||
<text> | ||
<input type="hidden" name="provider" value="@providerName"/> | ||
Input security code: <input name="code" value=""/><br/> | ||
<button type="submit" class="btn btn-primary">Validate</button> | ||
<div asp-validation-summary="ModelOnly" class="text-danger"></div> | ||
</text> | ||
} | ||
</div> | ||
} | ||
|
||
} | ||
else | ||
{ | ||
|
||
|
||
<div class="login-form"> | ||
|
||
@using (Html.BeginUmbracoForm<UmbLoginController>( | ||
"HandleLogin", new { RedirectUrl = loginModel.RedirectUrl })) { | ||
|
||
<h4>Log in with a local account.</h4> | ||
<hr /> | ||
<div asp-validation-summary="ModelOnly" class="text-danger"></div> | ||
<div class="mb-3"> | ||
<label asp-for="@loginModel.Username" class="form-label"></label> | ||
<input asp-for="@loginModel.Username" class="form-control" /> | ||
<span asp-validation-for="@loginModel.Username" class="form-text text-danger"></span> | ||
</div> | ||
<div class="mb-3"> | ||
<label asp-for="@loginModel.Password" class="form-label"></label> | ||
<input asp-for="@loginModel.Password" class="form-control" /> | ||
<span asp-validation-for="@loginModel.Password" class="form-text text-danger"></span> | ||
</div> | ||
<div class="mb-3 form-check"> | ||
<input asp-for="@loginModel.RememberMe" class="form-check-input"> | ||
<label asp-for="@loginModel.RememberMe" class="form-check-label"> | ||
@Html.DisplayNameFor(m => loginModel.RememberMe) | ||
</label> | ||
</div> | ||
|
||
<button type="submit" class="btn btn-primary">Log in</button> | ||
|
||
|
||
} | ||
@{ | ||
var loginProviders = await memberExternalLoginProviders.GetMemberProvidersAsync(); | ||
var externalSignInError = ViewData.GetExternalSignInProviderErrors(); | ||
|
||
if (loginProviders.Any()) | ||
{ | ||
<hr/> | ||
<h4>Or using external providers</h4> | ||
if (externalSignInError?.AuthenticationType is null && externalSignInError?.Errors.Any() == true) | ||
{ | ||
@Html.DisplayFor(x => externalSignInError.Errors); | ||
} | ||
|
||
@foreach (var login in await memberExternalLoginProviders.GetMemberProvidersAsync()) | ||
{ | ||
|
||
@using (Html.BeginUmbracoForm<UmbExternalLoginController>(nameof(UmbExternalLoginController.ExternalLogin))) | ||
{ | ||
<button type="submit" name="provider" value="@login.ExternalLoginProvider.AuthenticationType"> | ||
Sign in with @login.AuthenticationScheme.DisplayName | ||
</button> | ||
|
||
if (externalSignInError?.AuthenticationType == login.ExternalLoginProvider.AuthenticationType) | ||
{ | ||
@Html.DisplayFor(x => externalSignInError.Errors); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
</div> | ||
} |
Oops, something went wrong.