Skip to content

Commit

Permalink
Updates to Quickstart 1-3 for v4 (#4576)
Browse files Browse the repository at this point in the history
* update qs1 source

* update qs1 text

* update QS2 code and text

* switch to HTTPS

* update QS3 text and code
  • Loading branch information
leastprivilege authored Jun 25, 2020
1 parent 8a4fb71 commit 6924ff0
Show file tree
Hide file tree
Showing 401 changed files with 100,478 additions and 29,881 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -211,5 +211,4 @@ samples/KeyManagement/FileSystem/signingkeys/
workspace.xml

src/IdentityServer4/host/identityserver.db
src/IdentityServer4/host/tempkey.jwk
src/EntityFramework/host/tempkey.jwk
tempkey.jwk
2 changes: 1 addition & 1 deletion docs/quickstarts/0_overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ They will be used as a starting point for the various tutorials.

OK - let's get started!

.. note:: The quickstarts target the latest version of IdentityServer and ASP.NET Core (3.0) - there are also quickstarts for `ASP.NET Core 2 <http://docs.identityserver.io/en/aspnetcore2/quickstarts/0_overview.html>`_ and `ASP.NET Core 1 <http://docs.identityserver.io/en/aspnetcore1/quickstarts/0_overview.html>`_.
.. note:: The quickstarts target the IdentityServer 4.x and ASP.NET Core 3.1.x - there are also quickstarts for `ASP.NET Core 2 <http://docs.identityserver.io/en/aspnetcore2/quickstarts/0_overview.html>`_ and `ASP.NET Core 1 <http://docs.identityserver.io/en/aspnetcore1/quickstarts/0_overview.html>`_.
54 changes: 45 additions & 9 deletions docs/quickstarts/1_client_credentials.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,19 @@ and let it add your IdentityServer project (keep this command in mind as we will

.. note:: The protocol used in this Template is ``https`` and the port is set to 5001 when running on Kestrel or a random one on IISExpress. You can change that in the ``Properties\launchSettings.json`` file. For production scenarios you should always use ``https``.

Defining an API Resource
^^^^^^^^^^^^^^^^^^^^^^^^
Defining an API Scope
^^^^^^^^^^^^^^^^^^^^^
An API is a resource in your system that you want to protect.
Resource definitions can be loaded in many ways, the template you used to create the project above shows how to use a "code as configuration" approach.

The Config.cs is already created for you. Open it, update the code to look like this::

public static class Config
{
public static IEnumerable<ApiResource> Apis =>
new List<ApiResource>
public static IEnumerable<ApiScope> ApiScopes =>
new List<ApiScope>
{
new ApiResource("api1", "My API")
new ApiScope("api1", "My API")
};
}

Expand Down Expand Up @@ -102,7 +102,8 @@ For this, add a client definition::
}
};

You can think of the ClientId and the ClientSecret as the login and password for your application itself. It identifies your application to the identity server so that it knows which application is trying to connect to it.
You can think of the ClientId and the ClientSecret as the login and password for your application itself.
It identifies your application to the identity server so that it knows which application is trying to connect to it.


