DZone
Web Dev Zone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
  • Refcardz
  • Trend Reports
  • Webinars
  • Zones
  • |
    • Agile
    • AI
    • Big Data
    • Cloud
    • Database
    • DevOps
    • Integration
    • IoT
    • Java
    • Microservices
    • Open Source
    • Performance
    • Security
    • Web Dev
DZone > Web Dev Zone > Upgrading to ASP.NET Core RC2, OpenIdConnect, JWT, Swagger, AutoRest, and Angular 2 SPA (Part 2)

Upgrading to ASP.NET Core RC2, OpenIdConnect, JWT, Swagger, AutoRest, and Angular 2 SPA (Part 2)

Continuing on from a previous post, this article details my journey in upgrading a Service Fabric multi-tenant application from .NET Core RC1 to RC2. Read on and learn from my experience.

Andrej Medic user avatar by
Andrej Medic
·
Jun. 23, 16 · Web Dev Zone · Tutorial
Like (2)
Save
Tweet
4.05K Views

Join the DZone community and get the full member experience.

Join For Free

Continuing on from a previous post, this article details my journey in upgrading a Service Fabric multi-tenant application from .NET Core RC1 to RC2, which turned out to be a breaking—albeit worthwhile—change, specifically for the Startup.cs class and related boot strapping code for Swagger, CookieAuthentication, OpenIdConnectAuthentication, and JwtBearerAuthentication. In subsequent articles, we’ll explore how .NET Core RC2 hosts web applications but for now, let’s look at the first challenge encountered during the upgrade, which was to chase down all required libraries that are also .NET Core RC2 compatible.

As of the time of writing, I could only get Swashbuckle version 6.0.0-beta9 to work with .NET Core RC2.

The below code supports multi-tenant Azure AD authentication and is meant for development scenarios as ValidateIssuer and RequireHttpsMetadata are both set to false for simplicity.

The full dependencies section of your project.json should look something like this:

"dependencies": {
    "Microsoft.AspNetCore.Hosting": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Authentication": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Diagnostics": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.SpaServices": "1.0.0-beta-000004",
    "Microsoft.AspNetCore.StaticFiles": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Mvc.Core": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Mvc.Formatters.Json": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final",
    "Microsoft.IdentityModel.Clients.ActiveDirectory": "3.9.302261508-alpha",
    "Microsoft.Extensions.Configuration.Binder": "1.0.0-rc2-final",
    "Swashbuckle": "6.0.0-beta9",
    "Swashbuckle.SwaggerUi": "6.0.0-beta9",
    "Swashbuckle.SwaggerGen": "6.0.0-beta9"
}

Your Startup.cs usings should look something like the below:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Serialization;
using System;
using System.Net;

Having sourced the relevant libraries and compatible versions, it’s now time to turn our attention to the ConfigureServices method wherein we’ll set up Swagger, tweak JSON formatting for JavaScript clients such as our Angular 2 SPA, and finally, also tweak how AutoRest generates client code. I want AutoRest to generate separate files per server side controller which is achieved through a custom SwaggerOperationNameFilter.

public IServiceProvider ConfigureServices(IServiceCollection services)
{
	// Add MVC service
	services.AddMvc().AddJsonOptions(options =>
	{
		// Support for JavaScript clients which assume CamelCase - starting with lower case
		options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
	});

	// Add Swagger API service
	services.AddSwaggerGen();
	services.ConfigureSwaggerGen(options =>
	{
		options.SingleApiVersion(new Swashbuckle.SwaggerGen.Generator.Info
		{
			Version = "v1",
			Title = "Acme API",
			Description = "Acme API Home",
			TermsOfService = "Legal"
		});

		// Controls how tools like AutoRest generate client code (separate files per server side controller)
		options.OperationFilter<SwaggerOperationNameFilter>();
		options.DescribeStringEnumsInCamelCase();
		options.DescribeAllEnumsAsStrings();
	});
    
	var acmeOptions = new AcmeOptions();
	Configuration.Bind(acmeOptions);
	services.AddSingleton(acmeOptions);
    
	// Configure IoC service
	var builder = new ContainerBuilder();
	builder.Populate(services);
	var container = builder.Build();
	return container.Resolve<IServiceProvider>();
}

