Authentication / Authorization
Who are you, anyway?
This commit is contained in:
parent
5235e5a5db
commit
c0237e1433
@ -1,6 +1,8 @@
|
|||||||
|
module MyPrayerJournal.App
|
||||||
|
|
||||||
open Microsoft.AspNetCore.Builder
|
open Microsoft.AspNetCore.Builder
|
||||||
open Microsoft.AspNetCore.Hosting
|
open Microsoft.AspNetCore.Hosting
|
||||||
|
open Microsoft.AspNetCore.Http
|
||||||
open Microsoft.AspNetCore.Localization
|
open Microsoft.AspNetCore.Localization
|
||||||
open Microsoft.Extensions.Configuration
|
open Microsoft.Extensions.Configuration
|
||||||
open Microsoft.Extensions.DependencyInjection
|
open Microsoft.Extensions.DependencyInjection
|
||||||
@ -31,13 +33,17 @@ type Startup(env : IHostingEnvironment) =
|
|||||||
ignore <| services.AddLocalization (fun options -> options.ResourcesPath <- "Resources")
|
ignore <| services.AddLocalization (fun options -> options.ResourcesPath <- "Resources")
|
||||||
ignore <| services.AddMvc ()
|
ignore <| services.AddMvc ()
|
||||||
ignore <| services.AddDistributedMemoryCache ()
|
ignore <| services.AddDistributedMemoryCache ()
|
||||||
ignore <| services.AddSession ()
|
|
||||||
// RethinkDB connection
|
// RethinkDB connection
|
||||||
async {
|
async {
|
||||||
let cfg = services.BuildServiceProvider().GetService<IOptions<AppConfig>>().Value
|
let cfg = services.BuildServiceProvider().GetService<IOptions<AppConfig>>().Value
|
||||||
let! conn = DataConfig.Connect cfg.DataConfig
|
let! conn = DataConfig.Connect cfg.DataConfig
|
||||||
do! conn.EstablishEnvironment cfg
|
do! conn.EstablishEnvironment cfg
|
||||||
ignore <| services.AddSingleton conn
|
ignore <| services.AddSingleton conn
|
||||||
|
//ignore <| services.AddDistributedRethinkDBCache (fun options ->
|
||||||
|
// options.Connection <- conn
|
||||||
|
// options.Database <- match cfg.DataConfig.Database with null -> "" | db -> db
|
||||||
|
// options.TableName <- "Session")
|
||||||
|
ignore <| services.AddSession ()
|
||||||
} |> Async.RunSynchronously
|
} |> Async.RunSynchronously
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
@ -52,8 +58,14 @@ type Startup(env : IHostingEnvironment) =
|
|||||||
|
|
||||||
ignore <| app.UseStaticFiles ()
|
ignore <| app.UseStaticFiles ()
|
||||||
|
|
||||||
// Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715
|
ignore <| app.UseCookieAuthentication(
|
||||||
|
CookieAuthenticationOptions(
|
||||||
|
AuthenticationScheme = Keys.Authentication,
|
||||||
|
LoginPath = PathString("/user/log-on"),
|
||||||
|
AutomaticAuthenticate = true,
|
||||||
|
AutomaticChallenge = true,
|
||||||
|
ExpireTimeSpan = TimeSpan(2, 0, 0),
|
||||||
|
SlidingExpiration = true))
|
||||||
ignore <| app.UseMvc(fun routes ->
|
ignore <| app.UseMvc(fun routes ->
|
||||||
ignore <| routes.MapRoute(name = "default", template = "{controller=Home}/{action=Index}/{id?}"))
|
ignore <| routes.MapRoute(name = "default", template = "{controller=Home}/{action=Index}/{id?}"))
|
||||||
|
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module MyPrayerJournal.Keys
|
module MyPrayerJournal.Keys
|
||||||
|
|
||||||
|
/// Instance name for cookie authentication
|
||||||
|
let Authentication = "mpj-authentication"
|
||||||
|
|
||||||
/// The current user
|
/// The current user
|
||||||
let CurrentUser = "mpj-user"
|
let CurrentUser = "mpj-user"
|
||||||
|
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
namespace MyPrayerJournal.Controllers
|
namespace MyPrayerJournal.Controllers
|
||||||
|
|
||||||
|
open Microsoft.AspNetCore.Authorization
|
||||||
open Microsoft.AspNetCore.Mvc
|
open Microsoft.AspNetCore.Mvc
|
||||||
|
open MyPrayerJournal
|
||||||
open RethinkDb.Driver.Net
|
open RethinkDb.Driver.Net
|
||||||
|
|
||||||
/// Home controller
|
/// Home controller
|
||||||
|
[<Authorize>]
|
||||||
[<Route("")>]
|
[<Route("")>]
|
||||||
type HomeController(data : IConnection) =
|
type HomeController(data : IConnection) =
|
||||||
inherit ApplicationController(data)
|
inherit ApplicationController(data)
|
||||||
|
|
||||||
|
[<AllowAnonymous>]
|
||||||
[<HttpGet("")>]
|
[<HttpGet("")>]
|
||||||
member this.Index() = this.View()
|
member this.Index() =
|
||||||
|
async {
|
||||||
|
match this.HttpContext.User with
|
||||||
|
| :? AppUser as user -> return this.View "Dashboard" :> IActionResult
|
||||||
|
| _ -> return upcast this.View ()
|
||||||
|
} |> Async.StartAsTask
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
namespace MyPrayerJournal.Controllers
|
namespace MyPrayerJournal.Controllers
|
||||||
|
|
||||||
|
open Microsoft.AspNetCore.Authorization
|
||||||
open Microsoft.AspNetCore.Mvc
|
open Microsoft.AspNetCore.Mvc
|
||||||
open Microsoft.Extensions.Options
|
open Microsoft.Extensions.Options
|
||||||
open MyPrayerJournal
|
open MyPrayerJournal
|
||||||
@ -7,34 +8,42 @@ open MyPrayerJournal.ViewModels
|
|||||||
open RethinkDb.Driver.Net
|
open RethinkDb.Driver.Net
|
||||||
|
|
||||||
/// Controller for all /user URLs
|
/// Controller for all /user URLs
|
||||||
|
[<Authorize>]
|
||||||
[<Route("user")>]
|
[<Route("user")>]
|
||||||
type UserController(data : IConnection, cfg : IOptions<AppConfig>) =
|
type UserController(data : IConnection, cfg : IOptions<AppConfig>) =
|
||||||
inherit ApplicationController(data)
|
inherit ApplicationController(data)
|
||||||
|
|
||||||
|
[<AllowAnonymous>]
|
||||||
[<HttpGet("log-on")>]
|
[<HttpGet("log-on")>]
|
||||||
member this.ShowLogOn () =
|
member this.ShowLogOn () =
|
||||||
this.View(LogOnViewModel())
|
this.View(LogOnViewModel())
|
||||||
|
|
||||||
|
[<AllowAnonymous>]
|
||||||
[<HttpPost("log-on")>]
|
[<HttpPost("log-on")>]
|
||||||
[<ValidateAntiForgeryToken>]
|
[<ValidateAntiForgeryToken>]
|
||||||
member this.DoLogOn (form : LogOnViewModel) =
|
member this.DoLogOn (form : LogOnViewModel) =
|
||||||
async {
|
async {
|
||||||
let! user = data.LogOnUser form.Email (User.HashPassword form.Password cfg.Value.PasswordSaltBytes)
|
let! user = data.LogOnUser form.Email (User.HashPassword form.Password cfg.Value.PasswordSaltBytes)
|
||||||
match user with
|
match user with
|
||||||
| Some usr -> (* this.Session.[Keys.User] <- usr
|
| Some usr -> do! this.HttpContext.Authentication.SignInAsync(Keys.Authentication, AppUser(user))
|
||||||
|
// TODO: welcome message
|
||||||
|
(* this.Session.[Keys.User] <- usr
|
||||||
{ UserMessage.Empty with Level = Level.Info
|
{ UserMessage.Empty with Level = Level.Info
|
||||||
Message = Strings.get "LogOnSuccess" }
|
Message = Strings.get "LogOnSuccess" }
|
||||||
|> model.AddMessage
|
|> model.AddMessage *)
|
||||||
this.Redirect "" model |> ignore // Save the messages in the session before the Nancy redirect
|
|
||||||
// TODO: investigate if addMessage should update the session when it's called
|
|
||||||
return this.LoginAndRedirect (System.Guid.Parse usr.Id, fallbackRedirectUrl = "/") :> obj
|
|
||||||
*)
|
|
||||||
return this.Redirect "/" :> IActionResult
|
return this.Redirect "/" :> IActionResult
|
||||||
| _ -> (*{ UserMessage.Empty with Level = Level.Error
|
| _ -> (*{ UserMessage.Empty with Level = Level.Error
|
||||||
Message = Strings.get "LogOnFailure" }
|
Message = Strings.get "LogOnFailure" }
|
||||||
|> model.AddMessage
|
|> model.AddMessage
|
||||||
return this.Redirect "/user/log-on" model *)
|
return this.Redirect "/user/log-on" model *)
|
||||||
return upcast this.RedirectToAction("ShowLogOn")
|
return upcast this.RedirectToAction "ShowLogOn"
|
||||||
//return this.View()
|
//return this.View()
|
||||||
} |> Async.StartAsTask
|
} |> Async.StartAsTask
|
||||||
|
|
||||||
|
[<HttpGet("log-off")>]
|
||||||
|
member this.LogOff () =
|
||||||
|
async {
|
||||||
|
do! this.HttpContext.Authentication.SignOutAsync(Keys.Authentication)
|
||||||
|
// TODO: goodbye message
|
||||||
|
return this.LocalRedirect "/"
|
||||||
|
} |> Async.StartAsTask
|
@ -1,6 +1,7 @@
|
|||||||
namespace MyPrayerJournal
|
namespace MyPrayerJournal
|
||||||
|
|
||||||
open Newtonsoft.Json
|
open Newtonsoft.Json
|
||||||
|
open System.Security.Claims
|
||||||
open System.Security.Cryptography
|
open System.Security.Cryptography
|
||||||
|
|
||||||
/// A user
|
/// A user
|
||||||
@ -81,4 +82,11 @@ type Request = {
|
|||||||
|> List.sortBy (fun item -> -item.AsOf)
|
|> List.sortBy (fun item -> -item.AsOf)
|
||||||
|> List.map (fun item -> item.AsOf)
|
|> List.map (fun item -> item.AsOf)
|
||||||
|> List.head
|
|> List.head
|
||||||
|
|
||||||
|
/// The user for use with identity
|
||||||
|
[<AllowNullLiteral>]
|
||||||
|
type AppUser(user : User option) =
|
||||||
|
inherit ClaimsPrincipal()
|
||||||
|
|
||||||
|
/// The current user
|
||||||
|
member val User = user with get
|
@ -3,7 +3,6 @@ namespace MyPrayerJournal.ViewModels
|
|||||||
//open MyPrayerJournal
|
//open MyPrayerJournal
|
||||||
|
|
||||||
/// Parent view model for all myPrayerJournal view models
|
/// Parent view model for all myPrayerJournal view models
|
||||||
[<AllowNullLiteral>]
|
|
||||||
type AppViewModel() =
|
type AppViewModel() =
|
||||||
member this.Q = "X"
|
member this.Q = "X"
|
||||||
(*
|
(*
|
||||||
|
@ -2,7 +2,6 @@ namespace MyPrayerJournal.ViewModels
|
|||||||
|
|
||||||
open System.ComponentModel.DataAnnotations
|
open System.ComponentModel.DataAnnotations
|
||||||
|
|
||||||
[<AllowNullLiteral>]
|
|
||||||
type LogOnViewModel() =
|
type LogOnViewModel() =
|
||||||
inherit AppViewModel()
|
inherit AppViewModel()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user