使用您的Web开发技能,用Electron构建桌面应用程序

本文最初发布在Okta开发人员博客上 感谢您支持使SitePoint成为可能的合作伙伴。

Electron是一个框架,可使用JavaScript,HTML和CSS等Web技术构建跨平台的桌面应用程序。 它是为GitHub的Atom编辑器创建的,此后得到了广泛的采用。 电子为我每天使用的多个应用程序提供动力:Slack,Kitematic和Visual Studio Code等。

Electron 2.0于2018年5月上旬发布,并对项目进行了更改以遵守严格的语义版本控制。 这对开发人员来说是个好消息,因为这意味着修补程序版本将更加稳定,并且新功能将仅在主要版本中提供。 当开放源代码项目正确使用语义版本控制时,最终用户不会经常看到破坏性的更改,并且往往会提高工作效率。

Electron 3.0于2018年9月18日发布,包含主要版本的颠簸和一些新功能。 有关更多信息,请参见Electron博客

使用Web技术开发桌面应用程序是一个吸引人的概念。 我认为Gerard Sans的这则推文很钉钉:

你有网页开发技能吗? 大! 您具有使用Electron构建桌面应用程序所需的条件!

在本文中,我将向您展示如何使用TypeScript,AppAuth-JS和OpenID Connect(OIDC)创建Electron应用程序。 您将学习如何为用户添加身份验证和保护Electron应用程序。

什么是AppAuth?

AppAuth是一个旨在为本机应用程序创建客户端SDK的项目。 使用OIDC和OAuth 2.0,可以在您的应用中实现身份验证和授权。 它具有可用于iOS,macOS,Android和JavaScript环境的SDK。 AppAuth-JS是JavaScript客户端的SDK。 AppAuth还支持OAuth的PKCE扩展 ,以使公共客户端更加安全。

几乎每个应用程序都依赖于安全的身份管理系统。 对于正在构建Electron应用程序的大多数开发人员,在滚动自己的身份验证/授权或插入托管身份服务(如Okta)之间都需要做出决定。

使用Electron构建桌面应用

我将为您简化事情。 您将使用现有示例,而不是从头开始构建应用程序。 AppAuth-JS项目有两个示例,一个服务器端示例,其节点位于src / node_app / index.ts ,一个appauth-js-electron-sample 。 克隆电子示例开始。

git clone https://github.com/googlesamples/appauth-js-electron-sample.git okta-electron-example

在此项目中打开package.json并进行以下更改。


   "scripts": {
     "compile": "tsc",
     "watch": "tsc --watch",
     "start": "npm run compile && npx electron .",
     "dev": "npm run compile && npm run watch & npx electron ."
   },
   "files": [
     "built/**"
   "author": "rahulrav",
   "license": "MIT",
   "dependencies": {
     "@openid/appauth": "^1.1.1",
     "@types/react": "^16.3.17",
     "@types/react-dom": "^16.0.6",
     "material-design-lite": "^1.3.0"
   },
   "devDependencies": {
     "electron": "^3.0.0",
     "typescript": "^2.9.1"
   }
 }

这些更改不是必需的,但它们会使事情变得更容易。 “脚本”中的更改使得它可以在运行npm run devnpm start之前进行编译。 您还需要将electron依赖关系变为devDependency并将TypeScript升级到最新版本。

导航到克隆目录,使用npm安装依赖项,然后运行该应用程序。

cd okta-electron-example
npm i
npm run dev

它应该启动该应用程序并显示一个登录链接。

initial-load.png

如果您拥有Google帐户,请点击登录 ,然后登录 ,您将被重定向回您的应用程序。 您应该会看到您的头像和名称。

Google登录后

下图显示了如何使用OpenID Connect进行此授权流程。

OIDC流程

此时,您可以看到正在通过Google进行身份验证。 在下一节中,我将向您展示如何添加PKCE支持以使该应用程序更安全,以及如何使用Okta代替Google。

为什么要使用Okta进行身份验证?

您可能会问:当使用Google身份验证时,为什么我应该使用Okta? 原因很简单。 如果您想管理应用程序的用户(并且不可避免),Okta可以实现。 使用Google,拥有Google帐户的任何人都可以登录,但是您无法撤消访问权限或更新用户的权限,因为您无法通过Google管理用户。 Okta使您可以管理用户,以及修改其属性和权限。 更好的是,您仍然可以使用Okta将Google用作社交登录机制!

在桌面应用程序中使用Okta与OIDC进行身份验证

Okta的目标是使身份管理比以往更加轻松,安全和可伸缩。 Okta是一项云服务,允许开发人员创建,编辑和安全地存储用户帐户和用户帐户数据,并将它们与一个或多个应用程序连接。 我们的API使您能够:

