using OpenIddict.Client.AspNetCore;
namespace Dpz.Core.Web.Controllers;
public class AccountController(
IApplicationSignInManager signInManager,
IAccountService accountService,
IConfiguration configuration
) : Controller
{
[HttpPost]
public async Task<IActionResult> LogOut()
{
await HttpContext.SignOutAsync(Program.AuthorizeCookieName);
// return SignOut(
// new AuthenticationProperties { RedirectUri = "/" },
// OpenIddictClientAspNetCoreDefaults.AuthenticationScheme
// );
return Redirect("/");
}
/// <summary>
/// 认证中心回调
/// </summary>
/// <returns></returns>
[Route("signin-oidc"), HttpGet]
public async Task<IActionResult> SignIn()
{
var result = await HttpContext.AuthenticateAsync(
OpenIddictClientAspNetCoreDefaults.AuthenticationScheme
);
if (!result.Succeeded || !result.Principal.Authenticated)
{
return Forbid(Program.AuthorizeCookieName);
}
// var principal = result.Principal;
var sub = result.Principal.FindFirst("sub")?.Value ?? throw new Exception("sub is null");
var userInfo = await accountService.GetOneUserAsync(sub);
if (userInfo == null)
{
return Forbid(Program.AuthorizeCookieName);
}
await signInManager.SignInAsync(
userInfo,
new AuthenticationProperties { IsPersistent = true }
);
// 跳转回原页面
var returnUrl = result.Properties?.RedirectUri ?? "/";
return Redirect(returnUrl);
}
[CheckAuthorize]
public IActionResult Index()
{
var memberHost = configuration["Server:Issuer"];
return Redirect($"{memberHost}/user");
}
[Route("re-login.html")]
public async Task<IActionResult> ReLogin()
{
await HttpContext.SignOutAsync(Program.AuthorizeCookieName);
return View();
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
代码解释
这是一个基于 ASP.NET Core 的账户控制器(AccountController),集成了 OpenIddict 进行身份认证。以下是详细解释:
📌 类定义与依赖注入
public class AccountController(
IApplicationSignInManager signInManager,
IAccountService accountService,
IConfiguration configuration
) : Controller
- 使用 主构造函数(C# 12 新特性)注入三个依赖:
IApplicationSignInManager:管理用户登录状态IAccountService:获取用户信息的业务服务IConfiguration:读取应用配置(如认证服务器地址)
🔹 方法 1:LogOut(登出)
[HttpPost]
public async Task<IActionResult> LogOut()
功能:
- 清除本地 Cookie 认证状态
- 使用自定义的
Program.AuthorizeCookieName退出登录 - 重定向到首页
/
注释代码:
- 被注释的代码是通过 OpenIddict 客户端 退出,会同时清除认证中心的会话
- 当前实现仅清除本地 Cookie
🔹 方法 2:SignIn(OIDC 回调处理)
[Route("signin-oidc"), HttpGet]
public async Task<IActionResult> SignIn()
功能:
这是 OAuth2/OIDC 认证流程的回调端点,处理认证中心返回的认证结果。
流程:
- 认证结果验证
var result = await HttpContext.AuthenticateAsync(
OpenIddictClientAspNetCoreDefaults.AuthenticationScheme
);
- 从 OpenIddict 客户端方案中获取认证结果
- 失败处理
if (!result.Succeeded || !result.Principal.Authenticated)
{
return Forbid(Program.AuthorizeCookieName);
}
- 认证失败或未通过则返回 403 禁止访问
- 提取用户标识
var sub = result.Principal.FindFirst("sub")?.Value ?? throw new Exception("sub is null");
- 从 Claims 中获取
sub(Subject,用户唯一标识符) - 这是 OIDC 标准中的用户 ID
- 获取用户信息
var userInfo = await accountService.GetOneUserAsync(sub);
if (userInfo == null)
{
return Forbid(Program.AuthorizeCookieName);
}
- 根据
sub从业务系统中查询用户详细信息 - 用户不存在则拒绝访问
- 建立本地会话
await signInManager.SignInAsync(
userInfo,
new AuthenticationProperties { IsPersistent = true }
);
- 使用自定义的 SignInManager 创建本地 Cookie 会话
IsPersistent = true表示创建持久化 Cookie("记住我"功能)
- 跳转回原页面
var returnUrl = result.Properties?.RedirectUri ?? "/";
return Redirect(returnUrl);
- 从认证属性中获取原始请求的 URL
- 默认跳转到首页
🔹 方法 3:Index(用户中心重定向)
[CheckAuthorize]
public IActionResult Index()
{
var memberHost = configuration["Server:Issuer"];
return Redirect($"{memberHost}/user");
}
功能:
- 需要授权才能访问(
[CheckAuthorize]自定义特性) - 从配置中读取认证服务器地址(
Server:Issuer) - 重定向到认证中心的用户管理页面
🔹 方法 4:ReLogin(重新登录)
[Route("re-login.html")]
public async Task<IActionResult> ReLogin()
{
await HttpContext.SignOutAsync(Program.AuthorizeCookieName);
return View();
}
功能:
- 清除本地 Cookie
- 返回一个视图(可能包含重新登录的引导页面)
🏗️ 架构特点
分离式认证:
- 使用外部 OIDC 认证中心(通过 OpenIddict Client)
- 本地维护会话(通过自定义 Cookie)
双重身份验证:
- OIDC 认证 → 本地用户查询 → 创建本地会话
灵活的注销策略:
- 可选择仅本地注销或联动认证中心注销
🔐 安全要点
- ✅ 验证
sub不为空 - ✅ 验证用户在本地系统存在
- ✅ 使用持久化 Cookie 提升用户体验
- ⚠️
throw new Exception应替换为更友好的错误处理
这是一个典型的 OIDC 客户端实现,适用于微服务架构中的 Web 应用统一认证场景。
AI 正在分析代码…
评论加载中...