我有一个现有的企业部署应用程序,该应用程序使用OpenID Connect
进行身份验证。一旦通过身份验证,为了安全起见,我将AuthState
对象存储在iOS钥匙串中,以便以后可以仅使用Face / Touch ID来登录用户(鉴于AuthState中的刷新令牌仍然有效)。 AuthState
对象如下所示:
namespace OpenId.AppAuth
{
[Register ("OIDAuthState", true)]
public class AuthState : NSObject, INSCoding, INativeObject, IDisposable, INSSecureCoding
{
[CompilerGenerated]
private static readonly IntPtr class_ptr = Class.GetHandle ("OIDAuthState");
[CompilerGenerated]
private object __mt_ErrorDelegate_var;
[CompilerGenerated]
private object __mt_StateChangeDelegate_var;
public override IntPtr ClassHandle {
get;
}
[CompilerGenerated]
public virtual NSError AuthorizationError {
[Export ("authorizationError")]
get;
}
[CompilerGenerated]
public virtual IAuthStateErrorDelegate ErrorDelegate {
[Export ("errorDelegate", ArgumentSemantic.Weak)]
get;
[Export ("setErrorDelegate:", ArgumentSemantic.Weak)]
set;
}
[CompilerGenerated]
public virtual bool IsAuthorized {
[Export ("isAuthorized")]
get;
}
[CompilerGenerated]
public virtual AuthorizationResponse LastAuthorizationResponse {
[Export ("lastAuthorizationResponse")]
get;
}
[CompilerGenerated]
public virtual RegistrationResponse LastRegistrationResponse {
[Export ("lastRegistrationResponse")]
get;
}
[CompilerGenerated]
public virtual TokenResponse LastTokenResponse {
[Export ("lastTokenResponse")]
get;
}
[CompilerGenerated]
public virtual string RefreshToken {
[Export ("refreshToken")]
get;
}
[CompilerGenerated]
public virtual string Scope {
[Export ("scope")]
get;
}
[CompilerGenerated]
public virtual IAuthStateChangeDelegate StateChangeDelegate {
[Export ("stateChangeDelegate", ArgumentSemantic.Weak)]
get;
[Export ("setStateChangeDelegate:", ArgumentSemantic.Weak)]
set;
}
public static IAuthorizationFlowSession PresentAuthorizationRequest (AuthorizationRequest authorizationRequest, UIViewController presentingViewController, AuthStateAuthorizationCallback callback);
[CompilerGenerated]
[DesignatedInitializer]
[EditorBrowsable (EditorBrowsableState.Advanced)]
[Export ("initWithCoder:")]
public AuthState (NSCoder coder)
: base (NSObjectFlag.Empty);
[CompilerGenerated]
[EditorBrowsable (EditorBrowsableState.Advanced)]
protected AuthState (NSObjectFlag t)
: base (t);
[CompilerGenerated]
[EditorBrowsable (EditorBrowsableState.Advanced)]
protected internal AuthState (IntPtr handle)
: base (handle);
[Export ("initWithAuthorizationResponse:")]
[CompilerGenerated]
public AuthState (AuthorizationResponse authorizationResponse)
: base (NSObjectFlag.Empty);
[Export ("initWithAuthorizationResponse:tokenResponse:")]
[CompilerGenerated]
public AuthState (AuthorizationResponse authorizationResponse, TokenResponse tokenResponse)
: base (NSObjectFlag.Empty);
[Export ("initWithRegistrationResponse:")]
[CompilerGenerated]
public AuthState (RegistrationResponse registrationResponse)
: base (NSObjectFlag.Empty);
[Export ("initWithAuthorizationResponse:tokenResponse:registrationResponse:")]
[DesignatedInitializer]
[CompilerGenerated]
public AuthState (AuthorizationResponse authorizationResponse, TokenResponse tokenResponse, RegistrationResponse registrationResponse)
: base (NSObjectFlag.Empty);
[Export ("encodeWithCoder:")]
[CompilerGenerated]
[Preserve (Conditional = true)]
public virtual void EncodeTo (NSCoder encoder);
[Export ("performActionWithFreshTokens:")]
[CompilerGenerated]
public unsafe virtual void PerformWithFreshTokens ([BlockProxy (typeof(ObjCRuntime.Trampolines.NIDAuthStateAction))] AuthStateAction action);
[Export ("performActionWithFreshTokens:additionalRefreshParameters:")]
[CompilerGenerated]
public unsafe virtual void PerformWithFreshTokens ([BlockProxy (typeof(ObjCRuntime.Trampolines.NIDAuthStateAction))] AuthStateAction action, NSDictionary<NSString, NSString> additionalParameters);
[Export ("authStateByPresentingAuthorizationRequest:UICoordinator:callback:")]
[CompilerGenerated]
public unsafe static IAuthorizationFlowSession PresentAuthorizationRequest (AuthorizationRequest authorizationRequest, IAuthorizationUICoordinator UICoordinator, [BlockProxy (typeof(ObjCRuntime.Trampolines.NIDAuthStateAuthorizationCallback))] AuthStateAuthorizationCallback callback);
[Export ("setNeedsTokenRefresh")]
[CompilerGenerated]
public virtual void SetNeedsTokenRefresh ();
[Export ("tokenRefreshRequest")]
[CompilerGenerated]
public virtual TokenRequest TokenRefreshRequest ();
[Export ("tokenRefreshRequestWithAdditionalParameters:")]
[CompilerGenerated]
public virtual TokenRequest TokenRefreshRequest (NSDictionary<NSString, NSString> additionalParameters);
[Export ("updateWithAuthorizationResponse:error:")]
[CompilerGenerated]
public virtual void Update (AuthorizationResponse authorizationResponse, NSError error);
[Export ("updateWithTokenResponse:error:")]
[CompilerGenerated]
public virtual void Update (TokenResponse tokenResponse, NSError error);
[Export ("updateWithAuthorizationError:")]
[CompilerGenerated]
public virtual void Update (NSError authorizationError);
[Export ("updateWithRegistrationResponse:")]
[CompilerGenerated]
public virtual void UpdateWithRegistrationResponse (RegistrationResponse registrationResponse);
[CompilerGenerated]
protected override void Dispose (bool disposing);
}
}
在iOS 12.1
之前,更新一切正常
问题::安装ios 12.1更新后,仅当在发布模式下运行时(在连接到VS for Mac调试器时在开发模式下调试时有效),查询存储二进制文件的钥匙串中的现有钥匙NSData
对象的AuthState
表示挂起,最终应用程序终止,原因是响应时间超过10秒。
有人遇到任何类似的问题吗?如果有人能阐明这里发生的事情或为我指明正确的方向,那将是惊人的。
其他信息:
如何获取NSData
对象的AppAuth
二进制表示形式:
NSData authStateData = NSKeyedArchiver.ArchivedDataWithRootObject(authState);
我如何将此NSData
保存到钥匙串中:
var secAccess = new SecAccessControl(SecAccessible.WhenUnlockedThisDeviceOnly, SecAccessControlCreateFlags.UserPresence);
var secRecord = new SecRecord(SecKind.GenericPassword)
{
Account = "keystring",
Service = "ServiceNameString",
Label = "keystring",
ValueData = authStateData,
AccessControl = secAccess
};
var result = SecKeyChain.Add(secRecord);
如何查询keychain
中的现有数据:
var searchRecord = new SecRecord(SecKind.GenericPassword)
{
Service = ServiceName,
Label = key,
};
var match = SecKeyChain.QueryAsRecord(searchRecord, out SecStatusCode resultCode);
我检查过,设备日志中没有明显的错误。我错过的iOS 12.1中有没有一个更改对此有重大影响?
更新:我将代码重构为仅在密钥链中存储加密密钥密码,而不是整个AuthState对象,并将加密的序列化AuthState存储到本地文件中。仍然看到相同的问题,在设备上的调试模式下,一切正常,从钥匙串写入和读取都很好,当在同一设备上未连接调试器的情况下运行时,相同的构建,写得很好,当成功验证TouchID / FaceID后读取挂起Xamarin.iOS SDK中是否有一个错误,导致最新的iOS发生了一些变化?
答案 0 :(得分:0)
答案 1 :(得分:0)
我已经解决了我遇到的问题,因为在主线程上进行了保存到钥匙串的调用,这似乎是某种竞争状况在锁定应用程序。通常,此调用非常快速,并且过去锁定任何内容都不会出现问题,但是iOS 12.1更新中的某些内容对此进行了更改。无论如何,我只要显式运行代码即可将加密密码保存到后台线程的钥匙串中,即可解决问题:
Task.Run(() =>
{
var keychain = new KeyChain();
keychain.SetValueForKey("securedvalue", "securedvaluekey");
}).ConfigureAwait(false);