Añade autenticación a tu aplicación .NET Core (Blazor WASM)
- La siguiente demostración está construida sobre .NET Core 8.0 y Blorc.OpenIdConnect.
- Los proyectos de ejemplo de .NET Core están disponibles en el repositorio de GitHub.
Requisitos previos
- Una cuenta de Logto Cloud o un Logto autoalojado.
- Una aplicación de página única de Logto creada.
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
:
<head>
<!-- ... -->
<script src="_content/Blorc.Core/injector.js"></script>
<!-- ... -->
</head>
Registrar servicios
Añade el siguiente código al archivo 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();
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:
- Tu aplicación invoca el método de inicio de sesión.
- El usuario es redirigido a la página de inicio de sesión de Logto. Para aplicaciones nativas, se abre el navegador del sistema.
- 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
- 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.
- 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.
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
.
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
:
{
// ...
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
:
@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:
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:
- Ejecuta tu aplicación, verás el botón de inicio de sesión.
- 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.
- 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.
- 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.
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:
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 reclamo | Tipo | Descripción | ¿Necesita userinfo? |
---|---|---|---|
sub | string | El identificador único del usuario | No |
profile
Nombre del reclamo | Tipo | Descripción | ¿Necesita userinfo? |
---|---|---|---|
name | string | El nombre completo del usuario | No |
username | string | El nombre de usuario del usuario | No |
picture | string | URL 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_at | number | Momento 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_at | number | Momento 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.
A diferencia de los reclamos estándar, los reclamos created_at
y updated_at
utilizan milisegundos en lugar de segundos.
email
Nombre del reclamo | Tipo | Descripción | ¿Necesita userinfo? |
---|---|---|---|
string | La dirección de correo electrónico del usuario | No | |
email_verified | boolean | Si la dirección de correo electrónico ha sido verificada | No |
phone
Nombre del reclamo | Tipo | Descripción | ¿Necesita userinfo? |
---|---|---|---|
phone_number | string | El número de teléfono del usuario | No |
phone_number_verified | boolean | Si el número de teléfono ha sido verificado | No |
address
Por favor, consulta el OpenID Connect Core 1.0 para los detalles del reclamo de dirección.
custom_data
Nombre del reclamo | Tipo | Descripción | ¿Necesita userinfo? |
---|---|---|---|
custom_data | object | Los datos personalizados del usuario | Sí |
identities
Nombre del reclamo | Tipo | Descripción | ¿Necesita userinfo? |
---|---|---|---|
identities | object | Las identidades vinculadas del usuario | Sí |
sso_identities | array | Las identidades SSO vinculadas del usuario | Sí |
urn:logto:scope:organizations
Nombre del reclamo | Tipo | Descripción | ¿Necesita userinfo? |
---|---|---|---|
organizations | string[] | Los IDs de las organizaciones a las que pertenece el usuario | No |
organization_data | object[] | Los datos de las organizaciones a las que pertenece el usuario | Sí |
urn:logto:scope:organization_roles
Nombre del reclamo | Tipo | Descripción | ¿Necesita userinfo? |
---|---|---|---|
organization_roles | string[] | 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):
{
// ...
"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.
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