You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Angular通过浏览器URI启动UWP应用并传递对象实现自动登录

实现方案概述

核心基于UWP的*协议激活(Protocol Activation)*能力实现,整体流程为:UWP端提前注册自定义URI Scheme,Angular端构造带加密凭证的对应Scheme URI触发启动UWP,UWP端接收参数后解密校验,完成自动登录。


步骤1:UWP端注册自定义URI协议

  1. 打开UWP项目的Package.appxmanifest文件,切换到「声明」标签页
  2. 新增「协议」声明,设置名称为自定义值(比如myuwpapp),保存配置即可
  3. 重写App.xaml.cs的OnActivated方法,用于接收启动URI参数:
protected override void OnActivated(IActivatedEventArgs args)
{
    if (args.Kind == ActivationKind.Protocol)
    {
        ProtocolActivatedEventArgs protocolArgs = args as ProtocolActivatedEventArgs;
        Uri launchUri = protocolArgs.Uri;
        // 后续参数解析、解密逻辑在此处实现
    }
    base.OnActivated(args);
}

步骤2:Angular端实现凭证加密与URI构造

注意:禁止明文传递账号密码,统一使用AES对称加密,两端提前约定加密参数,生产环境密钥建议从后端动态获取,不要硬编码在前端代码中

  1. 安装加密依赖:
    npm install crypto-js @types/crypto-js
  2. 业务逻辑实现示例:
import * as CryptoJS from 'crypto-js';

// 启动UWP方法,传入用户账号密码
launchUWP(userId: string, password: string) {
    // 加密参数:密钥长度需符合AES要求(16/24/32位),IV固定为16位
    const aesKey = '约定的AES加密密钥';
    const aesIv = '约定的16位偏移量';

    // 构造凭证对象,增加时间戳防止重放攻击
    const credential = {
        userId,
        password,
        timestamp: new Date().getTime()
    };

    // AES加密
    const encryptedCred = CryptoJS.AES.encrypt(
        JSON.stringify(credential),
        CryptoJS.enc.Utf8.parse(aesKey),
        {
            iv: CryptoJS.enc.Utf8.parse(aesIv),
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        }
    ).toString();

    // URI编码避免特殊字符解析异常
    const encodedCred = encodeURIComponent(encryptedCred);
    // 构造启动URI
    const launchUri = `myuwpapp://autoLogin?cred=${encodedCred}`;

    // 触发启动UWP
    window.location.href = launchUri;
}

步骤3:UWP端实现参数解密与自动登录

UWP端需使用和Angular端完全一致的加密参数解密,示例代码如下:

  1. 首先安装JSON解析依赖:Newtonsoft.Json Nuget包
  2. 解密与登录逻辑实现:
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;

// 解密工具方法
private string AesDecrypt(string encryptedText, string key, string iv)
{
    byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
    using (Aes aes = Aes.Create())
    {
        aes.Key = Encoding.UTF8.GetBytes(key);
        aes.IV = Encoding.UTF8.GetBytes(iv);
        aes.Mode = CipherMode.CBC;
        aes.Padding = PaddingMode.PKCS7;

        ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
        using (var ms = new MemoryStream())
        using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
        {
            cs.Write(encryptedBytes, 0, encryptedBytes.Length);
            cs.FlushFinalBlock();
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }
}

// 凭证实体类,和Angular端结构对应
public class CredentialModel
{
    public string UserId { get; set; }
    public string Password { get; set; }
    public long Timestamp { get; set; }
}

// 完善OnActivated中的处理逻辑
protected override void OnActivated(IActivatedEventArgs args)
{
    if (args.Kind == ActivationKind.Protocol)
    {
        ProtocolActivatedEventArgs protocolArgs = args as ProtocolActivatedEventArgs;
        var queryParams = HttpUtility.ParseQueryString(protocolArgs.Uri.Query);
        string encryptedCred = queryParams.Get("cred");
        
        if (!string.IsNullOrEmpty(encryptedCred))
        {
            try
            {
                // 使用和前端一致的密钥解密
                string aesKey = "约定的AES加密密钥";
                string aesIv = "约定的16位偏移量";
                string decryptedStr = AesDecrypt(encryptedCred, aesKey, aesIv);
                var credential = JsonConvert.DeserializeObject<CredentialModel>(decryptedStr);

                // 校验凭证有效期,比如设置5分钟过期,防止重放攻击
                long currentTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                if (currentTimestamp - credential.Timestamp > 5 * 60 * 1000)
                {
                    // 凭证过期,跳转手动登录页
                    NavigateToLoginPage();
                    return;
                }

                // 校验账号密码有效性,验证通过则进入应用主页
                bool isLoginValid = ValidateUserCredential(credential.UserId, credential.Password);
                if (isLoginValid)
                {
                    NavigateToMainPage();
                }
                else
                {
                    NavigateToLoginPage();
                }
            }
            catch
            {
                // 解密失败/参数非法,跳转手动登录页
                NavigateToLoginPage();
            }
        }
        else
        {
            NavigateToLoginPage();
        }
    }
    base.OnActivated(args);
}

注意事项

  • 首次触发URI启动时,浏览器会弹出确认弹窗询问用户是否允许启动对应UWP应用,属于浏览器安全策略限制,无法通过代码绕过
  • 加密密钥不要硬编码在代码中:UWP端可以存到Windows凭据管理器,Angular端生产环境建议由后端接口签发短期有效密钥,降低泄露风险
  • 如果传递的参数较长,可以先压缩再加密,避免超出浏览器URI长度限制
  • 可额外增加签名校验:对加密后的凭证生成签名一并传递,UWP端先校验签名合法性再解密,防止参数被篡改

内容的提问来源于stack exchange,提问作者Shreyas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 12:06:05