Skip to content

Commit 4dc2a43

Browse files
committed
initial commit
0 parents  commit 4dc2a43

16 files changed

+398
-0
lines changed

.gitignore

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
6+
# Runtime data
7+
pids
8+
*.pid
9+
*.seed
10+
11+
# Directory for instrumented libs generated by jscoverage/JSCover
12+
lib-cov
13+
14+
# Coverage directory used by tools like istanbul
15+
coverage
16+
17+
# nyc test coverage
18+
.nyc_output
19+
20+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21+
.grunt
22+
23+
# node-waf configuration
24+
.lock-wscript
25+
26+
# Compiled binary addons (http://nodejs.org/api/addons.html)
27+
build/Release
28+
29+
# Dependency directories
30+
node_modules
31+
jspm_packages
32+
typings
33+
34+
# Optional npm cache directory
35+
.npm
36+
37+
# Optional REPL history
38+
.node_repl_history
39+
40+
# .NET compiled files
41+
bin
42+
obj

.vscode/launch.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": ".NET Core Launch (web)",
9+
"type": "coreclr",
10+
"request": "launch",
11+
"preLaunchTask": "build",
12+
// If you have changed target frameworks, make sure to update the program path.
13+
"program": "${workspaceFolder}/bin/Debug/netcoreapp3.0/WebApi.dll",
14+
"args": [],
15+
"cwd": "${workspaceFolder}",
16+
"stopAtEntry": false,
17+
"internalConsoleOptions": "openOnSessionStart",
18+
"env": {
19+
"ASPNETCORE_ENVIRONMENT": "Development"
20+
},
21+
"sourceFileMap": {
22+
"/Views": "${workspaceFolder}/Views"
23+
}
24+
},
25+
{
26+
"name": ".NET Core Attach",
27+
"type": "coreclr",
28+
"request": "attach",
29+
"processId": "${command:pickProcess}"
30+
}
31+
]
32+
}

.vscode/tasks.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "build",
6+
"command": "dotnet",
7+
"type": "process",
8+
"args": [
9+
"build",
10+
"${workspaceFolder}/WebApi.csproj",
11+
"/property:GenerateFullPaths=true",
12+
"/consoleloggerparameters:NoSummary"
13+
],
14+
"problemMatcher": "$msCompile"
15+
}
16+
]
17+
}

Controllers/UsersController.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.AspNetCore.Authorization;
3+
using WebApi.Services;
4+
using System.Threading.Tasks;
5+
using WebApi.Models;
6+
7+
namespace WebApi.Controllers
8+
{
9+
[Authorize]
10+
[ApiController]
11+
[Route("[controller]")]
12+
public class UsersController : ControllerBase
13+
{
14+
private IUserService _userService;
15+
16+
public UsersController(IUserService userService)
17+
{
18+
_userService = userService;
19+
}
20+
21+
[AllowAnonymous]
22+
[HttpPost("authenticate")]
23+
public async Task<IActionResult> Authenticate([FromBody]AuthenticateModel model)
24+
{
25+
var user = await _userService.Authenticate(model.Username, model.Password);
26+
27+
if (user == null)
28+
return BadRequest(new { message = "Username or password is incorrect" });
29+
30+
return Ok(user);
31+
}
32+
33+
[HttpGet]
34+
public async Task<IActionResult> GetAll()
35+
{
36+
var users = await _userService.GetAll();
37+
return Ok(users);
38+
}
39+
}
40+
}

Entities/User.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace WebApi.Entities
2+
{
3+
public class User
4+
{
5+
public int Id { get; set; }
6+
public string FirstName { get; set; }
7+
public string LastName { get; set; }
8+
public string Username { get; set; }
9+
public string Password { get; set; }
10+
}
11+
}

Helpers/BasicAuthenticationHandler.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.Net.Http.Headers;
3+
using System.Security.Claims;
4+
using System.Text;
5+
using System.Text.Encodings.Web;
6+
using System.Threading.Tasks;
7+
using Microsoft.AspNetCore.Authentication;
8+
using Microsoft.Extensions.Logging;
9+
using Microsoft.Extensions.Options;
10+
using WebApi.Entities;
11+
using WebApi.Services;
12+
13+
namespace WebApi.Helpers
14+
{
15+
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
16+
{
17+
private readonly IUserService _userService;
18+
19+
public BasicAuthenticationHandler(
20+
IOptionsMonitor<AuthenticationSchemeOptions> options,
21+
ILoggerFactory logger,
22+
UrlEncoder encoder,
23+
ISystemClock clock,
24+
IUserService userService)
25+
: base(options, logger, encoder, clock)
26+
{
27+
_userService = userService;
28+
}
29+
30+
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
31+
{
32+
if (!Request.Headers.ContainsKey("Authorization"))
33+
return AuthenticateResult.Fail("Missing Authorization Header");
34+
35+
User user = null;
36+
try
37+
{
38+
var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
39+
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
40+
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
41+
var username = credentials[0];
42+
var password = credentials[1];
43+
user = await _userService.Authenticate(username, password);
44+
}
45+
catch
46+
{
47+
return AuthenticateResult.Fail("Invalid Authorization Header");
48+
}
49+
50+
if (user == null)
51+
return AuthenticateResult.Fail("Invalid Username or Password");
52+
53+
var claims = new[] {
54+
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
55+
new Claim(ClaimTypes.Name, user.Username),
56+
};
57+
var identity = new ClaimsIdentity(claims, Scheme.Name);
58+
var principal = new ClaimsPrincipal(identity);
59+
var ticket = new AuthenticationTicket(principal, Scheme.Name);
60+
61+
return AuthenticateResult.Success(ticket);
62+
}
63+
}
64+
}

Helpers/ExtensionMethods.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using WebApi.Entities;
4+
5+
namespace WebApi.Helpers
6+
{
7+
public static class ExtensionMethods
8+
{
9+
public static IEnumerable<User> WithoutPasswords(this IEnumerable<User> users) {
10+
return users.Select(x => x.WithoutPassword());
11+
}
12+
13+
public static User WithoutPassword(this User user) {
14+
user.Password = null;
15+
return user;
16+
}
17+
}
18+
}

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2019 Jason Watmore
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Models/AuthenticateModel.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.ComponentModel.DataAnnotations;
2+
3+
namespace WebApi.Models
4+
{
5+
public class AuthenticateModel
6+
{
7+
[Required]
8+
public string Username { get; set; }
9+
10+
[Required]
11+
public string Password { get; set; }
12+
}
13+
}

Program.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Microsoft.AspNetCore.Hosting;
2+
using Microsoft.Extensions.Hosting;
3+
4+
namespace WebApi
5+
{
6+
public class Program
7+
{
8+
public static void Main(string[] args)
9+
{
10+
CreateHostBuilder(args).Build().Run();
11+
}
12+
13+
public static IHostBuilder CreateHostBuilder(string[] args) =>
14+
Host.CreateDefaultBuilder(args)
15+
.ConfigureWebHostDefaults(webBuilder =>
16+
{
17+
webBuilder.UseStartup<Startup>()
18+
.UseUrls("http://localhost:4000");
19+
});
20+
}
21+
}

0 commit comments

Comments
 (0)