.net - Xamarin 身份验证 - IUser 已贬值,迁移到 IAccount 时出现问题
问题描述
我的第一个 Xamarin Forms 应用程序即将结束(哇!),并且处于学习身份验证并将其链接到 Azure 的阶段。
我已经下载了我能找到的最好的例子,在这里:链接到 Xamarin Azure 示例
我计划浏览 IdentityService.cs 文件并弄清楚它是如何工作的。
不幸的是,最近出现了贬值,如下所述:msal net 2 已发布
我已经尽可能地改变了,但仍然有两个错误:
msalResult = await msaClient.AcquireTokenSilentAsync(Scopes,
IdentityService.GetUserByPolicy(msaClient.GetAccountsAsync(),
SignUpAndInPolicy), UIBehavior.ForceLogin, null, null, Authority, UIParent);
这显示一个错误:
严重性代码描述项目文件行抑制状态错误 CS1503 参数 1:无法从 'System.Threading.Tasks.Task>' 转换为 'System.Collections.Generic.IEnumerable' Reviewer.Core C:\Users\Administrator\Desktop\snppts\ xam-az-bw\src\Reviewer.Core\Services\IdentityService.cs 54 活动
和:
public void Logout()
{
foreach (var user in msaClient.GetAccountsAsync())
{
msaClient.Remove(user);
}
}
这显示了以下相关错误:
严重性代码 描述 项目文件行抑制状态错误 CS1579 foreach 语句无法对“Task>”类型的变量进行操作,因为“Task>”不包含“GetEnumerator”Reviewer.Core C:\Users\Administrator\Desktop\ 的公共实例定义snppts\xam-az-bw\src\Reviewer.Core\Services\IdentityService.cs 120 活动
我怀疑这两个问题有相同的根本原因。任何人都可以帮助我以正确的方式提取帐户吗?我不想更多地摆弄原件,而且我基本上是在修补一个我一开始还不了解的身份验证过程!
这是完整的文件代码:
using System;
using Microsoft.Identity.Client;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using Reviewer.Core;
using System.Linq;
[assembly: Dependency(typeof(IdentityService))]
namespace Reviewer.Core
{
public class IdentityService : IIdentityService
{
static readonly string Tenant = "b2cbuild.onmicrosoft.com";
static readonly string ClientID = "adc26e3b-2568-4007-810d- 6cc94e7416de";
static readonly string SignUpAndInPolicy = "B2C_1_Reviewer_SignUpIn";
static readonly string AuthorityBase =
$"https://login.microsoftonline.com/tfp/{Tenant}/";
static readonly string Authority = $"{AuthorityBase}
{SignUpAndInPolicy}";
static readonly string[] Scopes = {
"https://b2cbuild.onmicrosoft.com/reviewer/rvw_all" };
static readonly string RedirectUrl = $"msal{ClientID}://auth";
readonly PublicClientApplication msaClient;
public IdentityService()
{
msaClient = new PublicClientApplication(ClientID);
msaClient.ValidateAuthority = false;
msaClient.RedirectUri = RedirectUrl;
}
UIParent parent;
public UIParent UIParent { get => parent; set => parent = value; }
public async Task<AuthenticationResult> Login()
{
AuthenticationResult msalResult = null;
// Running on Android - we need UIParent to be set to the main Activity
if (UIParent == null && Device.RuntimePlatform == Device.Android)
return msalResult;
// First check if the token happens to be cached - grab silently
msalResult = await GetCachedSignInToken();
if (msalResult != null)
return msalResult;
// Token not in cache - call adb2c to acquire it
try
{
msalResult = await msaClient.AcquireTokenSilentAsync(Scopes,
IdentityService.GetUserByPolicy(msaClient.GetAccountsAsync(),
SignUpAndInPolicy),
UIBehavior.ForceLogin,
null,
null,
Authority,
UIParent);
if (msalResult?.Account.HomeAccountId != null)
{
var parsed = ParseIdToken(msalResult.IdToken);
DisplayName = parsed["name"]?.ToString();
}
}
catch (MsalServiceException ex)
{
if (ex.ErrorCode == MsalClientException.AuthenticationCanceledError)
{
System.Diagnostics.Debug.WriteLine("User cancelled");
}
else if (ex.ErrorCode == "access_denied")
{
// most likely the forgot password was hit
System.Diagnostics.Debug.WriteLine("Forgot password");
}
else
{
System.Diagnostics.Debug.WriteLine(ex);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
return msalResult;
}
public async Task<AuthenticationResult> GetCachedSignInToken()
{
try
{
// This checks to see if there's already a user in the cache
var authResult = await msaClient.AcquireTokenSilentAsync(Scopes,
IdentityService.GetUserByPolicy(msaClient.GetAccountsAsync(),
SignUpAndInPolicy),
Authority,
false);
if (authResult?.User != null)
{
var parsed = ParseIdToken(authResult.IdToken);
DisplayName = parsed["name"]?.ToString();
}
return authResult;
}
catch (MsalUiRequiredException ex)
{
// happens if the user hasn't logged in yet & isn't in the cache
System.Diagnostics.Debug.WriteLine(ex);
}
return null;
}
public void Logout()
{
foreach (var user in msaClient.GetAccountsAsync())
{
msaClient.Remove(user);
}
}
public string DisplayName { get; set; }
IAccount GetUserByPolicy(IEnumerable<IAccount> users, string policy)
{
foreach (var user in users)
{
string userIdentifier = Base64UrlDecode(user.HomeAccountId.Identifier.Split('.')[0]);
if (userIdentifier.EndsWith(policy.ToLower(), StringComparison.OrdinalIgnoreCase)) return user;
}
return null;
}
string Base64UrlDecode(string s)
{
s = s.Replace('-', '+').Replace('_', '/');
s = s.PadRight(s.Length + (4 - s.Length % 4) % 4, '=');
var byteArray = Convert.FromBase64String(s);
var decoded = Encoding.UTF8.GetString(byteArray, 0, byteArray.Count());
return decoded;
}
JObject ParseIdToken(string idToken)
{
// Get the piece with actual user info
idToken = idToken.Split('.')[1];
idToken = Base64UrlDecode(idToken);
return JObject.Parse(idToken);
}
}
}
解决方案
要回答您的问题,我认为您await
在 msaClient.GetAccountsAsync() 前面缺少
msalResult = await msaClient.AcquireTokenSilentAsync(Scopes,
IdentityService.GetUserByPolicy(await msaClient.GetAccountsAsync(),
SignUpAndInPolicy),
UIBehavior.ForceLogin, null, null, Authority, UIParent);
和
public void Logout()
{
var accounts = await msaClient.GetAccountsAsync();
foreach (var account in accounts)
{
msaClient.RemoveAsync(account);
accounts = await msaClient.GetAccountsAsync();
}
}
(这真的是一个ClearCache()
)
我建议你看看这个示例:https ://github.com/Azure-Samples/active-directory-b2c-xamarin-native ,其中已经有更新的代码
推荐阅读
- android - 直接通过xml加载drawable效率低吗?
- svg - 将未知来源的 SVG 居中到已知的 SVG
- php - 在我的 wordpress 主题中覆盖 email-header.php
- api - 如何在前端使用 LinkedIn JavaScript SDK 进行授权而不暴露您的 API 密钥?
- amazon-web-services - 管理来自未访问 Internet 的私有子网的 Route53 私有 DNS 条目
- ios - 将 TableView 点击位置转换为单元格视图位置
- javascript - Jquery 到 Pure Vanilla JS
- ios - Appcelerator - 在 Facebook 上分享链接
- azure-service-fabric - Azure Service Fabric 部署
- database-schema - 创建 ERD 和关系模式