Saltar al contenido principal

Añade autenticación a tu aplicación .NET Core (Blazor WASM)

tip

Requisitos previos

Instalación

Agrega el paquete NuGet a tu proyecto:

dotnet add package Blorc.OpenIdConnect

Integración

Añadir referencias de script

Incluye Blorc.Core/injector.js en el archivo index.html:

index.html
<head>
<!-- ... -->
<script src="_content/Blorc.Core/injector.js"></script>
<!-- ... -->
</head>

Registrar servicios

Añade el siguiente código al archivo Program.cs:

Program.cs
using Blorc.OpenIdConnect;
using Blorc.Services;

builder.Services.AddBlorcCore();
builder.Services.AddAuthorizationCore();
builder.Services.AddBlorcOpenIdConnect(
options =>
{
builder.Configuration.Bind("IdentityServer", options);
});

var webAssemblyHost = builder.Build();

await webAssemblyHost
.ConfigureDocumentAsync(async documentService =>
{
await documentService.InjectBlorcCoreJsAsync();
await documentService.InjectOpenIdConnectAsync();
});

await webAssemblyHost.RunAsync();
info

No es necesario usar el paquete Microsoft.AspNetCore.Components.WebAssembly.Authentication. El paquete Blorc.OpenIdConnect se encargará del proceso de autenticación.

Configurar URIs de redirección

Antes de profundizar en los detalles, aquí tienes una visión general rápida de la experiencia del usuario final. El proceso de inicio de sesión se puede simplificar de la siguiente manera:

  1. Tu aplicación invoca el método de inicio de sesión.
  2. El usuario es redirigido a la página de inicio de sesión de Logto. Para aplicaciones nativas, se abre el navegador del sistema.
  3. El usuario inicia sesión y es redirigido de vuelta a tu aplicación (configurada como el URI de redirección).
Sobre el inicio de sesión basado en redirección
  1. Este proceso de autenticación sigue el protocolo OpenID Connect (OIDC), y Logto aplica medidas de seguridad estrictas para proteger el inicio de sesión del usuario.
  2. Si tienes múltiples aplicaciones, puedes usar el mismo proveedor de identidad (Logto). Una vez que el usuario inicia sesión en una aplicación, Logto completará automáticamente el proceso de inicio de sesión cuando el usuario acceda a otra aplicación.

Para aprender más sobre la lógica y los beneficios del inicio de sesión basado en redirección, consulta Experiencia de inicio de sesión de Logto explicada.


nota

En los siguientes fragmentos de código, asumimos que tu aplicación está ejecutándose en http://localhost:3000/.

Configurar URIs de redirección

Cambia a la página de detalles de la aplicación en Logto Console. Añade una URI de redirección http://localhost:3000/callback.

URI de redirección en Logto Console

Al igual que al iniciar sesión, los usuarios deben ser redirigidos a Logto para cerrar la sesión de la sesión compartida. Una vez terminado, sería ideal redirigir al usuario de vuelta a tu sitio web. Por ejemplo, añade http://localhost:3000/ como la sección de URI de redirección posterior al cierre de sesión.

Luego haz clic en "Guardar" para guardar los cambios.

Configurar aplicación

Añade el siguiente código al archivo appsettings.json:

appsettings.json
{
// ...
IdentityServer: {
Authority: 'https://<your-logto-endpoint>/oidc',
ClientId: '<your-logto-app-id>',
PostLogoutRedirectUri: 'http://localhost:3000/',
RedirectUri: 'http://localhost:3000/callback',
ResponseType: 'code',
Scope: 'openid profile', // Añade más alcances si es necesario
},
}

Recuerda añadir el RedirectUri y el PostLogoutRedirectUri a la lista de URIs de redirección permitidos en la configuración de la aplicación Logto. Ambos son la URL de tu aplicación WASM.

Añadir componente AuthorizeView

En las páginas Razor que requieren autenticación, añade el componente AuthorizeView. Supongamos que es la página Home.razor:

Pages/Home.razor
@using Microsoft.AspNetCore.Components.Authorization
@page "/"

<AuthorizeView>
<Authorized>
@* Vista autenticada *@
<button @onclick="OnLogoutButtonClickAsync">
Cerrar sesión
</button>
</Authorized>
<NotAuthorized>
@* Vista no autenticada *@
<button @onclick="OnLoginButtonClickAsync">
Iniciar sesión
</button>
</NotAuthorized>
</AuthorizeView>

Configurar autenticación

En el archivo Home.razor.cs (créalo si no existe), añade el siguiente código:

Pages/Home.razor.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Blorc.OpenIdConnect;
using Microsoft.AspNetCore.Components.Authorization;

