Skip to content

Commit 9b17de4

Browse files
committed
initial commit
0 parents  commit 9b17de4

14 files changed

+374
-0
lines changed

.gitignore

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
# Generated files
41+
client/app/**/*.js
42+
client/app/**/*.js.map
43+
44+
# .NET compiled files
45+
bin
46+
obj

.vscode/launch.json

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
// Use IntelliSense to find out which attributes exist for C# debugging
3+
// Use hover for the description of the existing attributes
4+
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
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": "${workspaceRoot}/bin/Debug/netcoreapp2.1/WebApi.dll",
14+
"args": [],
15+
"cwd": "${workspaceRoot}",
16+
"stopAtEntry": false,
17+
"internalConsoleOptions": "openOnSessionStart",
18+
"env": {
19+
"ASPNETCORE_ENVIRONMENT": "Development"
20+
},
21+
"sourceFileMap": {
22+
"/Views": "${workspaceRoot}/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

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"version": "0.1.0",
3+
"command": "dotnet",
4+
"isShellCommand": true,
5+
"args": [],
6+
"tasks": [
7+
{
8+
"taskName": "build",
9+
"args": [
10+
"${workspaceRoot}/WebApi.csproj"
11+
],
12+
"isBuildCommand": true,
13+
"problemMatcher": "$msCompile"
14+
}
15+
]
16+
}

Controllers/UsersController.cs

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

Entities/User.cs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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+
public string Token { get; set; }
11+
}
12+
}

Helpers/AppSettings.cs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace WebApi.Helpers
2+
{
3+
public class AppSettings
4+
{
5+
public string Secret { get; set; }
6+
}
7+
}

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2018 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.

Program.cs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.IO;
2+
using Microsoft.AspNetCore;
3+
using Microsoft.AspNetCore.Hosting;
4+
5+
namespace WebApi
6+
{
7+
public class Program
8+
{
9+
public static void Main(string[] args)
10+
{
11+
BuildWebHost(args).Run();
12+
}
13+
14+
public static IWebHost BuildWebHost(string[] args) =>
15+
WebHost.CreateDefaultBuilder(args)
16+
.UseStartup<Startup>()
17+
.UseUrls("http://localhost:4000")
18+
.Build();
19+
}
20+
}

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# aspnet-core-jwt-authentication-api
2+
3+
ASP.NET Core 2.1 - JWT Authentication API

Services/UserService.cs

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IdentityModel.Tokens.Jwt;
4+
using System.Linq;
5+
using System.Security.Claims;
6+
using System.Text;
7+
using Microsoft.Extensions.Options;
8+
using Microsoft.IdentityModel.Tokens;
9+
using WebApi.Entities;
10+
using WebApi.Helpers;
11+
12+
namespace WebApi.Services
13+
{
14+
public interface IUserService
15+
{
16+
User Authenticate(string username, string password);
17+
IEnumerable<User> GetAll();
18+
}
19+
20+
public class UserService : IUserService
21+
{
22+
// users hardcoded for simplicity, store in a db with hashed passwords in production applications
23+
private List<User> _users = new List<User>
24+
{
25+
new User { Id = 1, FirstName = "Test", LastName = "User", Username = "test", Password = "test" }
26+
};
27+
28+
private readonly AppSettings _appSettings;
29+
30+
public UserService(IOptions<AppSettings> appSettings)
31+
{
32+
_appSettings = appSettings.Value;
33+
}
34+
35+
public User Authenticate(string username, string password)
36+
{
37+
var user = _users.SingleOrDefault(x => x.Username == username && x.Password == password);
38+
39+
// return null if user not found
40+
if (user == null)
41+
return null;
42+
43+
// authentication successful so generate jwt token
44+
var tokenHandler = new JwtSecurityTokenHandler();
45+
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
46+
var tokenDescriptor = new SecurityTokenDescriptor
47+
{
48+
Subject = new ClaimsIdentity(new Claim[]
49+
{
50+
new Claim(ClaimTypes.Name, user.Id.ToString())
51+
}),
52+
Expires = DateTime.UtcNow.AddDays(7),
53+
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
54+
};
55+
var token = tokenHandler.CreateToken(tokenDescriptor);
56+
user.Token = tokenHandler.WriteToken(token);
57+
58+
// remove password before returning
59+
user.Password = null;
60+
61+
return user;
62+
}
63+
64+
public IEnumerable<User> GetAll()
65+
{
66+
// return users without passwords
67+
return _users.Select(x => {
68+
x.Password = null;
69+
return x;
70+
});
71+
}
72+
}
73+
}

Startup.cs

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using Microsoft.AspNetCore.Builder;
2+
using Microsoft.AspNetCore.Hosting;
3+
using Microsoft.Extensions.Configuration;
4+
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.Logging;
6+
using WebApi.Helpers;
7+
using WebApi.Services;
8+
using Microsoft.IdentityModel.Tokens;
9+
using System.Text;
10+
using Microsoft.AspNetCore.Authentication.JwtBearer;
11+
12+
namespace WebApi
13+
{
14+
public class Startup
15+
{
16+
public Startup(IConfiguration configuration)
17+
{
18+
Configuration = configuration;
19+
}
20+
21+
public IConfiguration Configuration { get; }
22+
23+
// This method gets called by the runtime. Use this method to add services to the container.
24+
public void ConfigureServices(IServiceCollection services)
25+
{
26+
services.AddCors();
27+
services.AddMvc();
28+
29+
// configure strongly typed settings objects
30+
var appSettingsSection = Configuration.GetSection("AppSettings");
31+
services.Configure<AppSettings>(appSettingsSection);
32+
33+
// configure jwt authentication
34+
var appSettings = appSettingsSection.Get<AppSettings>();
35+
var key = Encoding.ASCII.GetBytes(appSettings.Secret);
36+
services.AddAuthentication(x =>
37+
{
38+
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
39+
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
40+
})
41+
.AddJwtBearer(x =>
42+
{
43+
x.RequireHttpsMetadata = false;
44+
x.SaveToken = true;
45+
x.TokenValidationParameters = new TokenValidationParameters
46+
{
47+
ValidateIssuerSigningKey = true,
48+
IssuerSigningKey = new SymmetricSecurityKey(key),
49+
ValidateIssuer = false,
50+
ValidateAudience = false
51+
};
52+
});
53+
54+
// configure DI for application services
55+
services.AddScoped<IUserService, UserService>();
56+
}
57+
58+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
59+
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
60+
{
61+
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
62+
loggerFactory.AddDebug();
63+
64+
// global cors policy
65+
app.UseCors(x => x
66+
.AllowAnyOrigin()
67+
.AllowAnyMethod()
68+
.AllowAnyHeader()
69+
.AllowCredentials());
70+
71+
app.UseAuthentication();
72+
73+
app.UseMvc();
74+
}
75+
}
76+
}

WebApi.csproj

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
<PropertyGroup>
3+
<TargetFramework>netcoreapp2.1</TargetFramework>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<PackageReference Include="Microsoft.AspNetCore.App" />
7+
</ItemGroup>
8+
</Project>

appsettings.Development.json

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"Logging": {
3+
"IncludeScopes": false,
4+
"LogLevel": {
5+
"Default": "Debug",
6+
"System": "Information",
7+
"Microsoft": "Information"
8+
}
9+
}
10+
}

appsettings.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"AppSettings": {
3+
"Secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING"
4+
},
5+
"Logging": {
6+
"IncludeScopes": false,
7+
"LogLevel": {
8+
"Default": "Warning"
9+
}
10+
}
11+
}

0 commit comments

Comments
 (0)