• Windows Hello 浅尝(2)


    接着探索

    上一篇讲了一个微软官方的Demo,这个Demo基本上已经把我们要做的事情做完了。

    那么基于这个Demo,我说下我的思路。

    1.首先是要在界面程序中枚举出蓝牙设备

    2.为使用蓝牙设备的相关信息创建解锁用的Windows Hello设备

    3.当task收到解锁事件的时候再次枚举蓝牙设备,然后判断每个枚举到的蓝牙设备有没有对应Windows Hello设备

    4. 有就使用使用这个Windows Hello设备解锁电脑

    那这样我先使用我的小米手环的信息创建对应的解锁设备,当我的手环在附近的时候Task就能枚举到它从而解锁,当手环不在附近的时候Task自然就枚举不到它,于是就不能使用Windows Hello解锁。

    开始实践

    关于枚举蓝牙设备,我又在微软的官方例子中找到了Demo

    Demo地址:https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing

    这个Demo就展示了使用DeviceWatch去枚举设备

    DeviceWatcher m_deviceWatcher;
    string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" };
    m_deviceWatcher = DeviceInformation.CreateWatcher("(System.Devices.Aep.ProtocolId:="{bb7bb05e-5972-42b5-94fc-76eaa7084d49}")",
    //m_deviceWatcher = DeviceInformation.CreateWatcher("(System.Devices.Aep.ProtocolId:="{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}")",
                                                      requestedProperties,
                                                      DeviceInformationKind.AssociationEndpoint);
    
    m_deviceWatcher.Added += DeviceWatcher_Added;
    m_deviceWatcher.Updated += DeviceWatcher_Updated;
    m_deviceWatcher.Removed += DeviceWatcher_Removed;
    m_deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted;
    m_deviceWatcher.Stopped += DeviceWatcher_Stopped;
    m_deviceWatcher.Start();

     这个代码应该是一目了然的, 其中的关键就在于CreateWatcher时候使用的参数 {bb7bb05e-5972-42b5-94fc-76eaa7084d49} 能枚举到小米手环但是枚举不到手机, {e0cbf06c-cd8b-4647-bb8a-263b43f0f974} 则相反能枚举到手机但是枚举不到小米手环。

    这个类还能枚举到其他很多的设备,就靠CreateWatcher的参数具体可以看官方的Demo。

    下面是接口的定义,其中 DeviceInformation 和 DeviceInformationUpdate 就包含了设备的信息

    private void DeviceWatcher_Added(DeviceWatcher Sender, DeviceInformation DeviceInfo)
    {
    
    }
    
    private void DeviceWatcher_Updated(DeviceWatcher Sender, DeviceInformationUpdate DeviceInfoUpdate)
    {
    
    }
    
    private void DeviceWatcher_Removed(DeviceWatcher Sender, DeviceInformationUpdate DeviceInfoUpdate)
    {
    
    }
    
    private void DeviceWatcher_EnumerationCompleted(DeviceWatcher Sender, object e)
    {
    
    }
    
    private void DeviceWatcher_Stopped(DeviceWatcher Sender, object e)
    {
    
    }

     基本属性都有对应的变量,而我在CreateWatcher的时候附加的属性  string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" }; 会以键值对的形式保存在 DeviceInformation 和 DeviceInformationUpdate 的 Properties中

     我在界面程序中使用这套接口枚举到了我的手环,基本信息是这样的

    DeviceID: BluetoothLE#BluetoothLExx:xx:xx:xx:xx:xx-xx:xx:xx:xx:xx:xx

    Name: MI Band 2

     一开始我是想直接使用 BluetoothLE#BluetoothLExx:xx:xx:xx:xx:xx-xx:xx:xx:xx:xx:xx 这个ID去创建解锁设备的,但是发现都失败,实验下来可能是只能使用GUID去创建解锁设备。于是我就需要把 BluetoothLE#BluetoothLExx:xx:xx:xx:xx:xx-xx:xx:xx:xx:xx:xx 也存储起来,存储的思路

    其实例子中也给出了,就是存在解锁设备的  DeviceConfigurationData  中,因为 我还要在 DeviceConfigurationData 中存储解锁用的两个密码,所以我干脆就将在 DeviceConfigurationData  中存储JSON格式的数据,专门写了个序列化很反序列化的类。

    public class JsonData
    {
            
        public string Sign { get; set; }
           
        public string DeviceID { get; set; }
            
        public string DeviceKey { get; set; }
          
        public string AuthKey { get; set; }
    
        public bool CanUnLock { get; set; }
    }
    
    public class CMyHelloWinJson
    {
    
        public static JsonData ParesToData(string js)
        {
            JsonData rv = null;
            try
            {
                JsonObject schoolObject = JsonObject.Parse(js);
                if (schoolObject != null)
                {
                    rv = new JsonData();
                    rv.Sign = schoolObject.GetNamedString("Sign");
                    rv.DeviceID = schoolObject.GetNamedString("DeviceID");
                    rv.DeviceKey = schoolObject.GetNamedString("DeviceKey");
                    rv.AuthKey = schoolObject.GetNamedString("AuthKey");
                    rv.CanUnLock = schoolObject.GetNamedBoolean("CanUnLock");
                }
            }catch(Exception e)
            {
                return rv;
            }
     
            return rv;
        }
    
        public static string ParesToJson(JsonData Dat)
        {
            JsonObject schoolObject = new JsonObject();
            schoolObject.SetNamedValue("Sign", JsonValue.CreateStringValue(Dat.Sign));
            schoolObject.SetNamedValue("DeviceID", JsonValue.CreateStringValue(Dat.DeviceID));
            schoolObject.SetNamedValue("DeviceKey", JsonValue.CreateStringValue(Dat.DeviceKey));
            schoolObject.SetNamedValue("AuthKey", JsonValue.CreateStringValue(Dat.AuthKey));
            schoolObject.SetNamedValue("CanUnLock", JsonValue.CreateBooleanValue(Dat.CanUnLock));
            return schoolObject.ToString();
        }
    }

     所以在界面中创建解锁设备的代码就变成了这样

    string modelnumber = "MyHelloWin";
    
    // 随机数转 string 可能会丢失信息的
    byte[] deviceKeyArray = new byte[32];
    byte[] authKeyArray = new byte[32];
    
    IBuffer deviceKey = CryptographicBuffer.CreateFromByteArray(deviceKeyArray);
    IBuffer authKey = CryptographicBuffer.CreateFromByteArray(authKeyArray);
    
    JsonData Dat = new JsonData();
    Dat.Sign = "MyHellowin";
    
    Dat.DeviceKey = System.Text.Encoding.UTF8.GetString(deviceKeyArray);
    
    Dat.AuthKey = System.Text.Encoding.UTF8.GetString(authKeyArray);
    
    Dat.DeviceID = DeviceID;
    
    Dat.CanUnLock = false;
    
    string js = CMyHelloWinJson.ParesToJson(Dat);
    byte[] signArry = System.Text.Encoding.UTF8.GetBytes(js);
    IBuffer deviceConfigData = CryptographicBuffer.CreateFromByteArray(signArry);
    String deviceGUId = System.Guid.NewGuid().ToString();
    int state = await WinHello.RegisterDeviceAsync(deviceGUId, bleDeviceDisplay.DeviceName, modelnumber, deviceConfigData, deviceKey, authKey);
    
    
    // 注册
    SecondaryAuthenticationFactorDeviceCapabilities Capabilities = SecondaryAuthenticationFactorDeviceCapabilities.SecureStorage;
    SecondaryAuthenticationFactorRegistrationResult RegistrationResult = await SecondaryAuthenticationFactorRegistration.RequestStartRegisteringDeviceAsync(DervicesID,
            Capabilities,
            FriendlyName,
            ModelNumber,
            deviceKey,
            authKey);
    if (RegistrationResult.Status == SecondaryAuthenticationFactorRegistrationStatus.Started) {
        await RegistrationResult.Registration.FinishRegisteringDeviceAsync(DerviceContext);
    }
    
    return (int)RegistrationResult.Status;

     界面写好了,那么解锁的时候思路大致就是这样的

    先是枚举出所有的蓝牙设备,使用和上面相同的方法。

    private void DeviceWatcher_Added(DeviceWatcher Sender, DeviceInformation DeviceInfo)
    {

      IReadOnlyList<SecondaryAuthenticationFactorInfo> deviceList = await SecondaryAuthenticationFactorRegistration.FindAllRegisteredDeviceInfoAsync(SecondaryAuthenticationFactorDeviceFindScope.AllUsers);
      for (int i = 0; i < deviceList.Count; i++)
      {
          SecondaryAuthenticationFactorInfo deviceInfo = deviceList.ElementAt(i);
    
          byte[] combinedDataArray;
          CryptographicBuffer.CopyToByteArray(deviceInfo.DeviceConfigurationData, out combinedDataArray);
          string JS = System.Text.Encoding.UTF8.GetString(combinedDataArray);
          JsonData Dat = CMyHelloWinJson.ParesToData(JS);
    
          if (Dat == null)
          {
              continue;
          }
    
          if (String.Equals(Dat.DeviceID, DeviceInfo.DeviceID)) { // 使用这个设备进行解锁  } 
      }
    }

    具体解锁的方法,上面一篇文章中有相应的介绍。或者你直接看我写的Demo: http://git.oschina.net/alwaysking/MyHelloWin

    然而,当我天真的这样就搞定的时候,来了个晴天霹雳,因为在Task中使用DeviceWatcher枚举设备的时候他的回调函数根本不会被触发。注意我的蓝牙设备是配对的设备。

    解决方法也是有的,我们下一篇再讲

  • 相关阅读:
    struts2解决动态多文件上传的问题(上传文件与数据库字段一一对应)(转)
    Android应用如何开机自启动、自启动失败原因
    android操作ini工具类
    C++#define的用法(含特殊)
    c指针
    WP7备注(34)(UpdateSourceTrigger|ValidatesOnExceptions|NotifyOnValidationError)
    WP7备注(30)(数据绑定基本)
    WP7备注(38)(VisualStateManager)
    WP7备注(39)(ResourceDictionary)
    WP7备注(35)(Vector Graphics|Raster Graphics)
  • 原文地址:https://www.cnblogs.com/alwaysking/p/7258859.html
Copyright © 2020-2023  润新知