mirror of
https://github.com/bitwarden/server
synced 2026-01-05 10:03:23 +00:00
passwordless signin for billing portal
This commit is contained in:
@@ -5,8 +5,6 @@
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<RootNamespace>Bit.Billing</RootNamespace>
|
||||
<UserSecretsId>bitwarden-Billing</UserSecretsId>
|
||||
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
|
||||
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -15,6 +13,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -22,4 +21,9 @@
|
||||
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\images\" />
|
||||
<Folder Include="wwwroot\scripts\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
15
src/Billing/Controllers/HomeController.cs
Normal file
15
src/Billing/Controllers/HomeController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Billing.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
[Authorize]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/Billing/Controllers/LoginController.cs
Normal file
48
src/Billing/Controllers/LoginController.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Billing.Models;
|
||||
using Bit.Core.Identity;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Billing.Controllers
|
||||
{
|
||||
public class LoginController : Controller
|
||||
{
|
||||
private readonly PasswordlessSignInManager<IdentityUser> _signInManager;
|
||||
|
||||
public LoginController(
|
||||
PasswordlessSignInManager<IdentityUser> signInManager)
|
||||
{
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Index(LoginModel model)
|
||||
{
|
||||
var result = await _signInManager.PasswordlessSignInAsync(model.Email);
|
||||
if(!result.Succeeded)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Confirm(string email, string token)
|
||||
{
|
||||
var result = await _signInManager.PasswordlessSignInAsync(email, token, false);
|
||||
if(!result.Succeeded)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/Billing/Models/LoginModel.cs
Normal file
11
src/Billing/Models/LoginModel.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Bit.Billing.Models
|
||||
{
|
||||
public class LoginModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,10 @@ using Serilog.Events;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Bit.Billing.Utilities;
|
||||
using Bit.Core.Identity;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace Bit.Billing
|
||||
{
|
||||
@@ -42,7 +46,28 @@ namespace Bit.Billing
|
||||
services.AddScoped<CurrentContext>();
|
||||
|
||||
// Identity
|
||||
services.AddCustomIdentityServices(globalSettings);
|
||||
services.AddTransient<ILookupNormalizer, LowerInvariantLookupNormalizer>();
|
||||
services.AddIdentity<IdentityUser, Core.Models.Table.Role>()
|
||||
.AddUserStore<ReadOnlyIdentityUserStore>()
|
||||
.AddRoleStore<RoleStore>()
|
||||
.AddDefaultTokenProviders();
|
||||
services.TryAddScoped<PasswordlessSignInManager<IdentityUser>, PasswordlessSignInManager<IdentityUser>>();
|
||||
|
||||
services.Configure<DataProtectionTokenProviderOptions>(options =>
|
||||
{
|
||||
options.TokenLifespan = TimeSpan.FromMinutes(15);
|
||||
});
|
||||
services.ConfigureApplicationCookie(options =>
|
||||
{
|
||||
options.LoginPath = "/login";
|
||||
options.LogoutPath = "/";
|
||||
options.AccessDeniedPath = "/login";
|
||||
options.Cookie.Name = "BitwardenBilling";
|
||||
options.Cookie.HttpOnly = true;
|
||||
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
|
||||
options.ReturnUrlParameter = "returnUrl";
|
||||
options.SlidingExpiration = true;
|
||||
});
|
||||
|
||||
// Services
|
||||
services.AddBaseServices();
|
||||
@@ -55,6 +80,7 @@ namespace Bit.Billing
|
||||
{
|
||||
config.Filters.Add(new ExceptionHandlerFilterAttribute());
|
||||
});
|
||||
services.Configure<RouteOptions>(options => options.LowercaseUrls = true);
|
||||
}
|
||||
|
||||
public void Configure(
|
||||
@@ -71,10 +97,9 @@ namespace Bit.Billing
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
// Default Middleware
|
||||
app.UseDefaultMiddleware(env);
|
||||
|
||||
app.UseMvc();
|
||||
app.UseAuthentication();
|
||||
app.UseStaticFiles();
|
||||
app.UseMvcWithDefaultRoute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
src/Billing/Views/Home/Index.cshtml
Normal file
6
src/Billing/Views/Home/Index.cshtml
Normal file
@@ -0,0 +1,6 @@
|
||||
@{
|
||||
ViewData["Title"] = "Index";
|
||||
}
|
||||
|
||||
<h2>Index</h2>
|
||||
|
||||
21
src/Billing/Views/Login/Index.cshtml
Normal file
21
src/Billing/Views/Login/Index.cshtml
Normal file
@@ -0,0 +1,21 @@
|
||||
@{
|
||||
ViewData["Title"] = "Login";
|
||||
}
|
||||
|
||||
@model LoginModel
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-8 col-xs-offset-2">
|
||||
<h1 class="text-center">Login</h1>
|
||||
<form asp-action="" method="post" class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label asp-for="Email" class="col-sm-3">Email Address: </label>
|
||||
<div class="col-sm-9">
|
||||
<input asp-for="Email" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
<div asp-validation-summary="All"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
15
src/Billing/Views/Shared/Error.cshtml
Normal file
15
src/Billing/Views/Shared/Error.cshtml
Normal file
@@ -0,0 +1,15 @@
|
||||
@model ErrorViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Error";
|
||||
}
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
|
||||
</p>
|
||||
42
src/Billing/Views/Shared/_Layout.cshtml
Normal file
42
src/Billing/Views/Shared/_Layout.cshtml
Normal file
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] | Bitwarden Billing Portal</title>
|
||||
|
||||
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="~/styles/site.css">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">Bitwarden Billing</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
|
||||
<li><a asp-area="" asp-controller="Login" asp-action="Index">Login</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container body-content">
|
||||
@RenderBody()
|
||||
<hr />
|
||||
<footer>
|
||||
<p>© 2018 - 8bit Solutions LLC</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"></script>
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
3
src/Billing/Views/_ViewImports.cshtml
Normal file
3
src/Billing/Views/_ViewImports.cshtml
Normal file
@@ -0,0 +1,3 @@
|
||||
@using Bit.Billing
|
||||
@using Bit.Billing.Models
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
3
src/Billing/Views/_ViewStart.cshtml
Normal file
3
src/Billing/Views/_ViewStart.cshtml
Normal file
@@ -0,0 +1,3 @@
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
||||
35
src/Billing/wwwroot/styles/site.css
Normal file
35
src/Billing/wwwroot/styles/site.css
Normal file
@@ -0,0 +1,35 @@
|
||||
body {
|
||||
padding-top: 50px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
/* Wrapping element */
|
||||
/* Set some basic padding to keep content from hitting the edges */
|
||||
.body-content {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
/* Carousel */
|
||||
.carousel-caption p {
|
||||
font-size: 20px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Make .svg files in the carousel display properly in older browsers */
|
||||
.carousel-inner .item img[src$=".svg"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* QR code generator */
|
||||
#qrCode {
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
/* Hide/rearrange for smaller screens */
|
||||
@media screen and (max-width: 767px) {
|
||||
/* Hide captions */
|
||||
.carousel-caption {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user