你准备好了吗? 立即注册一个永久免费的开发者帐户 ! 完成后,请完成以下步骤以创建本机OIDC应用程序。

  1. 登录到您在developer.okta.com上的开发者帐户。
  2. 导航到“ 应用程序” ,然后单击“ 添加应用程序”
  3. 选择本 ,然后单击下一步
  4. 为应用程序命名(例如My Electron App ),然后添加http://localhost:8000作为登录重定向URI。
  5. 对于允许的授予类型,除了授权代码外,选择刷新令牌
  6. 单击完成

现在,您可以使用应用程序设置将使用Google更改为Okta。 修改flow.ts以使用Okta应用程序的设置。

const openIdConnectUrl = 'https://{yourOktaDomain}/oauth2/default';
const clientId = '{yourClientId}';
const redirectUri = 'http://localhost:8000';

您还需要更新app.ts以使用应用程序的/userinfo端点。

let request =
    new Request('https://{yourOktaDomain}/oauth2/default/v1/userinfo', {
      headers: new Headers({'Authorization': `Bearer ${accessToken}`}),
      method: 'GET',
      cache: 'no-cache'
    });

如果您重新启动应用程序并尝试登录,它将失败,因为您没有使用PKCE。 在启动的浏览器的地址栏中,您会看到类似以下的错误。

error=invalid_request&error_description=PKCE+code+challenge+is+required+when+the+token+endpoint+authentication+method+is+%27NONE%27.

将PKCE支持添加到您的桌面应用程序

PKCE(发音为“ pixy”)是OAuth 2.0的安全扩展,适用于移动(和桌面)客户端上的公共客户端。 它旨在防止在同一设备上运行的恶意应用程序拦截授权代码。

    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
    | End Device (e.g., Smartphone)  |
    |                                |
    | +-------------+   +----------+ | (6) Access Token  +----------+
    | |Legitimate   |   | Malicious|<--------------------|          |
    | |OAuth 2.0 App|   | App      |-------------------->|          |
    | +-------------+   +----------+ | (5) Authorization |          |
    |        |    ^          ^       |        Grant      |          |
    |        |     \         |       |                   |          |
    |        |      \   (4)  |       |                   |          |
    |    (1) |       \  Authz|       |                   |          |
    |   Authz|        \ Code |       |                   |  Authz   |
    | Request|         \     |       |                   |  Server  |
    |        |          \    |       |                   |          |
    |        |           \   |       |                   |          |
    |        v            \  |       |                   |          |
    | +----------------------------+ |                   |          |
    | |                            | | (3) Authz Code    |          |
    | |     Operating System/      |<--------------------|          |
    | |         Browser            |-------------------->|          |
    | |                            | | (2) Authz Request |          |
    | +----------------------------+ |                   +----------+
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+

PKCE工作组提供了一个很好的解释,我在下面进行了介绍。 您可以在官方RFC中阅读更多内容。

“为减轻这种攻击,PKCE使用了动态创建的密码随机密钥,称为“代码验证器”。 为每个授权请求创建一个唯一的代码验证器,并将其转换后的值(称为“代码挑战”)发送到授权服务器以获取授权代码。 然后,将获得的授权代码与“代码验证者”一起发送到令牌端点,服务器将其与先前接收的请求代码进行比较,以便它可以执行客户端对“代码验证者”的拥有证明。 这是缓解措施,因为攻击者不知道此一次性密钥,因为它是通过TLS发送的并且无法被截获。”

下图显示了PKCE如何与您的应用程序和Okta一起使用。

PKCE的验证码流

现在,您将PKCE添加到您的Electron应用程序中! 在flow.ts ,为PKCE添加一个challengePair变量作为AuthFlow类的成员变量。

private challengePair: { verifier: string, challenge: string };

在构造函数的末尾添加一行以初始化此变量。

this.challengePair = AuthService.getPKCEChallengePair();

创建pkce.ts来定义AuthService类。

const crypto = require('crypto');

export class AuthService {

  static getPKCEChallengePair() {
    let verifier = AuthService.base64URLEncode(crypto.randomBytes(32));
    let challenge = AuthService.base64URLEncode(AuthService.sha256(verifier));
    return {verifier, challenge};
  }

  static base64URLEncode(str: Buffer) {
    return str.toString('base64')
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=/g, '');
  }

  static sha256(buffer: string) : Buffer {
    return crypto.createHash('sha256').update(buffer).digest();
  }
}

将此类的导入添加到flow.ts

import { AuthService } from './pkce';

makeAuthorizationRequest()方法中,在if (username) {}逻辑之后,将代码质询和方法添加到extras映射中。

// PKCE
extras['code_challenge'] = this.challengePair.challenge;
extras['code_challenge_method'] = 'S256';

makeRequestTokenRequest() ,添加一个tokenRequestExtras变量并将其发送到请求中。

let tokenRequestExtras = { code_verifier: this.challengePair.verifier };