[Authorize]
public partial class Home : ComponentBase
{
[Inject]
public required IUserManager UserManager { get; set; }

public User<Profile>? User { get; set; }

[CascadingParameter]
protected Task<AuthenticationState>? AuthenticationStateTask { get; set; }

protected override async Task OnInitializedAsync()
{
User = await UserManager.GetUserAsync<User<Profile>>(AuthenticationStateTask!);
}

private async Task OnLoginButtonClickAsync(MouseEventArgs obj)
{
await UserManager.SignInRedirectAsync();
}

private async Task OnLogoutButtonClickAsync(MouseEventArgs obj)
{
await UserManager.SignOutRedirectAsync();
}
}

Una vez que el usuario está autenticado, la propiedad User se llenará con la información del usuario.

Punto de control: Prueba tu aplicación

Ahora, puedes probar tu aplicación:

  1. Ejecuta tu aplicación, verás el botón de inicio de sesión.
  2. Haz clic en el botón de inicio de sesión, el SDK iniciará el proceso de inicio de sesión y te redirigirá a la página de inicio de sesión de Logto.
  3. Después de iniciar sesión, serás redirigido de vuelta a tu aplicación y verás el botón de cierre de sesión.
  4. Haz clic en el botón de cierre de sesión para limpiar el almacenamiento local y cerrar sesión.

Obtener información del usuario

Mostrar información del usuario

Aquí hay algunos ejemplos de cómo mostrar información del usuario en la página Home.razor:

<AuthorizeView>
<Authorized>
@* Vista de inicio de sesión *@
@* ... *@
<p>Has iniciado sesión como @(@User?.Profile?.Name ?? "(nombre desconocido)").</p>
</Authorized>
@* ... *@
</AuthorizeView>

Para más propiedades y reclamos, consulta las clases User y Profile en el paquete Blorc.OpenIdConnect.

Solicitar reclamos adicionales

Es posible que encuentres que falta alguna información del usuario en el objeto devuelto desde User. Esto se debe a que OAuth 2.0 y OpenID Connect (OIDC) están diseñados para seguir el principio de privilegio mínimo (PoLP), y Logto está construido sobre estos estándares.

De forma predeterminada, se devuelven reclamos limitados. Si necesitas más información, puedes solicitar alcances adicionales para acceder a más reclamos.

info

Un "reclamo (Claim)" es una afirmación hecha sobre un sujeto; un "alcance (Scope)" es un grupo de reclamos. En el caso actual, un reclamo es una pieza de información sobre el usuario.

Aquí tienes un ejemplo no normativo de la relación alcance - reclamo:

tip

El reclamo "sub" significa "sujeto", que es el identificador único del usuario (es decir, el ID del usuario).

El SDK de Logto siempre solicitará tres alcances: openid, profile y offline_access.

Para solicitar alcances adicionales, puedes agregar alcances válidos a la propiedad IdentityServer.Scope en el archivo appsettings.json.

{
// ...
"IdentityServer": {
// ...
"Scope": "openid profile email phone"
}
}

Reclamos que necesitan solicitud de red

Para evitar sobrecargar el objeto de usuario, algunos reclamos requieren solicitudes de red para ser obtenidos. Por ejemplo, el reclamo custom_data no se incluye en el objeto de usuario incluso si se solicita en los alcances. Para obtener estos reclamos, puedes establecer la propiedad IdentityServer.LoadUserInfo en true en el archivo appsettings.json.

Por ejemplo, para obtener la dirección de correo electrónico del usuario y los datos personalizados, puedes usar la siguiente configuración:

{
// ...
"IdentityServer": {
// ...
"Scope": "openid profile email custom_data",
"LoadUserInfo": true
}
}

Alcances y reclamos

Logto utiliza las convenciones de alcances y reclamos (scopes and claims) de OIDC para definir los alcances y reclamos para obtener información del usuario del Token de ID y del endpoint userinfo de OIDC. Tanto "alcance" como "reclamo" son términos de las especificaciones de OAuth 2.0 y OpenID Connect (OIDC).

Aquí está la lista de alcances (Scopes) soportados y los reclamos (Claims) correspondientes:

openid

Nombre del reclamoTipoDescripción¿Necesita userinfo?
substringEl identificador único del usuarioNo

profile

Nombre del reclamoTipoDescripción¿Necesita userinfo?
namestringEl nombre completo del usuarioNo
usernamestringEl nombre de usuario del usuarioNo
picturestringURL de la foto de perfil del usuario final. Esta URL DEBE referirse a un archivo de imagen (por ejemplo, un archivo de imagen PNG, JPEG o GIF), en lugar de a una página web que contenga una imagen. Ten en cuenta que esta URL DEBERÍA referirse específicamente a una foto de perfil del usuario final adecuada para mostrar al describir al usuario final, en lugar de una foto arbitraria tomada por el usuario final.No
created_atnumberMomento en que se creó el usuario final. El tiempo se representa como el número de milisegundos desde la época Unix (1970-01-01T00:00:00Z).No
updated_atnumberMomento en que se actualizó por última vez la información del usuario final. El tiempo se representa como el número de milisegundos desde la época Unix (1970-01-01T00:00:00Z).No

