tutorial net español ejemplos asp c# asp.net-core identityserver4

c# - español - identity server 4 asp.net core 2



Ejemplo de flujo de código de autorización de Identity Server 4 (2)

Aquí hay una implementación de un flujo de código de autorización con Identity Server 4 y un cliente MVC para consumirlo.

IdentityServer4 puede usar un archivo client.cs para registrar nuestro cliente MVC, ClientId, ClientSecret, tipos de concesión permitidos (Código de autorización en este caso) y el RedirectUri de nuestro cliente:

public class Clients { public static IEnumerable<Client> Get() { var secret = new Secret { Value = "mysecret".Sha512() }; return new List<Client> { new Client { ClientId = "authorizationCodeClient2", ClientName = "Authorization Code Client", ClientSecrets = new List<Secret> { secret }, Enabled = true, AllowedGrantTypes = new List<string> { "authorization_code" }, //DELTA //IdentityServer3 wanted Flow = Flows.AuthorizationCode, RequireConsent = true, AllowRememberConsent = false, RedirectUris = new List<string> { "http://localhost:5436/account/oAuth2" }, PostLogoutRedirectUris = new List<string> {"http://localhost:5436"}, AllowedScopes = new List<string> { "api" }, AccessTokenType = AccessTokenType.Jwt } }; } }

Se hace referencia a esta clase en el método ConfigurationServices de Startup.cs en el proyecto IdentityServer4:

public void ConfigureServices(IServiceCollection services) { ////Grab key for signing JWT signature ////In prod, we''d get this from the certificate store or similar var certPath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "SscSign.pfx"); var cert = new X509Certificate2(certPath); // configure identity server with in-memory stores, keys, clients and scopes services.AddDeveloperIdentityServer(options => { options.IssuerUri = "SomeSecureCompany"; }) .AddInMemoryScopes(Scopes.Get()) .AddInMemoryClients(Clients.Get()) .AddInMemoryUsers(Users.Get()) .SetSigningCredential(cert); services.AddMvc(); }

Para referencia, aquí están las clases Usuarios y Ámbitos mencionados anteriormente:

public static class Users { public static List<InMemoryUser> Get() { return new List<InMemoryUser> { new InMemoryUser { Subject = "1", Username = "user", Password = "pass123", Claims = new List<Claim> { new Claim(ClaimTypes.GivenName, "GivenName"), new Claim(ClaimTypes.Surname, "surname"), //DELTA //.FamilyName in IdentityServer3 new Claim(ClaimTypes.Email, "[email protected]"), new Claim(ClaimTypes.Role, "Badmin") } } }; } } public class Scopes { // scopes define the resources in your system public static IEnumerable<Scope> Get() { return new List<Scope> { new Scope { Name = "api", DisplayName = "api scope", Type = ScopeType.Resource, Emphasize = false, } }; } }

La aplicación MVC requiere dos métodos de controlador. El primer método inicia el flujo de trabajo del proveedor de servicios (iniciado por SP). Crea un valor de Estado, lo guarda en un middleware de autenticación basado en cookies y, a continuación, redirige el navegador a IdentityProvider (IdP), nuestro proyecto IdentityServer4 en este caso.

public ActionResult SignIn() { var state = Guid.NewGuid().ToString("N"); //Store state using cookie-based authentication middleware this.SaveState(state); //Redirect to IdP to get an Authorization Code var url = idPServerAuthUri + "?client_id=" + clientId + "&response_type=" + response_type + "&redirect_uri=" + redirectUri + "&scope=" + scope + "&state=" + state; return this.Redirect(url); //performs a GET }

Para referencia, aquí están las constantes y el método SaveState utilizado anteriormente:

//Client and workflow values private const string clientBaseUri = @"http://localhost:5436"; private const string validIssuer = "SomeSecureCompany"; private const string response_type = "code"; private const string grantType = "authorization_code"; //IdentityServer4 private const string idPServerBaseUri = @"http://localhost:5000"; private const string idPServerAuthUri = idPServerBaseUri + @"/connect/authorize"; private const string idPServerTokenUriFragment = @"connect/token"; private const string idPServerEndSessionUri = idPServerBaseUri + @"/connect/endsession"; //These are also registered in the IdP (or Clients.cs of test IdP) private const string redirectUri = clientBaseUri + @"/account/oAuth2"; private const string clientId = "authorizationCodeClient2"; private const string clientSecret = "mysecret"; private const string audience = "SomeSecureCompany/resources"; private const string scope = "api"; //Store values using cookie-based authentication middleware private void SaveState(string state) { var tempId = new ClaimsIdentity("TempCookie"); tempId.AddClaim(new Claim("state", state)); this.Request.GetOwinContext().Authentication.SignIn(tempId); }

El segundo método de acción de MVC es llamado por IdenityServer4 después de que el usuario ingresa sus credenciales y marca cualquier casilla de autorización. El método de acción:

  • Coge el Código de Autorización y el Estado de la cadena de consulta
  • Valida estado
  • Las POST vuelven a IdentityServer4 para intercambiar el código de autorización para un token de acceso

Aquí está el método:

[HttpGet] public async Task<ActionResult> oAuth2() { var authorizationCode = this.Request.QueryString["code"]; var state = this.Request.QueryString["state"]; //Defend against CSRF attacks http://www.twobotechnologies.com/blog/2014/02/importance-of-state-in-oauth2.html await ValidateStateAsync(state); //Exchange Authorization Code for an Access Token by POSTing to the IdP''s token endpoint string json = null; using (var client = new HttpClient()) { client.BaseAddress = new Uri(idPServerBaseUri); var content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("grant_type", grantType) ,new KeyValuePair<string, string>("code", authorizationCode) ,new KeyValuePair<string, string>("redirect_uri", redirectUri) ,new KeyValuePair<string, string>("client_id", clientId) //consider sending via basic authentication header ,new KeyValuePair<string, string>("client_secret", clientSecret) }); var httpResponseMessage = client.PostAsync(idPServerTokenUriFragment, content).Result; json = httpResponseMessage.Content.ReadAsStringAsync().Result; } //Extract the Access Token dynamic results = JsonConvert.DeserializeObject<dynamic>(json); string accessToken = results.access_token; //Validate token crypto var claims = ValidateToken(accessToken); //What is done here depends on your use-case. //If the accessToken is for calling a WebAPI, the next few lines wouldn''t be needed. //Build claims identity principle var id = new ClaimsIdentity(claims, "Cookie"); //"Cookie" matches middleware named in Startup.cs //Sign into the middleware so we can navigate around secured parts of this site (e.g. [Authorized] attribute) this.Request.GetOwinContext().Authentication.SignIn(id); return this.Redirect("/Home"); }

Comprobar que el Estado recibió es lo que esperaba y ayuda a defenderse contra los ataques CSRF: http://www.twobotechnologies.com/blog/2014/02/importance-of-state-in-oauth2.html

Este método ValidateStateAsync compara el estado recibido con lo que se guardó en el middleware de cookies:

private async Task<AuthenticateResult> ValidateStateAsync(string state) { //Retrieve state value from TempCookie var authenticateResult = await this.Request .GetOwinContext() .Authentication .AuthenticateAsync("TempCookie"); if (authenticateResult == null) throw new InvalidOperationException("No temp cookie"); if (state != authenticateResult.Identity.FindFirst("state").Value) throw new InvalidOperationException("invalid state"); return authenticateResult; }

Este método ValidateToken utiliza las bibliotecas System.IdentityModel y System.IdentityModel.Tokens.Jwt de Microsoft para verificar que JWT esté debidamente firmado.

private IEnumerable<Claim> ValidateToken(string token) { //Grab certificate for verifying JWT signature //IdentityServer4 also has a default certificate you can might reference. //In prod, we''d get this from the certificate store or similar var certPath = Path.Combine(Server.MapPath("~/bin"), "SscSign.pfx"); var cert = new X509Certificate2(certPath); var x509SecurityKey = new X509SecurityKey(cert); var parameters = new TokenValidationParameters { RequireSignedTokens = true, ValidAudience = audience, ValidIssuer = validIssuer, IssuerSigningKey = x509SecurityKey, RequireExpirationTime = true, ClockSkew = TimeSpan.FromMinutes(5) }; //Validate the token and retrieve ClaimsPrinciple var handler = new JwtSecurityTokenHandler(); SecurityToken jwt; var id = handler.ValidateToken(token, parameters, out jwt); //Discard temp cookie and cookie-based middleware authentication objects (we just needed it for storing State) this.Request.GetOwinContext().Authentication.SignOut("TempCookie"); return id.Claims; }

Una solución de trabajo que contiene estos archivos de origen reside en GitHub en https://github.com/bayardw/IdentityServer4.Authorization.Code

Estoy tratando de implementar Identity Server 4 con AspNet Core utilizando el flujo de código de autorización.

El problema es que el repositorio IdentityServer4 en github tiene varias muestras, pero ninguna con el flujo de código de autorización .

¿Alguien tiene una muestra sobre cómo implementar el flujo de código de autorización con Identity Server 4 y un cliente en MVC que lo consume?