// use the code to make the token request.
let request = new TokenRequest(
  clientId,
  redirectUri,
  GRANT_TYPE_AUTHORIZATION_CODE,
  code,
  undefined,
  tokenRequestExtras
);

进行这些更改之后,您应该可以登录。但是,当您单击USER INFO时 ,您将看不到用户的名称或头像。 通过查看 > 切换开发者工具打开Chrome开发者工具以了解原因。

Electron的开发人员工具

要解决此问题,请在flow.ts中将scope变量flow.ts为包括profile 。 在使用时,请添加offline_access以便您的应用无需互联网即可正常运行。

const scope = 'openid profile offline_access';

刷新您的应用程序(在Mac上为Command + R,在Windows / Linux上为Ctrl + R),现在单击USER INFO时应会看到名称。

来自用户信息端点的名称

注意:我利用这些PKCE代码示例来完成所有这些工作。

在Okta中添加头像

您可能会注意到,用户信息端点未返回化身。 app.ts的代码根据picture属性设置头像。

private updateUi() {
  this.handleSignIn.textContent = SIGN_OUT;
  this.fetchUserInfo.style.display = '';
  if (this.userInfo) {
    this.userProfileImage.src = `${this.userInfo.picture}?sz=96`;
    this.userName.textContent = this.userInfo.name;
    this.showSnackBar(
        {message: `Welcome ${this.userInfo.name}`, timeout: 4000});
    this.userCard.style.display = '';
  }
}

您可以在上面的代码中删除?sz=96 ,因为此示例未使用它。

要向您的用户添加picture属性,请登录Okta仪表板,然后导航至Users > Profile Editor 。 单击第一个“用户”并添加picture属性。 点击保存

添加图片属性

浏览回到配置文件编辑器,然后为您的Electron App单击映射 。 创建从user.picturepicture的映射,然后选择将映射应用于用户创建和更新。 单击“ 保存映射立即应用更新”

添加图片映射

现在转到“ 用户” >“ 人员” ,选择一个用户,导航至“ 个人资料”标签,然后点击“ 编辑” 。 在底部添加picture的值。 例如,您可以使用我们的Okta Developer徽标的URL。

https://www.okta.com/sites/all/themes/Okta/images/logos/developer/Dev_Logo-02_Large.png

现在,如果您单击用户信息链接,则应该看到与您的用户关联的头像。

用户信息图片

提示:如果要在生产中使用此图像,建议您为图片使用较小的图像(例如150×150尺寸)。 您还可以图像进行base64编码 ,并将其值用于图片。

下面的屏幕截图显示了此应用,并为我的帐户添加了一些额外的修饰和base64图像值。

抛光哑光

打包您的桌面应用以进行生产

要将此应用打包以进行生产发行,可以使用electronic-builder 。 使用npm安装电子生成器。

npm i -D electron-builder@20.28.4

在您的package.json添加一个build部分:

"build": {
  "appId": "com.okta.developer.electron",
  "productName": "Electron Awesomeness",
  "mac": {
    "category": "public.app-category.developer-tools"
  }
}

然后添加packdistpostinstall脚本。

"scripts": {
  ...
  "pack": "npm run compile && electron-builder --dir",
  "dist": "npm run compile && electron-builder",
  "postinstall": "electron-builder install-app-deps"
}

要将您的应用打包以进行生产,请使用以下命令:

  • npm run pack会生成package目录,而不会真正打包它。 这对于测试目的很有用。
  • npm run dist将以可分发格式打包(例如dmg,Windows安装程序,deb软件包)。

注意:如果应用程序在打包后仍未启动,则可能是因为您未配置代码签名 。 要在构建macOS时禁用代码签名,请运行export CSC_IDENTITY_AUTO_DISCOVERY=false 。 如果您拥有Apple开发者帐户,请打开Xcode,转到“首选项” >“ 帐户”并确保您已登录,并下载了开发证书。

电子示例应用程序源代码

您可以在此处找到本文的源代码。

我做了一些小的调整(例如,优化导入,将双引号更改为单引号),但是没有什么大的调整。 要查看该项目与原始项目之间的区别, 请单击此处

了解有关Electron,AppAuth和OIDC的更多信息

你有它! 继续并使用您的网络技能来创建出色的桌面应用程序!

要了解有关Electron,AppAuth,React和OIDC的更多信息,请查看以下资源:

有问题吗? 请在下面发表评论, 在Twitter上对我进行ping操作 ,或在我们的开发者论坛上提问。

喜欢在这里学到的东西吗? 关注@oktadev在Facebook上像我们一样, 在LinkedIn 关注我们,或在YouTube上观看我们的视频

变更日志:

From: https://www.sitepoint.com/use-your-web-dev-skills-to-build-a-desktop-app-with-electron/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值