Code for the custom SwaggerOperationNameFilter:

internal class SwaggerOperationNameFilter : IOperationFilter
{
	public void Apply(Operation operation, OperationFilterContext context)
	{
		operation.OperationId = context.ApiDescription.GroupName + "_" + operation.OperationId;
	}
}

Concluding the changes required for the .NET Core RC2 upgrade, we dive into the Configure method. Canny readers will notice that UseCookieAuthentication, UseOpenIdConnectAuthentication, and UseJwtBearerAuthentication have been refactored to handle options in a more consistent manner with the rest of the .NET Core APIs.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{	
	if (env.IsDevelopment())
	{
		app.UseDeveloperExceptionPage();
	}

	app.UseStaticFiles();

	app.UseCookieAuthentication(new CookieAuthenticationOptions
	{
		AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme,
		AutomaticAuthenticate = true,
		AutomaticChallenge = true,
		CookieSecure = CookieSecureOption.Never,
		// The default setting for cookie expiration is 14 days. SlidingExpiration is set to true by default
		ExpireTimeSpan = TimeSpan.FromHours(1),
		SlidingExpiration = true
	});

	var acmeOptions = app.ApplicationServices.GetService<AcmeOptions>();

	app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
	{
		AutomaticAuthenticate = true,
		AutomaticChallenge = true,
		ClientId = acmeOptions.ClientId,
		Authority = AcmeConstants.AuthEndpointPrefix + "common/",
		PostLogoutRedirectUri = acmeOptions.PostLogoutRedirectUri,
		CallbackPath = AcmeRouteConstants.LoginCallbackRoute,
		SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme,
		AuthenticationScheme = OpenIdConnectDefaults.AuthenticationScheme,
		TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false },
		RequireHttpsMetadata = false,
		Events = new OpenIdConnectAuthenticationEvents(acmeOptions)
		{
			OnAuthenticationFailed = context => OpenIdConnectAuthenticationEvents.GetFailedResponse(context)
		}
	});

	// Add JwtBearerAuthentication middleware 
	app.UseJwtBearerAuthentication(new JwtBearerOptions
	{
		AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme,
		Audience = acmeOptions.JwtAudience,
		AutomaticAuthenticate = true,
		AutomaticChallenge = true,
		Authority = AcmeConstants.AuthEndpointPrefix + "common/",
		TokenValidationParameters = new TokenValidationParameters
		{
			ValidateIssuer = false,
		},
		RequireHttpsMetadata = false,
		Events = new JwtBearerAuthenticationEvents(acmeOptions)
		{
			OnAuthenticationFailed = context => JwtBearerAuthenticationEvents.GetFailedResponse(context)
		}
	});

	app.UseMvc(routes =>
	{
		routes.MapRoute(
			name: "webapi",
			template: "api/{controller}/{action}/{id?}");

		routes.MapSpaFallbackRoute("spa-fallback", new { controller = "Home", action = "Index" });
	});

	// Enable Use of Swagger
	app.UseSwaggerGen();
	app.UseSwaggerUi();
}

If you’re wondering why I left the Microsoft.IdentityModel.Clients.ActiveDirectory library at “3.9.302261508-alpha”, in upcoming articles we’ll detail a strategy for automated integration testing of your .NET Core APIs using xUnit and optionally a BDD approach (SpecFlow).

That's all for now... stay tuned for future posts.

.NET ASP.NET ASP.NET Core AngularJS JWT (JSON Web Token)

Published at DZone with permission of Andrej Medic. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How to Configure Git in Eclipse IDE
  • Instancio: Random Test Data Generator for Java (Part 1)
  • Servlets Listeners Introduction and Examples
  • 5 Steps to Effective KYC Compliance

Comments

Web Dev Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • MVB Program
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

DZone.com is powered by 

AnswerHub logo