Authentication, take 2; take 3 forthcoming...

*cue sad trombone*
This commit is contained in:
Daniel J. Summers 2016-10-07 22:07:46 -05:00
parent c0237e1433
commit d3a80b9ceb
7 changed files with 63 additions and 49 deletions

View File

@ -8,6 +8,7 @@ open Microsoft.Extensions.Configuration
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Logging
open Microsoft.Extensions.Options
open RethinkDB.DistributedCache
open System
open System.IO
@ -28,46 +29,45 @@ type Startup(env : IHostingEnvironment) =
// This method gets called by the runtime. Use this method to add services to the container.
member this.ConfigureServices (services : IServiceCollection) =
ignore <| services.AddOptions ()
ignore <| services.Configure<AppConfig>(this.Configuration.GetSection("MyPrayerJournal"))
ignore <| services.AddLocalization (fun options -> options.ResourcesPath <- "Resources")
ignore <| services.AddMvc ()
ignore <| services.AddDistributedMemoryCache ()
services.AddOptions () |> ignore
services.Configure<AppConfig> (this.Configuration.GetSection "MyPrayerJournal") |> ignore
services.AddLocalization (fun opt -> opt.ResourcesPath <- "Resources") |> ignore
services.AddMvc () |> ignore
//ignore <| services.AddDistributedMemoryCache ()
// RethinkDB connection
async {
let cfg = services.BuildServiceProvider().GetService<IOptions<AppConfig>>().Value
let! conn = DataConfig.Connect cfg.DataConfig
do! conn.EstablishEnvironment cfg
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 ()
services.AddSingleton conn |> ignore
services.AddDistributedRethinkDBCache (fun options ->
options.Database <- match cfg.DataConfig.Database with null -> "" | db -> db
options.TableName <- "Session") |> ignore
services.AddSession () |> ignore
} |> Async.RunSynchronously
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
member this.Configure (app : IApplicationBuilder, env : IHostingEnvironment, loggerFactory : ILoggerFactory) =
ignore <| loggerFactory.AddConsole(this.Configuration.GetSection "Logging")
ignore <| loggerFactory.AddDebug ()
loggerFactory.AddConsole(this.Configuration.GetSection "Logging") |> ignore
loggerFactory.AddDebug () |> ignore
match env.IsDevelopment () with
| true -> ignore <| app.UseDeveloperExceptionPage ()
ignore <| app.UseBrowserLink ()
| _ -> ignore <| app.UseExceptionHandler("/error")
| true -> app.UseDeveloperExceptionPage () |> ignore
app.UseBrowserLink () |> ignore
| _ -> app.UseExceptionHandler "/error" |> ignore
ignore <| app.UseStaticFiles ()
app.UseStaticFiles () |> ignore
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 <| routes.MapRoute(name = "default", template = "{controller=Home}/{action=Index}/{id?}"))
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 ->
routes.MapRoute(name = "default", template = "{controller=Home}/{action=Index}/{id?}") |> ignore) |> ignore
/// Default to Development environment
let defaults = seq { yield WebHostDefaults.EnvironmentKey, "Development" }
@ -81,12 +81,12 @@ let main argv =
.AddEnvironmentVariables("ASPNETCORE_")
.AddCommandLine(argv)
.Build()
WebHostBuilder()
.UseConfiguration(cfg)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build()
.Run()
use host =
WebHostBuilder()
.UseConfiguration(cfg)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build()
host.Run()
0

View File

@ -2,20 +2,23 @@ namespace MyPrayerJournal.Controllers
open Microsoft.AspNetCore.Authorization
open Microsoft.AspNetCore.Mvc
open Microsoft.Extensions.Logging
open MyPrayerJournal
open RethinkDb.Driver.Net
/// Home controller
[<Authorize>]
[<Route("")>]
type HomeController(data : IConnection) =
type HomeController(data : IConnection, logger : ILogger<HomeController>) =
inherit ApplicationController(data)
[<AllowAnonymous>]
[<HttpGet("")>]
member this.Index() =
logger.LogDebug(Newtonsoft.Json.JsonConvert.SerializeObject this.HttpContext.User)
async {
match this.HttpContext.User with
| :? AppUser as user -> return this.View "Dashboard" :> IActionResult
| _ -> return upcast this.View ()
} |> Async.StartAsTask
}
|> Async.StartAsTask

