Skip to content

Commit

Permalink
Adding a HttpContextPrincipalResolver and testpages
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurzaczek committed Jan 24, 2022
1 parent a5591f4 commit 3b4d917
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 2 deletions.
8 changes: 8 additions & 0 deletions Zetbox.Client.ASPNET.Toolkit/AspNetClientModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
// You should have received a copy of the GNU Lesser General Public
// License along with zetbox. If not, see <http://www.gnu.org/licenses/>.

using Microsoft.AspNetCore.Http;
using Zetbox.Client.ASPNET.Toolkit;

namespace Zetbox.Client.ASPNET
{
using System;
Expand Down Expand Up @@ -130,6 +133,11 @@ protected override void Load(ContainerBuilder moduleBuilder)
.As<IProblemReporter>()
.SingleInstance();

moduleBuilder
.Register<HttpContextPrincipalResolver>(c => new HttpContextPrincipalResolver(c.Resolve<ILifetimeScope>(), c.Resolve<IHttpContextAccessor>()))
.As<IPrincipalResolver>()
.SingleInstance();

moduleBuilder
.Register<ZetboxContextHttpScope>(c => new ZetboxContextHttpScope(c.Resolve<IZetboxContext>()))
.InstancePerLifetimeScope();
Expand Down
30 changes: 30 additions & 0 deletions Zetbox.Client.ASPNET.Toolkit/HttpContextPrincipalResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
using Autofac;
using Microsoft.AspNetCore.Http;
using Zetbox.API;
using Zetbox.API.Common;

namespace Zetbox.Client.ASPNET.Toolkit
{
public class HttpContextPrincipalResolver : BasePrincipalResolver
{
private readonly IHttpContextAccessor _httpContextAccessor;

public HttpContextPrincipalResolver(ILifetimeScope parentScope, IHttpContextAccessor httpContextAccessor) : base(parentScope)
{
_httpContextAccessor = httpContextAccessor;
}

public override ZetboxPrincipal GetCurrent()
{
if (!string.IsNullOrEmpty(_httpContextAccessor.HttpContext?.User?.Identity?.Name))
return Resolve(_httpContextAccessor.HttpContext?.User?.Identity);
else
return null;
}
}
}
6 changes: 6 additions & 0 deletions Zetbox.Client.ASPNET.Toolkit/ZetboxStartup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Zetbox.API;
using Zetbox.API.Configuration;
using Zetbox.API.Utils;
Expand Down Expand Up @@ -36,6 +38,10 @@ public virtual void ConfigureServices(IServiceCollection services)

OnConfigureControllersWithViews(options);
});

services.AddHttpContextAccessor();
// TODO: Is there a "official" extension method?
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
}

protected virtual void OnConfigureControllersWithViews(MvcOptions options)
Expand Down
114 changes: 114 additions & 0 deletions Zetbox.Client.ASPNET/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using log4net;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Zetbox.API;
using Zetbox.API.Server;
using Zetbox.App.Base;
using Zetbox.App.Extensions;
using Zetbox.Client.Presentables;
using DataType = System.ComponentModel.DataAnnotations.DataType;

namespace Zetbox.Client.ASPNET.Controllers
{
public class LoginModel
{
[Required]
[Display(Name = "Benutzername")]
public string UserName { get; set; }

[Required]
[DataType(DataType.Password)]
[Display(Name = "Passwort")]
public string Password { get; set; }

[Display(Name = "Eingeloggt bleiben?")]
public bool RememberMe { get; set; }
}

[Authorize]
public class AccountController: ZetboxController
{
private static readonly ILog _log = LogManager.GetLogger(typeof(AccountController));

private readonly Func<IZetboxContext> _ctxFactory;
private readonly Func<IZetboxServerContext> _srvCtxFactory;

public AccountController(IViewModelFactory vmf, ZetboxContextHttpScope contextScope, Func<IZetboxContext> ctxFactory, Func<IZetboxServerContext> srvCtxFactory)
: base(vmf, contextScope)
{
_ctxFactory = ctxFactory;
_srvCtxFactory = srvCtxFactory;
}

//
// GET: /Account/Login

[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}

//
// POST: /Account/Login

[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var zbIdentity = DataContext.GetQuery<Identity>().SingleOrDefault(i => i.UserName.ToLower() == model.UserName.ToLower());
if (zbIdentity == null)
{
ModelState.AddModelError("", "Kein Eintrag unter diesem Benutzernamen und Passwort gefunden.");
return View(model);
}

if (string.IsNullOrWhiteSpace(zbIdentity.Password))
{
ModelState.AddModelError("", "Kein Eintrag unter diesem Benutzernamen und Passwort gefunden.");
return View(model);
}

if (!BCrypt.Net.BCrypt.Verify(model.Password, zbIdentity.Password) == true)
{
ModelState.AddModelError("", "Kein Eintrag unter diesem Benutzernamen und Passwort gefunden.");
return View(model);
}

_log.InfoFormat("User {0} logged in", model.UserName);
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, model.UserName),
new Claim("FullName", zbIdentity.DisplayName.IfNullOrWhiteSpace(model.UserName)),
};

var claimsIdentity = new ClaimsIdentity(
claims, CookieAuthenticationDefaults.AuthenticationScheme);

var authProperties = new AuthenticationProperties { };

await HttpContext.SignInAsync(new ClaimsPrincipal(claimsIdentity), authProperties);
return Redirect("/");
}

