fengling-auth-service/Views/Authorization/Authorize.cshtml
Sam 0c5bd5e647 feat: 添加OAuth2认证配置和实现
添加OAuth2认证相关配置文件和服务实现,包括环境变量配置、PKCE流程支持、token管理等功能。主要变更:
- 新增OAuth2配置文件
- 实现OAuth2服务层
- 更新请求拦截器支持token自动刷新
- 修改认证API和store以支持OAuth2流程
2026-02-07 17:47:11 +08:00

166 lines
8.1 KiB
Plaintext

@using Microsoft.Extensions.Primitives
@model Fengling.AuthService.ViewModels.AuthorizeViewModel
@{
Layout = "_Layout";
ViewData["Title"] = "授权确认";
}
<div class="min-h-[calc(100vh-4rem)] flex items-center justify-center px-4 py-8">
<div class="w-full max-w-md">
<!-- Header -->
<div class="text-center mb-8">
<div class="inline-flex h-16 w-16 items-center justify-center rounded-full bg-primary/10 mb-4">
<svg class="h-8 w-8 text-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
</svg>
</div>
<h1 class="text-2xl font-bold">授权确认</h1>
<p class="text-muted-foreground mt-2">
<span class="text-primary font-medium">@Model.ApplicationName</span>
请求访问您的账户
</p>
</div>
<!-- Authorization Card -->
<div class="bg-card border border-border rounded-lg shadow-sm overflow-hidden">
<!-- App Info Section -->
<div class="p-6 border-b border-border">
<div class="flex items-start gap-4">
<div class="flex-shrink-0">
<div
class="h-12 w-12 rounded-lg bg-primary flex items-center justify-center text-primary-foreground text-lg font-semibold">
@(Model.ApplicationName?.Substring(0, Math.Min(1, Model.ApplicationName.Length)).ToUpper() ?? "A")
</div>
</div>
<div class="flex-1 min-w-0">
<h2 class="font-semibold text-lg truncate">@Model.ApplicationName</h2>
<p class="text-sm text-muted-foreground mt-1">
该应用将获得以下权限:
</p>
</div>
</div>
</div>
<!-- Permissions Section -->
<div class="p-6">
<h3 class="text-sm font-medium text-foreground mb-4">请求的权限</h3>
<div class="space-y-3">
@if (Model.Scopes != null && Model.Scopes.Length > 0)
{
@foreach (var scope in Model.Scopes)
{
<div class="flex items-start gap-3 p-3 rounded-lg bg-muted/50">
<svg class="h-5 w-5 text-primary mt-0.5 flex-shrink-0"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
<polyline points="22 4 12 14.01 9 11.01"/>
</svg>
<div class="flex-1">
<p class="text-sm font-medium">@GetScopeDisplayName(scope)</p>
<p class="text-xs text-muted-foreground mt-0.5">@GetScopeDescription(scope)</p>
</div>
</div>
}
}
else
{
<p class="text-sm text-muted-foreground">无特定权限请求</p>
}
</div>
</div>
<!-- Warning Section -->
<div class="p-4 bg-destructive/5 border-t border-border">
<div class="flex items-start gap-2">
<svg class="h-4 w-4 text-destructive mt-0.5 flex-shrink-0" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round">
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/>
<path d="M12 9v4"/>
<path d="M12 17h.01"/>
</svg>
<p class="text-xs text-muted-foreground">
授予权限后,该应用将能够访问您的账户信息。您可以随时在授权管理中撤销权限。
</p>
</div>
</div>
</div>
<!-- Action Buttons -->
<form asp-controller="Authorization" asp-action="Authorize" method="post" class="mt-6 space-y-3">
@* Flow the request parameters so they can be received by the Accept/Reject actions: *@
@foreach (var parameter in Context.Request.HasFormContentType ?
(IEnumerable<KeyValuePair<string, StringValues>>) Context.Request.Form : Context.Request.Query)
{
<input type="hidden" name="@parameter.Key" value="@parameter.Value" />
}
<div class="grid grid-cols-2 gap-3">
<button type="submit" name="submit.Accept" value="Yes"
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 bg-primary text-primary-foreground hover:bg-primary/90 h-11 px-8 shadow">
<svg class="mr-2 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
<polyline points="22 4 12 14.01 9 11.01"/>
</svg>
授权
</button>
<button type="submit" name="submit.Deny" value="No"
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-11 px-8">
<svg class="mr-2 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
取消
</button>
</div>
</form>
<!-- Footer Links -->
<div class="mt-6 text-center text-sm">
<a href="#" class="text-muted-foreground hover:text-foreground transition-colors">
了解关于 OAuth 授权的更多信息
</a>
</div>
</div>
</div>
@functions {
private string GetScopeDisplayName(string scope)
{
return scope switch
{
"openid" => "OpenID Connect",
"profile" => "个人资料",
"email" => "电子邮件地址",
"phone" => "电话号码",
"address" => "地址信息",
"roles" => "角色权限",
"offline_access" => "离线访问",
_ => scope
};
}
private string GetScopeDescription(string scope)
{
return scope switch
{
"openid" => "用于用户身份验证",
"profile" => "访问您的姓名、头像等基本信息",
"email" => "访问您的电子邮件地址",
"phone" => "访问您的电话号码",
"address" => "访问您的地址信息",
"roles" => "访问您的角色和权限信息",
"offline_access" => "在您离线时仍可访问数据",
_ => "自定义权限范围"
};
}
}