View File

@ -25,7 +25,7 @@ type UserController(data : IConnection, cfg : IOptions<AppConfig>) =
async {
let! user = data.LogOnUser form.Email (User.HashPassword form.Password cfg.Value.PasswordSaltBytes)
match user with
| Some usr -> do! this.HttpContext.Authentication.SignInAsync(Keys.Authentication, AppUser(user))
| 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
@ -37,13 +37,13 @@ type UserController(data : IConnection, cfg : IOptions<AppConfig>) =
|> model.AddMessage
return this.Redirect "/user/log-on" model *)
return upcast this.RedirectToAction "ShowLogOn"
//return this.View()
} |> Async.StartAsTask
}
|> Async.StartAsTask
[<HttpGet("log-off")>]
member this.LogOff () =
async {
do! this.HttpContext.Authentication.SignOutAsync(Keys.Authentication)
do! this.HttpContext.Authentication.SignOutAsync Keys.Authentication
// TODO: goodbye message
return this.LocalRedirect "/"
} |> Async.StartAsTask

View File

@ -29,7 +29,7 @@ type IConnection with
.Filter(ReqlFunction1(fun usr -> upcast usr.["PasswordHash"].Eq(passwordHash)))
.RunResultAsync<User list>(this)
return user |> List.tryHead
}
}
/// Set up the environment for MyPrayerJournal
member this.EstablishEnvironment (cfg : AppConfig) =
@ -50,7 +50,7 @@ type IConnection with
| _ -> logStepStart " Database not found - creating..."
do! r.DbCreate("MyPrayerJournal").RunResultAsync(this)
logStepEnd ()
}
}
/// Ensure all tables exit
let checkTables () =
async {
@ -63,7 +63,7 @@ type IConnection with
logStepStart <| sprintf " %s table not found - creating..." tbl
do! db().TableCreate(tbl).RunResultAsync(this)
logStepEnd()
})
})
|> List.iter Async.RunSynchronously
// Seed the user table if it is empty
let! userCount = db().Table(DataTable.User).Count().RunResultAsync<int64>(this)
@ -75,7 +75,8 @@ type IConnection with
Email = "test@example.com"
PasswordHash = User.HashPassword "password" cfg.PasswordSaltBytes
Name = "Default User"
TimeZone = "America/Chicago" }).RunResultAsync(this)
TimeZone = "America/Chicago"
}).RunResultAsync(this)
logStepEnd ()
| _ -> ()
}
@ -95,11 +96,11 @@ type IConnection with
| _ -> logStepStart <| sprintf " %s.Email index not found - creating..." DataTable.User
do! db().Table(DataTable.User).IndexCreate("Email").RunResultAsync(this)
logStepEnd ()
}
}
async {
logStep "Database checks starting"
do! checkDatabase ()
do! checkTables ()
do! checkIndexes ()
logStep "Database checks complete"
}
}

View File

@ -75,6 +75,6 @@
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
@RenderSection("scripts", required: false)
@RenderSection("Scripts", required: false)
</body>
</html>

View File

@ -28,4 +28,13 @@
</p>
</div>
</div>
</form>
</form>
@section Scripts
{
<script type="text/javascript">
/* <![CDATA[ */
$(document).ready(function () { $("#Email").focus() })
/* ]]> */
</script>
}

View File

@ -37,6 +37,7 @@
},
"Newtonsoft.Json": "9.0.1",
"NodaTime": "2.0.0-alpha20160729",
"RethinkDB.DistributedCache": "0.9.0-alpha01",
"RethinkDb.Driver": "2.3.15"
},