_log.WarnFormat("User {0} failed logging in", model.UserName);
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "Kein Eintrag unter diesem Benutzernamen und Passwort gefunden.");
return View(model);
}
}
}
9 changes: 9 additions & 0 deletions Zetbox.Client.ASPNET/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Threading.Tasks;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.ModelBinding;
Expand Down Expand Up @@ -33,6 +34,13 @@ public Startup(IConfiguration configuration, IWebHostEnvironment env) : base(con
public override void ConfigureServices(IServiceCollection services)
{
base.ConfigureServices(services);

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.LoginPath = "/account/login";
});

}

public override void ConfigureContainer(ContainerBuilder builder)
Expand All @@ -59,6 +67,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
Expand Down
46 changes: 46 additions & 0 deletions Zetbox.Client.ASPNET/Views/Account/Login.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
@model Zetbox.Client.ASPNET.Controllers.LoginModel
@using Zetbox.Client.ASPNET

@{
ViewBag.Title = "Anmelden";
}

<h1>@ViewBag.Title</h1>
<div class="row">
<div class="col-md-8">
<section id="loginForm">
@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, false, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
@Html.BootstrapValidationSummary(excludePropertyErrors: true)
<div class="form-group">
@Html.LabelFor(m => m.UserName, new { @class = "col-md-3 control-label" })
<div class="col-md-9">
@Html.TextBoxFor(m => m.UserName, new { @class = "form-control autofocus" })
@Html.ValidationMessageFor(m => m.UserName)
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.Password, new { @class = "col-md-3 control-label" })
<div class="col-md-9">
@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Password)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-3 col-md-9">
<div class="checkbox">
@Html.CheckBoxFor(m => m.RememberMe)
@Html.LabelFor(m => m.RememberMe)
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-3 col-md-9">
<input type="submit" value="Log in" class="btn btn-primary" rel="nofollow" />
</div>
</div>
}
</section>
</div>
</div>
22 changes: 22 additions & 0 deletions Zetbox.Client.ASPNET/Views/Projekt/Edit.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@model Zetbox.Client.ASPNET.ViewModels.MvcProjektViewModel

@{
ViewData["Title"] = "Edit a Project";
}

<h1>@ViewBag.Title</h1>

@using (Html.BeginForm("Edit", "Projekt", FormMethod.Post, new { @class = "form-horizontal" }))
{
@Html.AntiForgeryToken()
@Html.BootstrapValidationSummary()
@Html.ZbHiddenID(Model.ID)
@await Html.PartialAsync("_ProjektEditor", Model)
@Html.StatusMessage(Model.StatusMessage)
<div class="form-group">
<div class="col-md-offset-3 col-md-6">
<button id="btnSave" type="submit" class="btn btn-primary">Save</button>
<a href="@Url.Action("Index", "Projekt")" class="btn btn-default">Back</a>
</div>
</div>
}
12 changes: 11 additions & 1 deletion Zetbox.Client.ASPNET/Views/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Account" asp-action="Login">Login</a>
</li>
</ul>
</div>
</div>
Expand All @@ -40,7 +43,14 @@

<footer class="border-top footer text-muted">
<div class="container">
&copy; 2019 - Zetbox.Client.ASPNET - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
<div class="row">
<div class="col-lg-8">
&copy; 2019 - Zetbox.Client.ASPNET - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
<div class="col-lg-4 text-right">
@User.Identity?.Name
</div>
</div>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
Expand Down
3 changes: 2 additions & 1 deletion Zetbox.Client.ASPNET/Zetbox.Client.ASPNET.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.4" />
</ItemGroup>

Expand All @@ -23,7 +24,7 @@
<ProjectReference Include="..\Zetbox.Assets\Zetbox.Assets.csproj" />
<ProjectReference Include="..\Zetbox.Client.ASPNET.Toolkit\Zetbox.Client.ASPNET.Toolkit.csproj" />
<ProjectReference Include="..\Zetbox.Client\Zetbox.Client.csproj" />
<ProjectReference Include="..\Zetbox.Objects\Zetbox.Objects.csproj" >
<ProjectReference Include="..\Zetbox.Objects\Zetbox.Objects.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
Expand Down

0 comments on commit 3b4d917

Please sign in to comment.