移动端sso

This commit is contained in:
biss committed 2026-08-15 16:37:10 +08:00
1 parent 18151fda81
commit f08cd94924
10 files changed
+155 -11

No files matched your search

+24 -5
View File
@@ -26,6 +26,7 @@ public sealed class SsoController(
ILogger<SsoController> logger) : ControllerBase
{
private const string BindingIntentProperty = "sso-binding-intent";
private const string NativeAppProperty = "sso-native-app";
private readonly SsoOptions _options = options.Value;
[AllowAnonymous]
@@ -42,6 +43,7 @@ public sealed class SsoController(
public async Task<IActionResult> Login(
[FromQuery] string? returnUrl = null,
[FromQuery] string? bindingIntent = null,
[FromQuery] bool nativeApp = false,
CancellationToken cancellationToken = default)
{
if (!_options.Enabled)
@@ -49,6 +51,8 @@ public sealed class SsoController(
var safeReturnUrl = NormalizeReturnUrl(returnUrl);
var properties = new AuthenticationProperties();
if (nativeApp)
properties.Items[NativeAppProperty] = bool.TrueString;
if (!string.IsNullOrWhiteSpace(bindingIntent))
{
var targetUserId = await cache.GetStringAsync(
@@ -108,6 +112,10 @@ public sealed class SsoController(
out var storedBindingIntent)
? storedBindingIntent
: null;
var nativeApp = authentication.Properties is { } externalProperties &&
externalProperties.Items.TryGetValue(NativeAppProperty, out var nativeAppValue) &&
bool.TryParse(nativeAppValue, out var isNativeApp) &&
isNativeApp;
if (!string.IsNullOrWhiteSpace(bindingIntent))
{
var targetUserId = await cache.GetStringAsync(
@@ -165,7 +173,7 @@ public sealed class SsoController(
cancellationToken);
await HttpContext.SignOutAsync(SsoAuthSchemes.ExternalCookie);
var bindingPage = BuildFrontendUrl("/sso/bind") +
var bindingPage = BuildFrontendUrl("/sso/bind", nativeApp) +
$"?code={Uri.EscapeDataString(bindingCode)}" +
$"&redirect={Uri.EscapeDataString(NormalizeReturnUrl(returnUrl))}";
return Redirect(bindingPage);
@@ -190,7 +198,7 @@ public sealed class SsoController(
cancellationToken);
await HttpContext.SignOutAsync(SsoAuthSchemes.ExternalCookie);
var callback = BuildFrontendUrl("/sso/callback") +
var callback = BuildFrontendUrl("/sso/callback", nativeApp) +
$"?code={Uri.EscapeDataString(exchangeCode)}" +
$"&redirect={Uri.EscapeDataString(NormalizeReturnUrl(returnUrl))}";
return Redirect(callback);
@@ -344,7 +352,8 @@ public sealed class SsoController(
[Authorize]
[HttpPost("prepare-binding")]
public async Task<ActionResult<SsoBindingStartResponse>> PrepareBinding(
CancellationToken cancellationToken)
CancellationToken cancellationToken,
[FromQuery] bool nativeApp = false)
{
if (!_options.Enabled)
return SsoProblem("统一身份认证尚未启用。", StatusCodes.Status404NotFound);
@@ -373,7 +382,8 @@ public sealed class SsoController(
values: new
{
returnUrl = "/account",
bindingIntent = intentCode
bindingIntent = intentCode,
nativeApp
})!;
return new SsoBindingStartResponse(loginUrl);
}
@@ -417,10 +427,19 @@ public sealed class SsoController(
? returnUrl
: "/dashboard";
private string BuildFrontendUrl(string path) =>
private string BuildFrontendUrl(string path, bool requireAbsoluteUrl = false)
{
if (requireAbsoluteUrl && string.IsNullOrWhiteSpace(_options.FrontendBaseUrl))
{
throw new InvalidOperationException(
"原生单点登录需要配置 Sso:FrontendBaseUrl 为已验证的 HTTPS 地址。");
}
return
string.IsNullOrWhiteSpace(_options.FrontendBaseUrl)
? path
: _options.FrontendBaseUrl.TrimEnd('/') + path;
}
private RedirectResult RedirectToFrontendError(
string error,