MAUI WebAuthenticator集成Microsoft SSO时未返回IdToken且AccessToken非JWT格式的问题
MAUI WebAuthenticator集成Microsoft SSO时未返回IdToken且AccessToken非JWT格式的问题
我仔细看了你的代码和配置细节,这两个问题其实都和Microsoft Account认证的端点版本配置有关,咱们一步步来解决:
问题根源分析
默认情况下,ASP.NET Core的AddMicrosoftAccount使用的是微软身份认证的v1端点,这个端点返回的Access Token是不透明的(非JWT格式),并且对OpenID Connect的支持不完整,所以即使你添加了openid Scope,也不会返回IdToken。而你在Azure中配置的应用是v2版本(Access Token版本为2),必须强制使用v2端点才能获取到JWT格式的Access Token和IdToken。
解决方案步骤
1. 强制Microsoft Account使用v2认证端点
修改你ASP.NET Web App的认证配置,在AddMicrosoftAccount中添加Authority配置,指定使用v2端点:
builder.Services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) .AddCookie() .AddMicrosoftAccount(options => { options.ClientId = "ClientId"; options.ClientSecret = "ClientSecret"; options.SaveTokens = true; options.CallbackPath = "/mobileauth"; // 关键:强制使用v2端点,才能返回JWT Token和IdToken options.Authority = "https://login.microsoftonline.com/common/v2.0"; options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("profile"); options.Scope.Add("email"); options.Scope.Add("offline_access"); options.Scope.Add("https://graph.microsoft.com/User.Read"); // 可选:明确指定ResponseType,确保请求IdToken options.ResponseType = "code id_token"; });
2. 在AuthController中获取并传递IdToken
修改你的AuthController,添加获取IdToken的逻辑,并将其传递给MAUI端:
[Route("mobileauth")] [ApiController] public class AuthController : ControllerBase { const String CallbackScheme = "myapp"; [HttpGet("{scheme}")] public async Task Get([FromRoute] String scheme) { var auth = await Request.HttpContext.AuthenticateAsync(scheme); // 简化认证成功判断逻辑 if (!auth.Succeeded) { await Request.HttpContext.ChallengeAsync(scheme); return; // 必须return,避免后续代码执行 } var claims = auth.Principal?.Claims ?? throw new InvalidOperationException("Claims are required"); var email = claims?.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.Email)?.Value; // 获取IdToken和JWT格式的AccessToken var accessToken = auth.Properties.GetTokenValue("access_token"); var idToken = auth.Properties.GetTokenValue("id_token"); var refreshToken = auth.Properties.GetTokenValue("refresh_token"); var queryParams = new Dictionary<String, String> { { "access_token", accessToken ?? throw new InvalidOperationException("Access token is required") }, { "id_token", idToken ?? throw new InvalidOperationException("Id token is required") }, { "refresh_token", refreshToken ?? String.Empty }, { "expires_in", (auth.Properties.ExpiresUtc?.ToUnixTimeSeconds() ?? -1).ToString() }, { "email", email ?? throw new InvalidOperationException("Email is required") } } .Where(kvp => !String.IsNullOrEmpty(kvp.Value) && kvp.Value != "-1") .Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}"); var query = String.Join("&", queryParams); var url = $"{CallbackScheme}://#{query}"; Request.HttpContext.Response.Redirect(url); } }
3. MAUI端解码JWT Token创建ClaimsIdentity
现在MAUI端拿到的Access Token和IdToken都是JWT格式了,你可以用System.IdentityModel.Tokens.Jwt库解码并创建身份信息:
using System.IdentityModel.Tokens.Jwt; var authResult = await WebAuthenticator.Default.AuthenticateAsync( new Uri("https://10.0.2.2:7016/mobileauth/Microsoft"), new Uri("myapp://")); // 解码IdToken获取用户身份信息 var idToken = authResult.Properties["id_token"]; var jwtHandler = new JwtSecurityTokenHandler(); var jwtToken = jwtHandler.ReadJwtToken(idToken); // 创建ClaimsIdentity供MAUI应用使用 var userIdentity = new ClaimsIdentity(jwtToken.Claims, "MicrosoftAuth"); var userPrincipal = new ClaimsPrincipal(userIdentity); // 后续可以将Principal存入应用的身份验证上下文
额外验证点
- 确认Azure应用注册的重定向URI已添加你的Web App的
https://<你的域名>/mobileauth地址 - 确保你的Azure应用是v2版本的应用注册(对应你提到的Access Token版本2)
- 测试时可以用JWT解析工具(比如jwt.io)验证返回的Token是否为JWT格式
内容来源于stack exchange
相关产品推荐
相关产品推荐