Configuring IdentityServer
Expand All @@ -112,7 +113,7 @@ Loading the resource and client definitions happens in `Startup.cs <https://gith
public void ConfigureServices(IServiceCollection services)
{
var builder = services.AddIdentityServer()
.AddInMemoryApiResources(Config.Apis)
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients);

// omitted for brevity
Expand Down Expand Up @@ -187,9 +188,11 @@ Update `Startup` to look like this::
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:5001";
options.RequireHttpsMetadata = false;

options.Audience = "api1";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
}

Expand All @@ -214,6 +217,8 @@ Update `Startup` to look like this::
Navigating to the controller ``https://localhost:6001/identity`` on a browser should return a 401 status code.
This means your API requires a credential and is now protected by IdentityServer.

.. note:: If you are wondering, why the above code disables audience validation, have a look :ref:`here <refResources>` for a more in-depth discussion.

Creating the client
^^^^^^^^^^^^^^^^^^^
The last step is to write a client that requests an access token, and then uses this token to access the API. For that, add a console project to your solution, remember to create it in the ``src``::
Expand Down Expand Up @@ -296,6 +301,37 @@ The output should look like this:

.. note:: By default an access token will contain claims about the scope, lifetime (nbf and exp), the client ID (client_id) and the issuer name (iss).

Authorization at the API
^^^^^^^^^^^^^^^^^^^^^^^^
Right now, the API accepts any access token issued by your identity server.

In the following we will add code that allows checking for the presence of the scope in the access token that the client asked for (and got granted).
For this we will use the ASP.NET Core authorization policy system. Add the following to the ``Configure`` method in ``Startup``::

services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "api1");
});
});

You can now enforce this policy at various levels, e.g.

* globally
* for all API endpoints
* for specific controllers/actions

Typically you setup the policy for all API endpoints in the routing system::

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers()
.RequireAuthorization("ApiScope");
});


Further experiments
^^^^^^^^^^^^^^^^^^^
This walkthrough focused on the success path so far
Expand Down
8 changes: 3 additions & 5 deletions docs/quickstarts/2_interactive_aspnetcore.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ To add support for OpenID Connect authentication to the MVC application, you fir
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:5001";
options.RequireHttpsMetadata = false;

options.ClientId = "mvc";
options.ClientSecret = "secret";
Expand Down Expand Up @@ -108,7 +107,8 @@ And then to ensure the authentication services execute on each request, add ``Us
.RequireAuthorization();
});

.. note:: The ``RequireAuthorization`` method disables anonymous access for the entire application. You can also use the ``[Authorize]`` attribute, if you want to specify that on a per controller or action method basis.
.. note:: The ``RequireAuthorization`` method disables anonymous access for the entire application.
You can also use the ``[Authorize]`` attribute, if you want to specify that on a per controller or action method basis.

Also modify the home view to display the claims of the user as well as the cookie properties::

Expand Down Expand Up @@ -158,7 +158,7 @@ Register the identity resources with IdentityServer in ``startup.cs``::

var builder = services.AddIdentityServer()
.AddInMemoryIdentityResources(Config.Ids)
.AddInMemoryApiResources(Config.Apis)
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients);

.. note:: All standard scopes and their corresponding claims can be found in the OpenID Connect `specification <https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims>`_
Expand Down Expand Up @@ -205,8 +205,6 @@ The client list should look like this::
ClientSecrets = { new Secret("secret".Sha256()) },

AllowedGrantTypes = GrantTypes.Code,
RequireConsent = false,
RequirePkce = true,
// where to redirect to after login
RedirectUris = { "http://localhost:5002/signin-oidc" },
Expand Down
20 changes: 8 additions & 12 deletions docs/quickstarts/3_aspnetcore_and_apis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,19 @@ In addition we enable support for refresh tokens via the ``AllowOfflineAccess``
ClientSecrets = { new Secret("secret".Sha256()) },

AllowedGrantTypes = GrantTypes.Code,
RequireConsent = false,
RequirePkce = true,
// where to redirect to after login
RedirectUris = { "http://localhost:5002/signin-oidc" },
RedirectUris = { "https://localhost:5002/signin-oidc" },

// where to redirect to after logout
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
PostLogoutRedirectUris = { "https://localhost:5002/signout-callback-oidc" },

AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
},

AllowOfflineAccess = true
}
}

Modifying the MVC client
Expand All @@ -52,7 +48,6 @@ All that's left to do now in the client is to ask for the additional resources v
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:5001";
options.RequireHttpsMetadata = false;

options.ClientId = "mvc";
options.ClientSecret = "secret";
Expand All @@ -61,18 +56,17 @@ All that's left to do now in the client is to ask for the additional resources v
options.SaveTokens = true;

options.Scope.Add("api1");
options.Scope.Add("offline_access");
});

Since ``SaveTokens`` is enabled, ASP.NET Core will automatically store the resulting access and refresh token in the authentication session.
You should be able to inspect the data on the page that prints out the contents of the session that you created earlier.

Using the access token
^^^^^^^^^^^^^^^^^^^^^^
You can access the tokens in the session using the standard ASP.NET Core extension methods that you can find in the ``Microsoft.AspNetCore.Authentication`` namespace::
You can access the tokens in the session using the standard ASP.NET Core extension methods
that you can find in the ``Microsoft.AspNetCore.Authentication`` namespace::

var accessToken = await HttpContext.GetTokenAsync("access_token");
var refreshToken = await HttpContext.GetTokenAsync("refresh_token");

For accessing the API using the access token, all you need to do is retrieve the token, and set it on your HttpClient::

Expand Down Expand Up @@ -105,4 +99,6 @@ By far the most complex task for a typical client is to manage the access token.
* start over

ASP.NET Core has many built-in facility that can help you with those tasks (like caching or sessions),
but there is still quite some work left to do. Feel free to have a look at `this <https://github.com/IdentityModel/IdentityModel.AspNetCore>`_ library, which can automate many of the boilerplate tasks.
but there is still quite some work left to do.
Feel free to have a look at `this <https://github.com/IdentityModel/IdentityModel.AspNetCore>`_ library, which can automate
many of the boilerplate tasks.
2 changes: 1 addition & 1 deletion samples/Quickstarts/1_ClientCredentials/src/Api/Api.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
Expand Down
13 changes: 8 additions & 5 deletions samples/Quickstarts/1_ClientCredentials/src/Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace Api
{
Expand All @@ -13,12 +14,14 @@ public static void Main(string[] args)
{
Console.Title = "API";

BuildWebHost(args).Run();
CreateHostBuilder(args).Build().Run();
}

public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
23 changes: 19 additions & 4 deletions samples/Quickstarts/1_ClientCredentials/src/Api/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;

namespace Api
{
Expand All @@ -12,14 +13,27 @@ public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();

// accepts any access token issued by identity server
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:5001";
options.RequireHttpsMetadata = false;

options.Audience = "api1";

options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});

// adds an authorization policy to make sure the token is for scope 'api1'
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "api1");
});
});
}

public void Configure(IApplicationBuilder app)
Expand All @@ -31,7 +45,8 @@ public void Configure(IApplicationBuilder app)

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapControllers()
.RequireAuthorization("ApiScope");
});
}
}
Expand Down
10 changes: 0 additions & 10 deletions samples/Quickstarts/1_ClientCredentials/src/Api/appsettings.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ namespace IdentityServer
{
public static class Config
{
public static IEnumerable<ApiResource> Apis =>
new List<ApiResource>
public static IEnumerable<ApiScope> ApiScopes =>
new List<ApiScope>
{
new ApiResource("api1", "My API")
new ApiScope("api1", "My API")
};

public static IEnumerable<Client> Clients =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="IdentityServer4" />

<PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Serilog.Sinks.Console" />
</ItemGroup>
</Project>
Loading

0 comments on commit 6924ff0

Please sign in to comment.