mirror of
https://github.com/ditkrg/AuthorizationServerDemos.git
synced 2026-01-22 23:46:54 +00:00
API is protected and client can login and call API
This commit is contained in:
commit
536c7fdb3d
458
.gitignore
vendored
Normal file
458
.gitignore
vendored
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- Backup*.rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
|
||||||
|
Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using OidcSamples.TrafficPoliceApi.Data;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace OidcSamples.TrafficPoliceApi.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class VehiclesController : Controller
|
||||||
|
{
|
||||||
|
private readonly ApplicationDbContext _applicationDbContext;
|
||||||
|
|
||||||
|
public VehiclesController(ApplicationDbContext applicationDbContext)
|
||||||
|
{
|
||||||
|
_applicationDbContext = applicationDbContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("")]
|
||||||
|
public async Task<IEnumerable<Vehicle>> Get()
|
||||||
|
{
|
||||||
|
var ownerId = UserId();
|
||||||
|
return await _applicationDbContext.Vehicles.Where(v => v.OwnerId == ownerId).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string UserId()
|
||||||
|
{
|
||||||
|
return User.Claims.First(c => c.Type == "sub").Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<Vehicle> Post(VehicleRequest request)
|
||||||
|
{
|
||||||
|
var vehicle = new Vehicle
|
||||||
|
{
|
||||||
|
Model = request.Model,
|
||||||
|
Color = request.Color,
|
||||||
|
LicensePlate = request.LicensePlate,
|
||||||
|
OwnerId = UserId(),
|
||||||
|
Type = (VehicleType)request.Type,
|
||||||
|
};
|
||||||
|
|
||||||
|
_applicationDbContext.Vehicles.Add(vehicle);
|
||||||
|
await _applicationDbContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
return vehicle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VehicleRequest
|
||||||
|
{
|
||||||
|
[StringLength(100)]
|
||||||
|
public string OwnerId { get; set; }
|
||||||
|
[StringLength(100)]
|
||||||
|
public string Model { get; set; }
|
||||||
|
[StringLength(32)]
|
||||||
|
public string Color { get; set; }
|
||||||
|
[StringLength(32)]
|
||||||
|
public string LicensePlate { get; set; }
|
||||||
|
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
|
||||||
|
public int Type { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace OidcSamples.TrafficPoliceApi.Data
|
||||||
|
{
|
||||||
|
public class ApplicationDbContext : DbContext
|
||||||
|
{
|
||||||
|
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<Vehicle> Vehicles { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum VehicleType
|
||||||
|
{
|
||||||
|
Sedan = 0,
|
||||||
|
SUV = 1,
|
||||||
|
Pickup = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Vehicle
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
[StringLength(100)]
|
||||||
|
public string OwnerId { get; set; }
|
||||||
|
[StringLength(100)]
|
||||||
|
public string Model { get; set; }
|
||||||
|
[StringLength(32)]
|
||||||
|
public string Color { get; set; }
|
||||||
|
[StringLength(32)]
|
||||||
|
public string LicensePlate { get; set; }
|
||||||
|
public VehicleType Type { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
63
CSharp/OidcSamples/OidcSamples.TrafficPoliceApi/Migrations/20210107062802_Vehicle.Designer.cs
generated
Normal file
63
CSharp/OidcSamples/OidcSamples.TrafficPoliceApi/Migrations/20210107062802_Vehicle.Designer.cs
generated
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
using OidcSamples.TrafficPoliceApi.Data;
|
||||||
|
|
||||||
|
namespace OidcSamples.TrafficPoliceApi.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20210107062802_Vehicle")]
|
||||||
|
partial class Vehicle
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.UseIdentityByDefaultColumns()
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63)
|
||||||
|
.HasAnnotation("ProductVersion", "5.0.1");
|
||||||
|
|
||||||
|
modelBuilder.Entity("OidcSamples.TrafficPoliceApi.Data.Vehicle", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.UseIdentityByDefaultColumn();
|
||||||
|
|
||||||
|
b.Property<string>("Color")
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("character varying(32)")
|
||||||
|
.HasColumnName("color");
|
||||||
|
|
||||||
|
b.Property<string>("LicensePlate")
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("character varying(32)")
|
||||||
|
.HasColumnName("license_plate");
|
||||||
|
|
||||||
|
b.Property<string>("Model")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("character varying(100)")
|
||||||
|
.HasColumnName("model");
|
||||||
|
|
||||||
|
b.Property<string>("OwnerId")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("character varying(100)")
|
||||||
|
.HasColumnName("owner_id");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("type");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_vehicles");
|
||||||
|
|
||||||
|
b.ToTable("vehicles");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
namespace OidcSamples.TrafficPoliceApi.Migrations
|
||||||
|
{
|
||||||
|
public partial class Vehicle : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "vehicles",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<long>(type: "bigint", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
owner_id = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
|
||||||
|
model = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
|
||||||
|
color = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||||
|
license_plate = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||||
|
type = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_vehicles", x => x.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "vehicles");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
using OidcSamples.TrafficPoliceApi.Data;
|
||||||
|
|
||||||
|
namespace OidcSamples.TrafficPoliceApi.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.UseIdentityByDefaultColumns()
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63)
|
||||||
|
.HasAnnotation("ProductVersion", "5.0.1");
|
||||||
|
|
||||||
|
modelBuilder.Entity("OidcSamples.TrafficPoliceApi.Data.Vehicle", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.UseIdentityByDefaultColumn();
|
||||||
|
|
||||||
|
b.Property<string>("Color")
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("character varying(32)")
|
||||||
|
.HasColumnName("color");
|
||||||
|
|
||||||
|
b.Property<string>("LicensePlate")
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("character varying(32)")
|
||||||
|
.HasColumnName("license_plate");
|
||||||
|
|
||||||
|
b.Property<string>("Model")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("character varying(100)")
|
||||||
|
.HasColumnName("model");
|
||||||
|
|
||||||
|
b.Property<string>("OwnerId")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("character varying(100)")
|
||||||
|
.HasColumnName("owner_id");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("type");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_vehicles");
|
||||||
|
|
||||||
|
b.ToTable("vehicles");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="IdentityModel" Version="5.0.0-preview.1.7" />
|
||||||
|
<PackageReference Include="IdentityModel.AspNetCore.OAuth2Introspection" Version="4.1.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.1" NoWarn="NU1605" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.1" NoWarn="NU1605" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.1">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.1" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
||||||
|
<PackageReference Include="EFCore.NamingConventions" Version="5.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
26
CSharp/OidcSamples/OidcSamples.TrafficPoliceApi/Program.cs
Normal file
26
CSharp/OidcSamples/OidcSamples.TrafficPoliceApi/Program.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace OidcSamples.TrafficPoliceApi
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
CreateHostBuilder(args).Build().Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||||
|
Host.CreateDefaultBuilder(args)
|
||||||
|
.ConfigureWebHostDefaults(webBuilder =>
|
||||||
|
{
|
||||||
|
webBuilder.UseStartup<Startup>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:55640",
|
||||||
|
"sslPort": 44305
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"OidcSamples.TrafficPoliceApi": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": "true",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
99
CSharp/OidcSamples/OidcSamples.TrafficPoliceApi/Startup.cs
Normal file
99
CSharp/OidcSamples/OidcSamples.TrafficPoliceApi/Startup.cs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.HttpsPolicy;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using OidcSamples.TrafficPoliceApi.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace OidcSamples.TrafficPoliceApi
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public Startup(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
Configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap["sub"] = "sub";
|
||||||
|
|
||||||
|
services.AddDbContext<ApplicationDbContext>(options =>
|
||||||
|
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))
|
||||||
|
.UseSnakeCaseNamingConvention()
|
||||||
|
);
|
||||||
|
|
||||||
|
services.AddCors(options => options.AddPolicy("Default", builder =>
|
||||||
|
{
|
||||||
|
builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
|
||||||
|
}));
|
||||||
|
|
||||||
|
services.AddControllers();
|
||||||
|
services.AddSwaggerGen(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerDoc("v1", new OpenApiInfo { Title = "OidcSamples.TrafficPoliceApi", Version = "v1" });
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddAuthorization(configure =>
|
||||||
|
{
|
||||||
|
//var policy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
|
||||||
|
// .RequireAuthenticatedUser()
|
||||||
|
// .Build();
|
||||||
|
configure.AddPolicy("Default", configure.DefaultPolicy);
|
||||||
|
//configure.DefaultPolicy = policy;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1. Add Authentication Services
|
||||||
|
services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
}).AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.Authority = "https://localhost:5003";
|
||||||
|
options.Audience = "traffic-police-api";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "OidcSamples.TrafficPoliceApi v1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseCors("Default");
|
||||||
|
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
app.UseRouting();
|
||||||
|
|
||||||
|
// 2. Enable authentication middleware
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
endpoints.MapControllers().RequireAuthorization();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace OidcSamples.TrafficPoliceApi
|
||||||
|
{
|
||||||
|
public class WeatherForecast
|
||||||
|
{
|
||||||
|
public DateTime Date { get; set; }
|
||||||
|
|
||||||
|
public int TemperatureC { get; set; }
|
||||||
|
|
||||||
|
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||||
|
|
||||||
|
public string Summary { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"DefaultConnection": "User ID=postgres;Password=root;Host=localhost;Port=5432;Database=traffic_police;"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
25
CSharp/OidcSamples/OidcSamples.sln
Normal file
25
CSharp/OidcSamples/OidcSamples.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.30717.126
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OidcSamples.TrafficPoliceApi", "OidcSamples.TrafficPoliceApi\OidcSamples.TrafficPoliceApi.csproj", "{F3B43AE8-C70F-4CC1-B8C0-CBFBA4D6E4C6}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{F3B43AE8-C70F-4CC1-B8C0-CBFBA4D6E4C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F3B43AE8-C70F-4CC1-B8C0-CBFBA4D6E4C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F3B43AE8-C70F-4CC1-B8C0-CBFBA4D6E4C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F3B43AE8-C70F-4CC1-B8C0-CBFBA4D6E4C6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {B628E698-0B30-4D54-AB84-B7721D9E26CE}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
23
React/.gitignore
vendored
Normal file
23
React/.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
68
React/README.md
Normal file
68
React/README.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||||
|
|
||||||
|
## Available Scripts
|
||||||
|
|
||||||
|
In the project directory, you can run:
|
||||||
|
|
||||||
|
### `npm start`
|
||||||
|
|
||||||
|
Runs the app in the development mode.<br>
|
||||||
|
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
|
||||||
|
|
||||||
|
The page will reload if you make edits.<br>
|
||||||
|
You will also see any lint errors in the console.
|
||||||
|
|
||||||
|
### `npm test`
|
||||||
|
|
||||||
|
Launches the test runner in the interactive watch mode.<br>
|
||||||
|
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||||
|
|
||||||
|
### `npm run build`
|
||||||
|
|
||||||
|
Builds the app for production to the `build` folder.<br>
|
||||||
|
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||||
|
|
||||||
|
The build is minified and the filenames include the hashes.<br>
|
||||||
|
Your app is ready to be deployed!
|
||||||
|
|
||||||
|
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||||
|
|
||||||
|
### `npm run eject`
|
||||||
|
|
||||||
|
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
|
||||||
|
|
||||||
|
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||||
|
|
||||||
|
Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
|
||||||
|
|
||||||
|
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||||
|
|
||||||
|
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||||
|
|
||||||
|
### Code Splitting
|
||||||
|
|
||||||
|
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
|
||||||
|
|
||||||
|
### Analyzing the Bundle Size
|
||||||
|
|
||||||
|
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
|
||||||
|
|
||||||
|
### Making a Progressive Web App
|
||||||
|
|
||||||
|
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
|
||||||
|
|
||||||
|
### Advanced Configuration
|
||||||
|
|
||||||
|
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
|
||||||
|
|
||||||
|
### Deployment
|
||||||
|
|
||||||
|
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
|
||||||
|
|
||||||
|
### `npm run build` fails to minify
|
||||||
|
|
||||||
|
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
|
||||||
21
React/cert.pem
Normal file
21
React/cert.pem
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDazCCAlOgAwIBAgIUT3DoD4EzVjOECDlLV/skOjH4sNIwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||||
|
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTAxMDcwNjU0NTdaFw0yMjAx
|
||||||
|
MDcwNjU0NTdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||||
|
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||||
|
AQUAA4IBDwAwggEKAoIBAQCiLrQItvpfLiVGXbe/6tml5PTjKc0az7KReMFFlTc0
|
||||||
|
3KvvD/7bAfwk2RqPEVF3pUTOJ3rGbYBtYi0GdgQbgiSJuuvbUtL+Pf1RRfNR2XZq
|
||||||
|
vfcJiytsVGOvD6JiFEFTn1P+7W2zIYlO7MuqGK2f2Fjb6zeEMG/7rRGvo3YIGfx/
|
||||||
|
vQE6JTWm1HhU0vDpc3pxm2ajW5NjG++7FgoycfQ+BDoQ0XitvWj2b+jt9m2/yPdz
|
||||||
|
9ptj41mDJWvtrPyJti2/3Bprccv/+qWSZGR7Io9+31e35R85sUpFZS91zTNWyy0Z
|
||||||
|
CoSgfpqFg/3ul/ROrAYdtfP2U5TJI4GGxaqFV9QP78DrAgMBAAGjUzBRMB0GA1Ud
|
||||||
|
DgQWBBSgHQxgyIpioCFuWirLuW/ZEwVYvTAfBgNVHSMEGDAWgBSgHQxgyIpioCFu
|
||||||
|
WirLuW/ZEwVYvTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBF
|
||||||
|
uZzW4vwdFfeCt8rqUjDcqnz7FM1al2GccHJ7ofDQYJo8gaWuSH2SeJ11eXKDux8M
|
||||||
|
xP83Nxr4s4rh6DaSybo3wqineMmEJ2F/ikjOMdgvoeTvFV32WAn+UBcmSjvfP6C9
|
||||||
|
HSSryc13nWS31xJ2SuMHkkBeOn4ZhwiRZYcsduVFFhkBpwzQx2HD0Dr0VaEefig4
|
||||||
|
pBQy2llCFGF/u6HoGeB87Cjs0rnWguvseYl28hgsX8fkZY+IWbY8OXL+jy0g0LSc
|
||||||
|
ap9lpqst3WfyFp0UvM7EPjdsxChsSOf4KbC/aHZCqTISRcg8snEHp5Rb6zE8NP/0
|
||||||
|
k62LJlKMPn0z8dS4JEp0
|
||||||
|
-----END CERTIFICATE-----
|
||||||
27
React/key.pem
Normal file
27
React/key.pem
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEAoi60CLb6Xy4lRl23v+rZpeT04ynNGs+ykXjBRZU3NNyr7w/+
|
||||||
|
2wH8JNkajxFRd6VEzid6xm2AbWItBnYEG4Ikibrr21LS/j39UUXzUdl2ar33CYsr
|
||||||
|
bFRjrw+iYhRBU59T/u1tsyGJTuzLqhitn9hY2+s3hDBv+60Rr6N2CBn8f70BOiU1
|
||||||
|
ptR4VNLw6XN6cZtmo1uTYxvvuxYKMnH0PgQ6ENF4rb1o9m/o7fZtv8j3c/abY+NZ
|
||||||
|
gyVr7az8ibYtv9waa3HL//qlkmRkeyKPft9Xt+UfObFKRWUvdc0zVsstGQqEoH6a
|
||||||
|
hYP97pf0TqwGHbXz9lOUySOBhsWqhVfUD+/A6wIDAQABAoIBAATc258LRXSHIKz8
|
||||||
|
cF77vqzfsYwCG9k68wKzmS/p6m7WUv1nAGA2rgW40LgLb+LjfK2lt2OtstUUxX7V
|
||||||
|
GQhuHYRXq2y3DgZ7e1Xtf/8rQwauTXLmzlWALkD4egjwzIiiVVVmbwyY69IG/ZBL
|
||||||
|
DyGkzf1CDzcScLkeFlKq1wYlKVH3H43rlhpP0+VvsVkPMdv3rO/N6tZGD4Dh3wY4
|
||||||
|
Pnf6RQcQVcolD7l2reLxJW7CIBJbnRFuSmtWkRNR+nii0KPxrRFMOLWRpPQlMVs3
|
||||||
|
Ho0x0C+qFghvYTHyQnIPaCsveAyeaQos4ltKSBiYT0+nABdpI39A43DOuTJIcOs4
|
||||||
|
2G4/FokCgYEA1/8sDm9zZeFUX/86dVfixOeWpP6xKqp/XlyvxHbSqLLfn8WaJ9dF
|
||||||
|
azmZWo40o7z2/gTPAVaN3PEnuU3KPCWBVWSFm3bHLzuslXF/Z5l8uqiFvhZNcNNq
|
||||||
|
mGCqMmPxqxgkIMF/aqs+0uj2DkiKvEgWeb7AfyDYPHY/tPpKlqUe8WcCgYEAwDgW
|
||||||
|
uUX6xnastpkeMV/fVl6CA5pdxVUyf4cqMMqdcFza7+dgHLSLX6jDr81zph57UzyC
|
||||||
|
MJ4RUPznhVYSFGtIRLRq83ZDrd2J4obGO0RPzbj2JxiF5o+fmo73uJDtJkZo2EPX
|
||||||
|
50OVXsJa6IES3FiGNxJlAV+TkxnzXjOqJGQ77d0CgYAQqC7/lfyyOKRHGumpLvPf
|
||||||
|
93QYmUOUZL2Zy1AKuJcaR2ETcyumMuW5lSGMaDcLAYGSqVBFbCVYiohjs+oKpWHJ
|
||||||
|
8gyTpp9JtzJh+/S1SpLh2ikmNZYXQ1aPFbVKWYbDiQMQO5vV4AriPPDsvQ9l4bFK
|
||||||
|
BjnWE/RZBU14aWzjHSy7tQKBgCJ+rk1Haq6NA4etSMbRjrHgOfLNlABivrI2HnMt
|
||||||
|
GT3d3AhrfEsKd2yOS7fT5eos1DLmy/JPm4nuKNo7zPjPG+QAgKT6V0DvXdxCFXbz
|
||||||
|
VmLzy3DOrNDoe1rwRzJfB7/zqMMOwcMl1Ltxo4DQEQNr+4IMkgXCEii24n7IRMNN
|
||||||
|
HZgdAoGBALzFDienCJmCUwpYXSLcN6ZqNYSDNQNgjwkWoRjpCYrzpRrcTxLF5o8L
|
||||||
|
Gz6QTXbkYOTZ0UaE9AlR6Aci/4o6RfucLsmbc0EvvyVbrVoX7i3rnH4HOK+RuAvj
|
||||||
|
7KlMPWiIQx4KciuUr8gHCufeCDb1RGvbRPIege8XGnJlQCf4s9sh
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
30
React/keytmp.pem
Normal file
30
React/keytmp.pem
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIxVNNPfT6hrwCAggA
|
||||||
|
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECPLxxQXt0qGZBIIEyE+8XcltU9Fv
|
||||||
|
SsFNOcp3/9saZi7sw0IIitUIF5QU2O2qG8qCQ5hU+OJkFNxwXNgBkwLvvRVS3YAH
|
||||||
|
5kkQ6S5GdoHJhw9LaSycPXYF+bOHt9IIMHmBjMKuXnX3eDL7dXwFf+EHE2HzIjN4
|
||||||
|
mjweE7eSgvuLLZfPsC6/izuCHVc66R6ZsJjQhzCakSPoGiUlZ4JcExDZA3q/NeyH
|
||||||
|
VIYy8dZ4dx1SXiLDd4r7FamRM+WxgNeCCPdZOyVlP0hlOCw1y7tH6I0oG3Ktzrj+
|
||||||
|
o/SV6e6KwQYGs2tETNTrPT0ykkMNUpGRdsx+nTZ2Dy4CVNnqwrZqVxwbVFW3kSQy
|
||||||
|
E1pP08stVbC7IbGpYWuIx2BgK4G96x+sFE8HIxUINOocVZgJQvhoGbW2EJynywZ3
|
||||||
|
tUpz9zNZTyCtKpw7iTbeLa0RVcuqJdP3YKVTYSZCOWO72TMc5WdQ1mqGwRH+i3ze
|
||||||
|
ik1YZNRBNMkLL4UZLcwuA+WfGjkWyIpyuqcqq2IlILaVCGoyWhmOWSug3ezmZTt7
|
||||||
|
eO1mgPvTUhShjlI/3DqFA2hBpq51k6MZUniKPNGcMAdyluVdw3m1MM623vocUZn6
|
||||||
|
b4ZQWldDXYTjSl3yaxjrY154z85HQJGon6Frk2kWX0PIgyNJ4S8JBYn9UvMbxp4I
|
||||||
|
bh2ZZOfIm3R4FyEX+gHpZ1NZH03NImxCK6ND7Ncz9kOPuMokjCPLuZS5XvCpLrvU
|
||||||
|
wDalfVV5TQrt1s9Ir7viZDY4xxNA6FD1rd7eA+2ZHwh0t88l7b02IMQ7hNQ0Ptn9
|
||||||
|
pt3v7xfV4w+ujRk9tFfXv9Nju/hKH6dHpPqhZP1Q1iTf1J2YX++8UCVfgNJSo4e+
|
||||||
|
ORAhvy5ZFfUeiAgtYTlbwSwDlTgGxYQ43ge7zp/B3/BgtUvvWBlZ5PNl/iTvpFUV
|
||||||
|
NeYRWB0HuzFOehDnB3ZsstjPP+ly3yoV6Xef9+aNp08HL966i41+ttNLW8r0W1yQ
|
||||||
|
taYLV3O2BtQwmQFogfaL5gO44fOdmr4aqiSrKGfK72iX+6qqu/b37ucUUVZUpzuA
|
||||||
|
jnoz1ELXUl35f4iW+yC7orIe3jv7n4BiZj/1iHlnqyStFYZlGXFXCb2ieBxHyso5
|
||||||
|
HbHEKa4vcJ0uZR26pIkweOTi1IiB5gJ6Dlw7alDTtl2bIzZ3JJ8sg2m9Y93ewWld
|
||||||
|
8Qapg19tP/ULOv2PpN1PEo62Gyb9WBzue5yTamXsfxupHbsS7nAoi4MVxFwQZYBV
|
||||||
|
/+HiZRYtDYSbn43A/Wo2gS908pRrNWRFBfDd/bzztAiotPJpMYamHDc7w08SEaM4
|
||||||
|
J4tujBIdC8KsewwDwnUvMUev8TXxDMbdjijZcDuaPaUOhPoppiaWbRTtoXKbxUam
|
||||||
|
SdTWuT3dXROLgkgBVD2wyLKWoRKD4SIW1n1gwD6MUr1wnJsss0u2iqSDZvaW9Nsu
|
||||||
|
K1UhAMCbbCG1WSoENaN2tuj+A0Hpk7mEoFZ9yKopipCsMfOouizG5kKWfu4vwkn2
|
||||||
|
xVCNyW6oAwKtM5fPo+Vh7U62t2AEHlQePaGfzWek+B0ptoVLFa6v4UPxrVXO2CTg
|
||||||
|
lseyJH6z2+UV9F0vCWIV/PkaAaVaCeP0q7qTG0E1Wqo7SuGq+q0AOessDeEgfO7m
|
||||||
|
91L5j36PkAKLvjpwgHl4AQ==
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
13326
React/package-lock.json
generated
Normal file
13326
React/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
React/package.json
Normal file
37
React/package.json
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "oidcclient",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.19.0",
|
||||||
|
"milligram": "^1.3.0",
|
||||||
|
"oidc-client": "^1.9.1",
|
||||||
|
"react": "^16.10.0",
|
||||||
|
"react-dom": "^16.10.0",
|
||||||
|
"react-redux": "^7.1.1",
|
||||||
|
"react-router-dom": "^5.1.0",
|
||||||
|
"react-scripts": "3.1.2",
|
||||||
|
"redux": "^4.0.4"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "set HTTPS=true; set SSL_CRT_FILE=cert.pem; set SSL_KEY_FILE=key.pem; react-scripts start",
|
||||||
|
"build": "react-scripts build",
|
||||||
|
"test": "react-scripts test",
|
||||||
|
"eject": "react-scripts eject"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": "react-app"
|
||||||
|
},
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
React/public/favicon.ico
Normal file
BIN
React/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
26
React/public/index.html
Normal file
26
React/public/index.html
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta name="theme-color" content="#000000" />
|
||||||
|
<title>We Want Doughnuts</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
36
React/src/App.js
Normal file
36
React/src/App.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
|
||||||
|
import SigninOidc from './pages/signin-oidc'
|
||||||
|
import SignoutOidc from './pages/signout-oidc'
|
||||||
|
import Home from './pages/home'
|
||||||
|
import Login from './pages/login'
|
||||||
|
import { Provider } from 'react-redux';
|
||||||
|
import store from './store';
|
||||||
|
import userManager, { loadUserFromStorage } from './services/userService'
|
||||||
|
import AuthProvider from './utils/authProvider'
|
||||||
|
import PrivateRoute from './utils/protectedRoute'
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// fetch current user from cookies
|
||||||
|
loadUserFromStorage(store)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Provider store={store}>
|
||||||
|
<AuthProvider userManager={userManager} store={store}>
|
||||||
|
<Router>
|
||||||
|
<Switch>
|
||||||
|
<Route path="/login" component={Login} />
|
||||||
|
<Route path="/signout-oidc" component={SignoutOidc} />
|
||||||
|
<Route path="/signin-oidc" component={SigninOidc} />
|
||||||
|
<PrivateRoute exact path="/" component={Home} />
|
||||||
|
</Switch>
|
||||||
|
</Router>
|
||||||
|
</AuthProvider>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
41
React/src/actions/authActions.js
Normal file
41
React/src/actions/authActions.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import {
|
||||||
|
STORE_USER,
|
||||||
|
USER_SIGNED_OUT,
|
||||||
|
USER_EXPIRED,
|
||||||
|
STORE_USER_ERROR,
|
||||||
|
LOADING_USER
|
||||||
|
} from './types'
|
||||||
|
import { setAuthHeader } from '../utils/axiosHeaders'
|
||||||
|
|
||||||
|
export function storeUser(user) {
|
||||||
|
setAuthHeader(user.access_token)
|
||||||
|
return {
|
||||||
|
type: STORE_USER,
|
||||||
|
payload: user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadingUser() {
|
||||||
|
return {
|
||||||
|
type: LOADING_USER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function storeUserError() {
|
||||||
|
return {
|
||||||
|
type: STORE_USER_ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function userExpired() {
|
||||||
|
return {
|
||||||
|
type: USER_EXPIRED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function userSignedOut() {
|
||||||
|
return {
|
||||||
|
type: USER_SIGNED_OUT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
5
React/src/actions/types.js
Normal file
5
React/src/actions/types.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const STORE_USER = 'STORE_USER'
|
||||||
|
export const USER_SIGNED_OUT = 'USER_SIGNED_OUT'
|
||||||
|
export const USER_EXPIRED = 'USER_EXPIRED'
|
||||||
|
export const STORE_USER_ERROR = 'STORE_USER_ERROR'
|
||||||
|
export const LOADING_USER = 'LOADING_USER'
|
||||||
6
React/src/index.js
Normal file
6
React/src/index.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import 'milligram/dist/milligram.min.css'
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
ReactDOM.render(<App />, document.getElementById('root'));
|
||||||
98
React/src/pages/home.js
Normal file
98
React/src/pages/home.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import React, { useState } from 'react'
|
||||||
|
import { signoutRedirect } from '../services/userService'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
import * as apiService from '../services/apiService'
|
||||||
|
import { prettifyJson } from '../utils/jsonUtils'
|
||||||
|
|
||||||
|
function Home() {
|
||||||
|
const user = useSelector(state => state.auth.user)
|
||||||
|
const [model, setModel] = useState('')
|
||||||
|
const [licensePlate, setlicensePlate] = useState('')
|
||||||
|
const [color, setColor] = useState('White')
|
||||||
|
const [type, setType] = useState(1)
|
||||||
|
|
||||||
|
const [vehicleData, setVehicleData] = useState(null)
|
||||||
|
function signOut() {
|
||||||
|
signoutRedirect()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getVehicles() {
|
||||||
|
console.log(user);
|
||||||
|
const vehicles = await apiService.getVehiclesFromApi(user.access_token);
|
||||||
|
setVehicleData(vehicles);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerVehicle() {
|
||||||
|
await apiService.registerVehicle({ model, licensePlate, color, type }, user.access_token);
|
||||||
|
await getVehicles();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getType(type) {
|
||||||
|
switch (type){
|
||||||
|
case 1:
|
||||||
|
return "Sedan";
|
||||||
|
case 2:
|
||||||
|
return "SUV";
|
||||||
|
case 3:
|
||||||
|
return "Pickup";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// async function getDoughnuts() {
|
||||||
|
// console.log(user);
|
||||||
|
// const doughnuts = await apiService.getDoughnutsFromApi(user.id);
|
||||||
|
// setDoughnutData(doughnuts)
|
||||||
|
// }
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Traffic Police</h1>
|
||||||
|
<p>Hello, {user.profile.given_name}.</p>
|
||||||
|
|
||||||
|
<button className="button button-outline" onClick={() => getVehicles()}>Get Vehicles</button>
|
||||||
|
<button className="button button-clear" onClick={() => signOut()}>Sign Out</button>
|
||||||
|
|
||||||
|
<h3>Register Vehicle:</h3>
|
||||||
|
|
||||||
|
<form onSubmit={e => e.preventDefault()}>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Model: </label>
|
||||||
|
<input value={model} type="text" name="model" onChange={e => setModel(e.target.value)} />
|
||||||
|
<label>License Plate: </label>
|
||||||
|
<input value={licensePlate} type="text" name="licensePlate" onChange={e => setlicensePlate(e.target.value)} />
|
||||||
|
<label>Color: </label>
|
||||||
|
<input value={color} type="text" name="color" onChange={e => setColor(e.target.value)} />
|
||||||
|
<label>Type: </label>
|
||||||
|
<select value={type} name="type" onChange={e => setType(e.target.value)} >
|
||||||
|
<option value="1">Sedan</option>
|
||||||
|
<option value="2">SUV</option>
|
||||||
|
<option value="3">Pickup</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button className="btn" onClick={() => registerVehicle()} >Register</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<h3>Your Vehicles:</h3>
|
||||||
|
|
||||||
|
{
|
||||||
|
vehicleData ?
|
||||||
|
<ul>
|
||||||
|
{ vehicleData.map(v => (<li>{v.color} {v.model} ({v.licensePlate}) - {getType(v.type)}</li>)) }
|
||||||
|
</ul>
|
||||||
|
:
|
||||||
|
<p>No vehicles yet :(</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
{prettifyJson(vehicleData ? vehicleData : 'No vehicles yet :(')}
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
<p><a target='_blank' rel='noopener noreferrer' href='https://github.com/tappyy/react-IS4-auth-demo'>Github Repo</a></p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Home
|
||||||
32
React/src/pages/login.js
Normal file
32
React/src/pages/login.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { signinRedirect } from '../services/userService'
|
||||||
|
import { Redirect } from 'react-router-dom'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
|
function Login() {
|
||||||
|
const user = useSelector(state => state.auth.user)
|
||||||
|
|
||||||
|
function login() {
|
||||||
|
signinRedirect()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
(user) ?
|
||||||
|
(<Redirect to={'/'} />)
|
||||||
|
:
|
||||||
|
(
|
||||||
|
<div>
|
||||||
|
<h1>Hello!</h1>
|
||||||
|
<p>Welcome to We Want Doughnuts.</p>
|
||||||
|
<p>A demo of using React and Identity Server 4 to authenticate a user via OpenID Connect to gain access to a web API (and some lovely doughnuts).</p>
|
||||||
|
<p>Start by signing in.</p>
|
||||||
|
<p>💡 <strong>Tip: </strong><em>User: 'spiderman', Pass: 'spiderman'</em></p>
|
||||||
|
|
||||||
|
<button onClick={() => login()}>Login</button>
|
||||||
|
<p><a target='_blank' rel='noopener noreferrer' href='https://github.com/tappyy/react-IS4-auth-demo'>Github Repo</a></p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Login
|
||||||
22
React/src/pages/signin-oidc.js
Normal file
22
React/src/pages/signin-oidc.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import React, { useEffect } from 'react'
|
||||||
|
import { signinRedirectCallback } from '../services/userService'
|
||||||
|
import { useHistory } from 'react-router-dom'
|
||||||
|
|
||||||
|
function SigninOidc() {
|
||||||
|
const history = useHistory()
|
||||||
|
useEffect(() => {
|
||||||
|
async function signinAsync() {
|
||||||
|
await signinRedirectCallback()
|
||||||
|
history.push('/')
|
||||||
|
}
|
||||||
|
signinAsync()
|
||||||
|
}, [history])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Redirecting...
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SigninOidc
|
||||||
22
React/src/pages/signout-oidc.js
Normal file
22
React/src/pages/signout-oidc.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import React, { useEffect } from 'react'
|
||||||
|
import { signoutRedirectCallback } from '../services/userService'
|
||||||
|
import { useHistory } from 'react-router-dom'
|
||||||
|
|
||||||
|
function SignoutOidc() {
|
||||||
|
const history = useHistory()
|
||||||
|
useEffect(() => {
|
||||||
|
async function signoutAsync() {
|
||||||
|
await signoutRedirectCallback()
|
||||||
|
history.push('/')
|
||||||
|
}
|
||||||
|
signoutAsync()
|
||||||
|
}, [history])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Redirecting...
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SignoutOidc
|
||||||
38
React/src/reducers/authReducer.js
Normal file
38
React/src/reducers/authReducer.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
USER_SIGNED_OUT,
|
||||||
|
STORE_USER_ERROR,
|
||||||
|
USER_EXPIRED,
|
||||||
|
STORE_USER,
|
||||||
|
LOADING_USER
|
||||||
|
} from '../actions/types'
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
user: null,
|
||||||
|
isLoadingUser: false
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case STORE_USER:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isLoadingUser: false,
|
||||||
|
user: action.payload
|
||||||
|
}
|
||||||
|
case LOADING_USER:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isLoadingUser: true
|
||||||
|
}
|
||||||
|
case USER_EXPIRED:
|
||||||
|
case STORE_USER_ERROR:
|
||||||
|
case USER_SIGNED_OUT:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
user: null,
|
||||||
|
isLoadingUser: false
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
6
React/src/reducers/index.js
Normal file
6
React/src/reducers/index.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { combineReducers } from 'redux';
|
||||||
|
import authReducer from './authReducer';
|
||||||
|
|
||||||
|
export default combineReducers({
|
||||||
|
auth: authReducer
|
||||||
|
})
|
||||||
17
React/src/services/apiService.js
Normal file
17
React/src/services/apiService.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
async function getVehiclesFromApi(access_token) {
|
||||||
|
const response = await axios.get(`https://localhost:5001/api/Vehicles`, { headers: { 'Authorization': `Bearer ${access_token}` } });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerVehicle(vehicle, access_token) {
|
||||||
|
console.log(vehicle);
|
||||||
|
const response = await axios.post(`https://localhost:5001/api/Vehicles`, vehicle, { headers: { 'Authorization': `Bearer ${access_token}` } });
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getVehiclesFromApi,
|
||||||
|
registerVehicle
|
||||||
|
}
|
||||||
46
React/src/services/userService.js
Normal file
46
React/src/services/userService.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { UserManager } from 'oidc-client';
|
||||||
|
import { storeUserError, storeUser } from '../actions/authActions'
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
authority: "https://localhost:5003",
|
||||||
|
client_id: "f42aec810e6a4980827037b6ffa7f968",
|
||||||
|
redirect_uri: "https://localhost:3000/signin-oidc",
|
||||||
|
response_type: "code",
|
||||||
|
scope: "openid profile traffic-police-api",
|
||||||
|
post_logout_redirect_uri: "https://localhost:3000/signout-oidc",
|
||||||
|
};
|
||||||
|
|
||||||
|
const userManager = new UserManager(config)
|
||||||
|
|
||||||
|
export async function loadUserFromStorage(store) {
|
||||||
|
try {
|
||||||
|
let user = await userManager.getUser()
|
||||||
|
if (!user) { return store.dispatch(storeUserError()) }
|
||||||
|
store.dispatch(storeUser(user))
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`User not found: ${e}`)
|
||||||
|
store.dispatch(storeUserError())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function signinRedirect() {
|
||||||
|
return userManager.signinRedirect()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function signinRedirectCallback() {
|
||||||
|
return userManager.signinRedirectCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function signoutRedirect() {
|
||||||
|
userManager.clearStaleState()
|
||||||
|
userManager.removeUser()
|
||||||
|
return userManager.signoutRedirect()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function signoutRedirectCallback() {
|
||||||
|
userManager.clearStaleState()
|
||||||
|
userManager.removeUser()
|
||||||
|
return userManager.signoutRedirectCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default userManager
|
||||||
13
React/src/store.js
Normal file
13
React/src/store.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { createStore, compose } from 'redux';
|
||||||
|
import rootReducer from './reducers'
|
||||||
|
|
||||||
|
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||||
|
const initialState = {}
|
||||||
|
|
||||||
|
const store = createStore(
|
||||||
|
rootReducer,
|
||||||
|
initialState,
|
||||||
|
composeEnhancers()
|
||||||
|
)
|
||||||
|
|
||||||
|
export default store;
|
||||||
54
React/src/utils/authProvider.js
Normal file
54
React/src/utils/authProvider.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import React, { useEffect, useRef } from 'react';
|
||||||
|
import { storeUser } from '../actions/authActions'
|
||||||
|
import { setAuthHeader } from './axiosHeaders';
|
||||||
|
|
||||||
|
export default function AuthProvider({ userManager: manager, store, children }) {
|
||||||
|
|
||||||
|
let userManager = useRef();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
userManager.current = manager
|
||||||
|
|
||||||
|
const onUserLoaded = (user) => {
|
||||||
|
console.log(`user loaded: ${user}`)
|
||||||
|
store.dispatch(storeUser(user))
|
||||||
|
}
|
||||||
|
|
||||||
|
const onUserUnloaded = () => {
|
||||||
|
setAuthHeader(null)
|
||||||
|
console.log(`user unloaded`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAccessTokenExpiring = () => {
|
||||||
|
console.log(`user token expiring`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAccessTokenExpired = () => {
|
||||||
|
console.log(`user token expired`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onUserSignedOut = () => {
|
||||||
|
console.log(`user signed out`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// events for user
|
||||||
|
userManager.current.events.addUserLoaded(onUserLoaded)
|
||||||
|
userManager.current.events.addUserUnloaded(onUserUnloaded)
|
||||||
|
userManager.current.events.addAccessTokenExpiring(onAccessTokenExpiring)
|
||||||
|
userManager.current.events.addAccessTokenExpired(onAccessTokenExpired)
|
||||||
|
userManager.current.events.addUserSignedOut(onUserSignedOut)
|
||||||
|
|
||||||
|
// Specify how to clean up after this effect:
|
||||||
|
return function cleanup() {
|
||||||
|
userManager.current.events.removeUserLoaded(onUserLoaded);
|
||||||
|
userManager.current.events.removeUserUnloaded(onUserUnloaded);
|
||||||
|
userManager.current.events.removeAccessTokenExpiring(onAccessTokenExpiring)
|
||||||
|
userManager.current.events.removeAccessTokenExpired(onAccessTokenExpired)
|
||||||
|
userManager.current.events.removeUserSignedOut(onUserSignedOut)
|
||||||
|
};
|
||||||
|
}, [manager, store]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
React.Children.only(children)
|
||||||
|
)
|
||||||
|
}
|
||||||
5
React/src/utils/axiosHeaders.js
Normal file
5
React/src/utils/axiosHeaders.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export function setAuthHeader(token) {
|
||||||
|
axios.defaults.headers.common['Authorization'] = token ? 'Bearer ' + token : ''
|
||||||
|
}
|
||||||
3
React/src/utils/jsonUtils.js
Normal file
3
React/src/utils/jsonUtils.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const prettifyJson = (value) => {
|
||||||
|
return JSON.stringify(value, null, 2);
|
||||||
|
}
|
||||||
13
React/src/utils/protectedRoute.js
Normal file
13
React/src/utils/protectedRoute.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { Route, Redirect } from 'react-router-dom'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
|
function ProtectedRoute({ children, component: Component, ...rest }) {
|
||||||
|
const user = useSelector(state => state.auth.user)
|
||||||
|
|
||||||
|
return user
|
||||||
|
? (<Route {...rest} component={Component} />)
|
||||||
|
: (<Redirect to={'/login'} />)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProtectedRoute
|
||||||
10782
React/yarn.lock
Normal file
10782
React/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user