F# API #18

Merged
danieljsummers merged 7 commits from fs-api into master 2018-08-07 02:21:29 +00:00
7 changed files with 71 additions and 24 deletions
Showing only changes of commit e4d00b4157 - Show all commits

6
.gitignore vendored
View File

@ -254,8 +254,8 @@ paket-files/
# Compiled files / application
src/api/build
src/public/index.html
src/public/static
src/config.json
src/api/MyPrayerJournal.Api/wwwroot/index.html
src/api/MyPrayerJournal.Api/wwwroot/static
src/api/MyPrayerJournal.Api/appsettings.development.json
/build
src/*.exe

View File

@ -1,8 +1,9 @@
/// HTTP handlers for the myPrayerJournal API
[<RequireQualifiedAccess>]
module MyPrayerJournal.Handlers
module MyPrayerJournal.Api.Handlers
open Giraffe
open MyPrayerJournal
open System
module Error =
@ -17,7 +18,7 @@ module Error =
/// Handle 404s from the API, sending known URL paths to the Vue app so that they can be handled there
let notFound : HttpHandler =
fun next ctx ->
let vueApp () = htmlFile "/index.html" next ctx
let vueApp () = htmlFile "wwwroot/index.html" next ctx
match true with
| _ when ctx.Request.Path.Value.StartsWith "/answered" -> vueApp ()
| _ when ctx.Request.Path.Value.StartsWith "/journal" -> vueApp ()
@ -31,6 +32,8 @@ module Error =
module private Helpers =
open Microsoft.AspNetCore.Http
open Microsoft.AspNetCore.Authorization
open System.Threading.Tasks
/// Get the database context from DI
let db (ctx : HttpContext) =
@ -47,6 +50,21 @@ module private Helpers =
/// The "now" time in JavaScript
let jsNow () =
DateTime.Now.Subtract(DateTime (1970, 1, 1)).TotalSeconds |> int64 |> (*) 1000L
let notAuthorized : HttpHandler =
setStatusCode 403 >=> fun _ _ -> Task.FromResult<HttpContext option> None
/// Handler to require authorization
let authorize : HttpHandler =
fun next ctx ->
task {
let auth = ctx.GetService<IAuthorizationService>()
let! result = auth.AuthorizeAsync (ctx.User, "LoggedOn")
Console.WriteLine (sprintf "*** Auth succeeded = %b" result.Succeeded)
match result.Succeeded with
| true -> return! next ctx
| false -> return! notAuthorized next ctx
}
/// Strongly-typed models for post requests
@ -87,7 +105,8 @@ module Journal =
/// GET /api/journal
let journal : HttpHandler =
fun next ctx ->
authorize
>=> fun next ctx ->
match user ctx with
| Some u -> json ((db ctx).JournalByUserId u.Value) next ctx
| None -> Error.notFound next ctx

View File

@ -22,4 +22,8 @@
<PackageReference Update="FSharp.Core" Version="4.5.2" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
</Project>

View File

@ -1,36 +1,50 @@
namespace MyPrayerJournal.Api
open System
open Microsoft.AspNetCore
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Hosting
open Microsoft.Extensions.Configuration
open Microsoft.Extensions.Logging
/// Configuration functions for the application
module Configure =
open Microsoft.AspNetCore.Authentication.JwtBearer
open Microsoft.AspNetCore.Server.Kestrel.Core
open Microsoft.Extensions.Configuration
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Logging
open Giraffe
open Giraffe.TokenRouter
open MyPrayerJournal
/// Set up the configuration for the app
let configuration (ctx : WebHostBuilderContext) (cfg : IConfigurationBuilder) =
cfg.SetBasePath(ctx.HostingEnvironment.ContentRootPath)
.AddJsonFile("appsettings.json", optional = true, reloadOnChange = true)
.AddJsonFile(sprintf "appsettings.%s.json" ctx.HostingEnvironment.EnvironmentName, optional = true)
.AddJsonFile(sprintf "appsettings.%s.json" ctx.HostingEnvironment.EnvironmentName)
.AddEnvironmentVariables()
|> ignore
/// Configure Kestrel from appsettings.json
let kestrel (ctx : WebHostBuilderContext) (opts : KestrelServerOptions) =
(ctx.Configuration.GetSection >> opts.Configure >> ignore) "Kestrel"
/// Configure dependency injection
let services (sc : IServiceCollection) =
sc.AddAuthentication()
.AddJwtBearer("Auth0",
fun opt ->
opt.Audience <- "")
sc.AddGiraffe () |> ignore
// mad props to Andrea Chiarelli @ https://auth0.com/blog/securing-asp-dot-net-core-2-applications-with-jwts/
use sp = sc.BuildServiceProvider()
let cfg = sp.GetRequiredService<IConfiguration>().GetSection "Auth0"
sc.AddAuthentication(
fun opts ->
opts.DefaultAuthenticateScheme <- JwtBearerDefaults.AuthenticationScheme
opts.DefaultChallengeScheme <- JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer (
fun opts ->
opts.Authority <- sprintf "https://%s/" cfg.["Domain"]
opts.Audience <- cfg.["Audience"]
opts.TokenValidationParameters.ValidateAudience <- false)
|> ignore
sc.AddAuthorization (fun opts -> opts.AddPolicy ("LoggedOn", fun p -> p.RequireClaim "sub" |> ignore))
|> ignore
()
/// Routes for the available URLs within myPrayerJournal
let webApp =
@ -82,6 +96,7 @@ module Configure =
module Program =
open System
open System.IO
let exitCode = 0
@ -89,10 +104,10 @@ module Program =
let CreateWebHostBuilder args =
let contentRoot = Directory.GetCurrentDirectory ()
WebHostBuilder()
.UseKestrel()
.UseContentRoot(contentRoot)
.ConfigureAppConfiguration(Configure.configuration)
.UseKestrel(Configure.kestrel)
.UseWebRoot(Path.Combine (contentRoot, "wwwroot"))
.ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> Configure.configuration)
.ConfigureServices(Configure.services)
.ConfigureLogging(Configure.logging)
.Configure(Action<IApplicationBuilder> Configure.application)

View File

@ -0,0 +1,9 @@
{
"Kestrel": {
"EndPoints": {
"Http": {
"Url": "http://localhost:3000"
}
}
}
}

View File

@ -4,8 +4,8 @@ var path = require('path')
module.exports = {
build: {
env: require('./prod.env'),
index: path.resolve(__dirname, '../../public/index.html'),
assetsRoot: path.resolve(__dirname, '../../public'),
index: path.resolve(__dirname, '../../api/MyPrayerJournal.Api/wwwroot/index.html'),
assetsRoot: path.resolve(__dirname, '../../api/MyPrayerJournal.Api/wwwroot'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
productionSourceMap: true,

View File

@ -1,6 +1,6 @@
{
"name": "my-prayer-journal",
"version": "0.9.6",
"version": "0.9.7",
"description": "myPrayerJournal - Front End",
"author": "Daniel J. Summers <daniel@bitbadger.solutions>",
"private": true,
@ -12,8 +12,8 @@
"e2e": "node test/e2e/runner.js",
"test": "npm run unit && npm run e2e",
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs",
"apistart": "cd .. && go build -o mpj-api.exe && mpj-api.exe",
"vue": "node build/build.js prod && cd .. && go build -o mpj-api.exe && mpj-api.exe"
"apistart": "cd ../api/MyPrayerJournal.Api && dotnet run",
"vue": "node build/build.js prod && cd ../api/MyPrayerJournal.Api && dotnet run"
},
"dependencies": {
"auth0-js": "^9.3.3",