Otros reclamos estándar incluyen family_name, given_name, middle_name, nickname, preferred_username, profile, website, gender, birthdate, zoneinfo y locale también se incluirán en el alcance profile sin necesidad de solicitar el endpoint de userinfo. Una diferencia en comparación con los reclamos anteriores es que estos reclamos solo se devolverán cuando sus valores no estén vacíos, mientras que los reclamos anteriores devolverán null si los valores están vacíos.

nota

A diferencia de los reclamos estándar, los reclamos created_at y updated_at utilizan milisegundos en lugar de segundos.

email

Nombre del reclamoTipoDescripción¿Necesita userinfo?
emailstringLa dirección de correo electrónico del usuarioNo
email_verifiedbooleanSi la dirección de correo electrónico ha sido verificadaNo

phone

Nombre del reclamoTipoDescripción¿Necesita userinfo?
phone_numberstringEl número de teléfono del usuarioNo
phone_number_verifiedbooleanSi el número de teléfono ha sido verificadoNo

address

Por favor, consulta el OpenID Connect Core 1.0 para los detalles del reclamo de dirección.

custom_data

Nombre del reclamoTipoDescripción¿Necesita userinfo?
custom_dataobjectLos datos personalizados del usuario

identities

Nombre del reclamoTipoDescripción¿Necesita userinfo?
identitiesobjectLas identidades vinculadas del usuario
sso_identitiesarrayLas identidades SSO vinculadas del usuario

urn:logto:scope:organizations

Nombre del reclamoTipoDescripción¿Necesita userinfo?
organizationsstring[]Los IDs de las organizaciones a las que pertenece el usuarioNo
organization_dataobject[]Los datos de las organizaciones a las que pertenece el usuario

urn:logto:scope:organization_roles

Nombre del reclamoTipoDescripción¿Necesita userinfo?
organization_rolesstring[]Los roles de organización a los que pertenece el usuario con el formato <organization_id>:<role_name>No

Considerando el rendimiento y el tamaño de los datos, si "¿Necesita userinfo?" es "Sí", significa que el reclamo no aparecerá en el Token de ID, pero se devolverá en la respuesta del endpoint de userinfo.

Recursos de API

Recomendamos leer primero 🔐 Control de acceso basado en roles (RBAC) para entender los conceptos básicos de Logto RBAC y cómo configurar correctamente los recursos de API.

Por defecto, cuando accedes a User?.AccessToken, obtendrás un token opaco que tiene una longitud corta y no es un JWT (JSON Web Token). Este token se utiliza para acceder al endpoint de userinfo.

Añadir recurso de API a la configuración

Para obtener un token JWT que pueda ser utilizado para acceder a un recurso de API definido en Logto, añade los siguientes parámetros al archivo appsettings.json (tomando https://my-api-resource como ejemplo):

appsettings.json
{
// ...
"IdentityServer": {
// ...
"Scope": "openid profile email <your-api-scopes>", // Añade tus alcances de API aquí
"Resource": "https://my-api-resource",
"ExtraTokenParams": {
"resource": "https://my-api-resource" // Asegúrate de que la clave "resource" esté en minúsculas
}
}
}

La propiedad Resource se utiliza para añadir el recurso de API a la solicitud de autenticación. La propiedad ExtraTokenParams se utiliza para añadir el recurso de API a la solicitud de token. Dado que Logto se ajusta a RFC 8707 para recursos de API, ambas propiedades son necesarias.

precaución

Dado que WebAssembly es una aplicación del lado del cliente, la solicitud de token solo se enviará al lado del servidor una vez. Debido a esta naturaleza, LoadUserInfo entra en conflicto con la obtención del token de acceso para recursos de API.

Usar token de acceso

Una vez que el usuario está autenticado, puedes acceder al recurso de API utilizando la propiedad User?.AccessToken. Por ejemplo, puedes usar el HttpClient para acceder al recurso de API:

using Blorc.OpenIdConnect;

builder.Services
.AddHttpClient("MyApiResource", client =>
{
client.BaseAddress = new Uri("https://my-api-resource");
})
.AddAccessToken(); // Añadir token de acceso al encabezado de la solicitud

Lecturas adicionales

Flujos de usuario final: flujos de autenticación, flujos de cuenta y flujos de organización Configurar conectores Protege tu API