-
Notifications
You must be signed in to change notification settings - Fork 60
Expand file tree
/
Copy pathStartup.cs
More file actions
126 lines (109 loc) · 5.68 KB
/
Startup.cs
File metadata and controls
126 lines (109 loc) · 5.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
using System;
using System.IdentityModel.Tokens;
using Microsoft.AspNet.Authentication.JwtBearer;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using System.Security.Cryptography;
using Microsoft.AspNet.Authorization;
using Microsoft.AspNet.Diagnostics;
using Newtonsoft.Json;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
namespace TokenAuthExampleWebApplication
{
public class Startup
{
const string TokenAudience = "ExampleAudience";
const string TokenIssuer = "ExampleIssuer";
private RsaSecurityKey key;
private TokenAuthOptions tokenOptions;
public Startup(IHostingEnvironment env)
{
}
public void ConfigureServices(IServiceCollection services)
{
// Fetching key from KeyContainer, if the key does not exist, we create it.
var keyFromContainer = KeyContainer.GetKeyFromContainer("TokenAuthExample");
// Create the key, and a set of token options to record signing credentials
// using that key, along with the other parameters we will need in the
// token controlller.
tokenOptions = new TokenAuthOptions()
{
Audience = TokenAudience,
Issuer = TokenIssuer,
SigningCredentials = new SigningCredentials(keyFromContainer, SecurityAlgorithms.RsaSha256Signature)
};
// Save the token options into an instance so they're accessible to the
// controller.
services.AddInstance<TokenAuthOptions>(tokenOptions);
// Enable the use of an [Authorize("Bearer")] attribute on methods and classes to protect.
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build());
});
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseIISPlatformHandler();
// Register a simple error handler to catch token expiries and change them to a 401,
// and return all other errors as a 500. This should almost certainly be improved for
// a real application.
app.UseExceptionHandler(appBuilder =>
{
appBuilder.Use(async (context, next) =>
{
var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;
// This should be much more intelligent - at the moment only expired
// security tokens are caught - might be worth checking other possible
// exceptions such as an invalid signature.
if (error != null && error.Error is SecurityTokenExpiredException)
{
context.Response.StatusCode = 401;
// What you choose to return here is up to you, in this case a simple
// bit of JSON to say you're no longer authenticated.
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(
JsonConvert.SerializeObject(
new { authenticated = false, tokenExpired = true }));
}
else if (error != null && error.Error != null)
{
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
// TODO: Shouldn't pass the exception message straight out, change this.
await context.Response.WriteAsync(
JsonConvert.SerializeObject
(new { success = false, error = error.Error.Message }));
}
// We're not trying to handle anything else so just let the default
// handler handle.
else await next();
});
});
app.UseJwtBearerAuthentication(options =>
{
// Basic settings - signing key to validate with, audience and issuer.
options.TokenValidationParameters.IssuerSigningKey = key;
options.TokenValidationParameters.ValidAudience = tokenOptions.Audience;
options.TokenValidationParameters.ValidIssuer = tokenOptions.Issuer;
// When receiving a token, check that we've signed it.
options.TokenValidationParameters.ValidateSignature = true;
// When receiving a token, check that it is still valid.
options.TokenValidationParameters.ValidateLifetime = true;
// This defines the maximum allowable clock skew - i.e. provides a tolerance on the token expiry time
// when validating the lifetime. As we're creating the tokens locally and validating them on the same
// machines which should have synchronised time, this can be set to zero. Where external tokens are
// used, some leeway here could be useful.
options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(0);
});
// Configure the HTTP request pipeline.
app.UseStaticFiles();
// Add MVC to the request pipeline.
app.UseMvc();
}
public static void Main(string[] args) => WebApplication.Run(args);
}
}