IdentityServer4 and SignarR authentication (Net Core 2.2) with custom token key
- Custom Token Retriever class:
public class CustomTokenRetriever
{
internal const string TokenItemsKey = "idsrv4:tokenvalidation:token";
// custom token key change it to the one you use for sending the access_token to the server
// during websocket handshake
internal const string SignalRTokenKey = "token";
static Func<HttpRequest, string> AuthHeaderTokenRetriever { get; set; }
static Func<HttpRequest, string> QueryStringTokenRetriever { get; set; }
static CustomTokenRetriever()
{
AuthHeaderTokenRetriever = TokenRetrieval.FromAuthorizationHeader();
QueryStringTokenRetriever = TokenRetrieval.FromQueryString();
}
public static string FromHeaderAndQueryString(HttpRequest request)
{
var token = AuthHeaderTokenRetriever(request);
if (string.IsNullOrEmpty(token))
{
token = QueryStringTokenRetriever(request);
}
if (string.IsNullOrEmpty(token))
{
token = request.HttpContext.Items[TokenItemsKey] as string;
}
if (string.IsNullOrEmpty(token) && request.Query.TryGetValue(SignalRTokenKey, out StringValues extract))
{
token = extract.ToString();
}
return token;
}
}
2. Startup configuration
public class Startup
{
public static IHostingEnvironment _hostingEnv;
public Startup(IHostingEnvironment env, IConfiguration configuration)
{
_hostingEnv = env;
Configuration = configuration;
}
public static IConfiguration Configuration { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//CORS
services.AddCors();
//Authentication
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
})
.AddIdentityServerAuthentication(options =>
{
options.Authority = "https://localhost:44326/"; // Auth Server
options.ApiName = "APIName"; // API Resource Id
options.TokenRetriever = CustomTokenRetriever.FromHeaderAndQueryString;
services.AddMvc();
services.AddSignalR()
.AddHubOptions<MyHub>(options =>
{
options.EnableDetailedErrors = false;
});
services.AddDistributedMemoryCache(); // Adds a default in-memory implementation of IDistributedCache
services.AddSingleton<ISingletonDeviceModels, SingletonDeviceModels>();
services.AddSingleton<IUserIdProvider, NameUserIdProvider>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//CORS
var cors = Configuration.GetSection("CorsOrigins").Get<List<string>>().ToArray();
app.UseCors(builder =>
builder.WithOrigins(cors)
.AllowAnyMethod()
.AllowAnyHeader()
.WithExposedHeaders("Content-Range", "Link")
.AllowCredentials()
);
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
// Add middleware after Identity but before Mvc
app.UseAuthentication();
app.UseSignalR(routes =>
{
routes.MapHub<MyHub>("/api/v1/myhub");
}
);
app.UseMvc();
}
}