Merge pull request #3 from Flight-Simulator-EFB/login

login feature
This commit is contained in:
Luke Else 2021-11-08 07:04:12 +00:00 committed by GitHub
commit 5845229628
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 11910 additions and 961 deletions

35
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,35 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/bin/Debug/net5.0/EFB.dll",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

42
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,42 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/EFB.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/EFB.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"${workspaceFolder}/EFB.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@ -0,0 +1,90 @@
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Net.Http;
using EFB.Models;
namespace EFB.Controllers.API
{
public class APIInterface
{
private HttpClient HttpClient { get; set; }
public async Task<ResponseModel> Get<T>(string Endpoint, Dictionary<string, string> Headers){
this.HttpClient = new HttpClient();
this.HttpClient.DefaultRequestHeaders.Clear();
if (Headers != null)
{
foreach (var Header in Headers)
{
this.HttpClient.DefaultRequestHeaders.Add(Header.Key, Header.Value);
}
}
if (Form.FormAuthenticator.ValidateEndpoint(Endpoint))
{
try
{
var pendingResult = this.HttpClient.GetAsync(Endpoint);
var result = await pendingResult;
string resultString = result.Content.ReadAsStringAsync().Result;
return new ResponseModel{
//Sender should be aware of type T becuase of Generic function
Result = JsonConvert.DeserializeObject<T>(resultString)
};
}
catch (System.Exception e)
{
return new ResponseModel{Error = e.Message};
}
}
//Returned in the event No other response has been returned
return new ResponseModel{Error = "Invalid Endpoint - Please try again later"};
}
public async Task<ResponseModel> Post<T>(string Endpoint, Dictionary<string, string> Headers, HttpContent Body){
this.HttpClient = new HttpClient();
this.HttpClient.DefaultRequestHeaders.Clear();
if (Headers != null)
{
foreach (var Header in Headers)
{
this.HttpClient.DefaultRequestHeaders.Add(Header.Key, Header.Value);
}
}
if (Form.FormAuthenticator.ValidateEndpoint(Endpoint))
{
try{//Try statement to catch errors in the process of making the request
var pendingResult = this.HttpClient.PostAsync(Endpoint, Body);
var result = await pendingResult;
string resultString = result.Content.ReadAsStringAsync().Result;
return new ResponseModel{
//Sender should be aware of type T becuase of Generic function
Result = JsonConvert.DeserializeObject<T>(resultString)
};
}catch(System.Exception e){
return new ResponseModel{Error = e.Message};
}
}
//Returned in the event No other response has been returned
return new ResponseModel{Error = "Invalid Endpoint - Please try again later"};
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace EFB.Controllers.Form
{
public static class FormAuthenticator
{
public static bool ValidateEMail(string EMail){
if (EMail.Contains("@") && EMail.Contains(".") && !EMail.Contains(" "))
{
if (EMail.Count(x => x == '@') == 1)
{
return true;
}
}
return false;
}
public static bool ValidateEndpoint(string Endpoint){
//If it contains http & :// it can be either https or http
if (Endpoint.Contains("http") && Endpoint.Contains("://") && Endpoint.Length > 7)
{
return true;
}
return false;
}
public static bool ValidateICAOCode(string ICAO){
if (ICAO.Length == 4)
{
//If the value contains a Number, then the value will return false
return !ICAO.Any(x => char.IsDigit(x));
}
return false;
}
public static bool ValidateCruiseAlt(int CruiseAlt){
if (CruiseAlt > 0 && CruiseAlt < 50000)
{
return true;
}
return false;
}
}
}

View File

@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using System.Net.Http;
using EFB.Models.JSON;
using Microsoft.Extensions.Logging;
using EFB.Models;
using EFB.Sessions;
namespace EFB.Controllers
{
//[Route("[controller]")]
public class UserController : Controller
{
private readonly ILogger<UserController> _logger;
public UserController(ILogger<UserController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public async Task<IActionResult> Login(string email, string password){
if (Form.FormAuthenticator.ValidateEMail(email))
{
//API Helper
API.APIInterface API = new API.APIInterface();
//Dictionary of Formdata to be encoded
Dictionary<string, string> formData = new Dictionary<string, string>();
formData.Add("grant_type", "client_credentials");
formData.Add("client_id", email);
formData.Add("client_secret", password);
HttpContent content = new FormUrlEncodedContent(formData);
var request = API.Post<Models.JSON.LoginResponse>("https://api.autorouter.aero/v1.0/oauth2/token", null, content);
//Wait for the response to come through
ResponseModel response = await request;
if (response.Error != null)
{
TempData["Error"] = response.Error;
TempData["email"] = email;
return RedirectToAction("Index", "Home");
}else{
//Type cast required but we know response will be of known type
LoginResponse login = (LoginResponse)response.Result;
//Generate User Session
if (login.error == null)
{
UserModel user = new UserModel{
EMail = email,
Token = new TokenModel{
Token = login.access_token,
Expiration = DateTime.UtcNow.AddSeconds(login.expires_in)
}
};
//Using Session Extensions (Store the user session)
HttpContext.Session.SetObject("User", user);
return RedirectToAction("App", "Home");
}else{
TempData["Error"] = login.error_description;
TempData["email"] = email;
return RedirectToAction("Index", "Home");
}
}
}else{
TempData["Error"] = "Please enter a valid E-Mail";
return RedirectToAction("Index", "Home");
}
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View("Error!");
}
}
}

View File

@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
</Project>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
</ItemGroup>
</Project>

19
Models/JSON/Login.cs Normal file
View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using System.Threading.Tasks;
namespace EFB.Models.JSON
{
public class Login
{
[JsonProperty]
public string grant_type { get; set; }
[JsonProperty]
public string client_id { get; set; }
[JsonProperty]
public string client_secret { get; set; }
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace EFB.Models.JSON
{
public class LoginResponse
{
[JsonProperty]
public string access_token { get; set; }
[JsonProperty]
public int expires_in { get; set; }
[JsonProperty]
public string token_type { get; set; }
[JsonProperty]
public string scope { get; set; }
[JsonProperty]
public string error { get; set; } = null;
[JsonProperty]
public string error_description { get; set; } = null;
}
}

16
Models/ResponseModel.cs Normal file
View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace EFB.Models
{
public class ResponseModel
{
//Object should be of known type from sender
public object Result { get; set; } = null;
public string Error { get; set; } = null;
}
}

View File

@ -26,14 +26,5 @@ namespace EFB.Models
//Contains the most recently stored position of the user in the simulator
public object SimPosition { get; set; } = null;
}
}

View File

@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
namespace EFB.Sessions
{
public static class SessionExtensions
{
public static void SetObject(this ISession session, string key, object value)
{//Sets the object of a session to Object
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T GetObject<T>(this ISession session, string key)
{//Gets a session of known type (T)
var value = session.GetString(key);
return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
}
}
}

View File

@ -24,6 +24,7 @@ namespace EFB
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSession();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -44,6 +45,8 @@ namespace EFB
app.UseRouting();
app.UseSession();
app.UseAuthorization();
app.UseEndpoints(endpoints =>

View File

@ -1,8 +1,43 @@
@{
ViewData["Title"] = "Home Page";
ViewData["Title"] = "Welcome";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
<div class="row">
<div class="card-body col-md-6">
<div class="container jumbotron">
<h3>AutoRouter Login</h3>
<br />
<br />
<form asp-controller="User" asp-action="Login">
<div class="form-group">
<input type="text" class="form-control" placeholder="E-Mail" name="email" value="@TempData["email"]">
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="Password" name="password">
</div>
<button type="submit" class="btn btn-secondary">Login</button>
@{
if (TempData["Error"] != null)
{//If an error has been flagged, information will be displayed to the user
<br />
<br />
<div class="alert alert-danger">
<strong>Warning!</strong> @TempData["Error"] <button type='button' class='close' data-dismiss='alert' aria-hidden='true' />&times;
</div>
}
}
</form>
</div>
</div>
<div class="card-body mh-100 bg-warning col-md-6">
<img src="/images/MainImage.png" width="100%" height="100%" style="object-fit: cover;">
</div>
</div>

View File

@ -9,9 +9,9 @@
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-dark bg-dark border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">EFB</a>
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Electronic Flight Bag</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
@ -19,10 +19,7 @@
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
<a class="nav-link text-light" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
</ul>
</div>
@ -32,12 +29,15 @@
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
@{
//Render body is used to load the relevant view in relation to the controller
}
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
&copy; 2021 - EFB - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
&copy; 2021 - EFB - <a href="https://luke-else.co.uk">Luke Else</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long