The IdentityServer4 in this article is based on the previous section of Jenkins for Docker automation deployment.
Mariadb,ef Core,aspnetidentity,docker is used.
Demo Address: https://sso.neverc.cn
Demo Source: Https://github.com/NeverCL/Geek.IdentityServer4
Brief introduction
OpenID Connect: Common authentication protocols are saml2p, Ws-federation and OpenID connect–saml2p. OpenID Connect is one of the newest protocols.
OAuth 2.0:oauth 2.0 is an authorization protocol. The protected API interface can be accessed through access tokens.
OpenID Connect is very similar to OAuth 2.0, and in fact, OpenID Connect is an extension above OAuth 2.0.
Authentication and API Access these two basic security issues are consolidated into one protocol-often requiring only one round-trip security token service.
The IdentityServer4 is based on ASP. NET Core 2 Implementation of these two protocols.
Support Specification: https://identityserver4.readthedocs.io/en/release/intro/specs.html
Keywords
Identityserver: Provides OpenID Connect and OAuth 2.0 protocols.
Users in the User:identityserver
Client: Third-party applications, including Web applications, native mobile or desktop applications, SPAs etc.
Resource: Contains identity data and APIs. This is the identity in the authentication authorization.
Identity Token: Identifies the authentication information that contains at least the user's sub claim.
Access Token: Identifies authorization information that can contain claim information for the client and user.
Authorization Mode Client Credentials
Client credentials is the simplest form of authorization.
Steps:
- Create Identityserver
- Defining APIs
- Define Client
- Creating an API
- Define Authentication
- Using the Client
- Request Token
- Use token
Identityserver:
dotnet new web -o Geek.IdentityServer4 && dotnet add Geek.IdentityServer4 package IdentityServer4
Startup:
services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryApiResources(Config.GetApiResources()) .AddInMemoryClients(Config.GetClients());...app.UseIdentityServer();
Config:
public static IEnumerable<ApiResource> GetApiResources(){ return new List<ApiResource> { new ApiResource("api1") };}public static IEnumerable<Client> GetClients(){ return new List<Client> { new Client { ClientId = "client", AllowedGrantTypes = GrantTypes.ClientCredentials, ClientSecrets = { new Secret("secret".Sha256()) }, Claims = { new Claim("name","名称") }, AllowedScopes = { "api1" } }, }}
Api:
dotnet new web -o Geek.Api && dotnet add Geek.Api package IdentityServer4.AccessTokenValidation
Startup:
services.AddMvc();services.AddAuthentication("Bearer")//AddIdentityServerAuthentication 默认SchemeName:Bearer .AddIdentityServerAuthentication(opt => { opt.ApiName = "api1"; opt.Authority = "https://sso.neverc.cn"; });...app.UseAuthentication();app.UseMvc();
Controller:
[Route("identity")][Authorize]public class IdentityController : ControllerBase{ [HttpGet] public IActionResult Get() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); }}
Client:
dotnet new web -o Geek.Client && dotnet add Geek.Client package IdentityServer4.IdentityModel
Program:
var disco = await DiscoveryClient.GetAsync("https://sso.neverc.cn");var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret");var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api1");var client = new HttpClient();client.SetBearerToken(tokenResponse.AccessToken);var response = await client.GetAsync("http://localhost:5001/identity");var content = await response.Content.ReadAsStringAsync();Console.WriteLine(JArray.Parse(content));
Resourceownerpassword
This authentication method requires the user to provide a username and password, so the client is a very trusted application that may be used this way.
Steps:
- Define the RO Client and User
- Using the Client
Identity Server
Config:
public static IEnumerable<Client> GetClients(){ ... new Client { ClientId = "ro.client", AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = { new Secret("secret".Sha256()) }, AllowedScopes = { "api1" } }}public static List<TestUser> GetUsers(){ return new List<TestUser> { new TestUser { SubjectId = "1", Username = "alice", Password = "password", } }}
Startup:
services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryApiResources(Config.GetApiResources()) .AddInMemoryClients(Config.GetClients()) .AddTestUsers(Config.GetUsers());
Client
var disco = await DiscoveryClient.GetAsync("https://sso.neverc.cn");var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.client", "secret");var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("alice", "password", "api1");var client = new HttpClient();client.SetBearerToken(tokenResponse.AccessToken);var response = await client.GetAsync("http://localhost:5001/identity");var content = await response.Content.ReadAsStringAsync();Console.WriteLine(JArray.Parse(content));
Differentiating between client Credentials and Resourceownerpassword can be distinguished by sub claim
Implicit
Implicit is an implicit mode and is transmitted directly via the browser side Id_token
Steps:
- Configure Identityserver
- Define Identityresources
- Defining the MVC Client
- Add MVC UI
- Create an MVC Client
Identityserver
public static ienumerable<identityresource> getidentityresources () {return new list< identityresource> {new Identityresources.openid (), New Identityresources.profile ()};} ... new client{ClientId = "MVC", ClientName = "MVC Client", allowedgranttypes = granttypes.implicit, clientsec RETs = {New Secret ("Secret"). SHA256 ())}, Redirecturis = {"HTTP://LOCALHOST:5002/SIGNIN-OIDC"}, Postlogoutredirecturis = {"Http://localhost:50 02/SIGNOUT-CALLBACK-OIDC "}, Allowedscopes = new List<string> {identityserverconstants.standardscopes. OpenId, IdentityServerConstants.StandardScopes.Profile,}}
services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryApiResources(Config.GetApiResources()) .AddInMemoryClients(Config.GetClients()) .AddTestUsers(Config.GetUsers()) .AddInMemoryIdentityResources(Config.GetIdentityResources());
Add Mvcui:
In the Identityserver project, PowerShell executes:
iex ((New-Object System.Net.WebClient).DownloadString(‘https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.ps1‘))
Mvcclient
public void ConfigureServices(IServiceCollection services){ JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); services.AddMvc(); services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.SignInScheme = "Cookies"; options.Authority = "https://sso.neverc.cn"; options.ClientId = "mvc"; options.SaveTokens = true; });}public void Configure(IApplicationBuilder app, IHostingEnvironment env){ app.UseAuthentication(); app.UseMvcWithDefaultRoute();}
public class HomeController : ControllerBase{ [Authorize] public ActionResult Index() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); }}
Hybrid
In implicit mode, Id_token in the browser is appropriate, but access_token should not be exposed in the browser.
Hybrid mode is based on the implicit, then transfer code, the code mode to obtain Access_token.
Steps:
- Define Client
- Using the Client
Identityserver Configuration
Config:
new Client{ ClientId = "hybrid", AllowedGrantTypes = GrantTypes.Hybrid, ClientSecrets = { new Secret("secret".Sha256()) }, RedirectUris = { "http://localhost:5002/signin-oidc" }, PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" }, AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, "api1" },};
Mvcclient Configuration
Startup:
.AddOpenIdConnect("oidc", options =>{ options.SignInScheme = "Cookies"; options.Authority = "https://sso.neverc.cn"; options.ClientId = "mvc"; options.ClientSecret = "secret"; options.ResponseType = "code id_token"; options.SaveTokens = true; options.Scope.Add("api1");});
Controller:
public async Task<IActionResult> CallApiUsingUserAccessToken(){ var accessToken = await HttpContext.GetTokenAsync("access_token"); var client = new HttpClient(); client.SetBearerToken(accessToken); var content = await client.GetStringAsync("http://localhost:5001/identity"); ViewBag.Json = JArray.Parse(content).ToString(); return View("json");}
Once the login is complete, the API service can be invoked via the Access_token call Callapiusinguseraccesstoken.
Summarize
This article has made a basic introduction for IDENTITYSERVER4.
In fact, IdentityServer4 can also be used in a very flexible combination with the ASP. NET Identity and EF core.
In addition, based on ASP. IDENTITYSERVER4 also supports cross-platform.
". NET core" ASP. IdentityServer4 (1): QuickStart