Maui学习笔记-身份认证和授权案例
在深入研究身份验证和授权时,可能会遇到很多术语。我们来简单介绍一下。
-
Authentication,简单来讲时认证、验证身份检查用户名和密码,更高级方法设计到指纹、扫描、人脸识别或2FA认证。
-
Authorization,授权,一旦通过身份认证,系统就可以决定当前用户是否有访问某些信息或执行一些操作的授权。
-
Open Authorization(OAuth),开放授权,它允许第三方用户访问你的程序,而无需注册用户名和密码。
使用ASP.NET Core Identity创建身份认证服务
-
我们首先使用ASP.NET Core WebApi(MinimalApis)创建一个基本的身份验证服务。
-
安装需要NuGet包
-
Microsoft.EntityFrameworkCore
-
Microsoft.EntityFrameworkCore.Sqlite
-
Microsoft.AspNetCore.Identity.EntityFrameworkCore
创建用户
-
创建User类,继承IdentityUser
-
IdentityUser是有框架管理的用户基类,它包括一些用户的基本属性,如UserName、PhoneNumber和Email等,所以我们不需要手动添加
public class User:IdentityUser
{
//出生日期
public DateOnly DateOfBirth { get; set; }
}
-
创建UserDbContext,用于处理用户相关的数据库操作。
public class UserDbContext:IdentityDbContext<User>
{
public UserDbContext(DbContextOptions<UserDbContext> options) : base(options)
{
}
}
注册身份认证所需的服务
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//注册身份验证,并配置Token.
builder.Services.AddAuthentication()
.AddBearerToken(IdentityConstants.BearerScheme);
//注册用户身份验证,指定数据库上下文.添加API端点支持,添加默认的Token
builder.Services.AddIdentityCore<User>()
.AddEntityFrameworkStores<UserDbContext>()
.AddApiEndpoints()
.AddDefaultTokenProviders();
//使用Sqlite数据库
builder.Services.AddDbContext<UserDbContext>
(opt => opt.UseSqlite(@"Data Source = userdata.db"));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
//添加身份验证中间件,它会自动为身份验证和用户管理创建一系列标准的 REST API 端点。
app.MapIdentityApi<User>();
//创建数据库
using (var scope = app.Services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<UserDbContext>();
dbContext.Database.EnsureCreated();
}
app.Run()
启动项目
-
我们看到框架已经为我们创建了一系列的API端点.
-
我们在register中注册一个账号,这里注意因为我们没有设置密码规则,这里的密码需要包含大小写字母、数字和特殊字符.
-
注册成功后,展开login,useCoolieshe和useSessionCookies选择false.
-
在Request body中输入邮件账号和密码,然后执行.
-
在Response body中我们可以看到token数据,这里的"expiresIn":3600代表令牌有效时间为3600秒.
创建Maui客户端项目
-
一旦有了身份验证服务,创建一个登录就简单了,我们只需要发送请求和接收响应就可以了.
-
我们使用Maui访问后端并拿到令牌.
-
首先安装CommunityToolkit.Mvvm工具包,然后创建两个目录,Models、ViewModels.
-
在Models中创建一个存储令牌信息的类.
public class BearerTokenInfo
{
/// <summary>
/// 访问令牌
/// </summary>
public string AccessToken { get; set; }
/// <summary>
/// 访问令牌过期时间
/// </summary>
public int ExpiresIn { get; set; }
/// <summary>
/// 刷新令牌
/// </summary>
public string RefreshToken { get; set; }
/// <summary>
/// 令牌时间戳
/// </summary>
public DateTime? TokenTimestamp { get; set; }
}
-
创建WebService类,用来处理与后端服务的通信.
-
需要获取你后端启动的IP地址.
-
一个请求令牌的方法,记录获取令牌时间.
public class WebService
{
static string baseUrl = "你的IP地址";
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(baseUrl)
};
public static WebService Instance { get; } = new();
public async Task<BearerTokenInfo> RequestTokenAsync(string url, object postContent)
{
HttpResponseMessage response = await httpClient.PostAsJsonAsync(url, postContent);
response.EnsureSuccessStatusCode();
var tokenInfo = await response.Content.ReadFromJsonAsync<BearerTokenInfo>();
tokenInfo.TokenTimestamp = DateTime.UtcNow;
SetAuthHeader(tokenInfo.AccessToken);
return tokenInfo;
}
private void SetAuthHeader(string token)
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
public async Task<BearerTokenInfo> Authenticate(string email, string password)
{
return await RequestTokenAsync("login/", new { email, password });
}
}
-
我们创建一个MainViewModel,用来执行登录方法
public partial class MainViewModel:ObservableObject
{
WebService webService = WebService.Instance;
[ObservableProperty]
private string email;
[ObservableProperty]
private string password;
[RelayCommand]
private async Task LoginAsync()
{
try
{
var tokenInfo = await webService.Authenticate(Email, Password);
await Shell.Current.DisplayAlert("Token", tokenInfo.AccessToken, "确定");
}
catch (Exception e)
{
await Shell.Current.DisplayAlert("错误", e.Message, "确定");
}
}
}
-
MainPage
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:AuthMauiDome.ViewModels"
x:Class="AuthMauiDome.MainPage">
<ContentPage.BindingContext>
<vm:MainViewModel />
</ContentPage.BindingContext>
<VerticalStackLayout
Spacing="10">
<Entry Placeholder="Email"
Text="{Binding Email}"/>
<Entry Placeholder="密码"
Text="{Binding Password}"
IsPassword="True"/>
<Button Text="登录"
Command="{Binding LoginCommand}"/>
</VerticalStackLayout>
</ContentPage>