F# API #18
6
.gitignore
vendored
6
.gitignore
vendored
@ -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
|
||||
|
@ -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) =
|
||||
@ -48,6 +51,21 @@ module private Helpers =
|
||||
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
|
||||
module Models =
|
||||
@ -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
|
||||
|
@ -22,4 +22,8 @@
|
||||
<PackageReference Update="FSharp.Core" Version="4.5.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -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)
|
||||
|
9
src/api/MyPrayerJournal.Api/appsettings.json
Normal file
9
src/api/MyPrayerJournal.Api/appsettings.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Kestrel": {
|
||||
"EndPoints": {
|
||||
"Http": {
|
||||
"Url": "http://localhost:3000"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user