使用 Java 构建 Microsoft Teams 选项卡应用,第 2 部分:创建带 SSO 的频道或组选项卡





5.00/5 (1投票)
在本文中,我们将探讨如何创建带有 SSO 的频道或组选项卡。
这是三部分系列文章的第二篇,演示了如何使用 Microsoft Teams 示例库来启动基于 Java 的 Teams 应用程序的构建。在本文中,我将展示如何创建一个使用单点登录 (SSO) 保护的频道(或组)选项卡。但是,此应用程序的大部分设置和安装操作与个人选项卡应用程序相同,因此您应该在继续之前查看 本系列的第一个文章。
Microsoft 提供了很棒的 Teams 应用概述。他们讨论了个人选项卡应用和频道选项卡应用之间的区别,即频道选项卡应用向一组 Teams 用户而不是单个用户提供内容。因此,下面详细介绍的应用程序是我上一篇文章中应用程序的扩展。
Microsoft 还指出,频道选项卡应用程序需要一个配置页面来控制组用户可以在应用中执行的操作。他们提供了一篇关于 创建配置页面 的优秀文章。
我将在此构建的应用程序提供了一个简单的配置页面,作为与 Teams 交互以控制组设置的示例。您需要 Java 经验才能继续学习,但我会解释如何使用 Teams。
在 Teams 应用中实现 SSO
要在 Teams 应用中实现单点登录 (SSO),我们首先在托管 Teams 的同一租户中将应用程序注册到 Azure Active Directory。 Teams 选项卡 SSO 身份验证 README 页面 涵盖了此注册过程。有关更多详细信息,请参阅第一个文章的“在 Teams 应用中实现 SSO”部分。
使用 Spring Initializr 创建应用程序
完成应用程序注册后,您就可以开始构建它了。 Spring 提供了 Spring Boot Initializr 工具,该工具可创建一个 Maven 包,我们可以将其导入 Eclipse。
通过在浏览器中打开并访问 https://start.spring.io/ 来运行该工具。然后,填写项目详细信息和元数据。包括以下依赖项:
- Spring Web
- Thymeleaf
- Azure Active Directory
- OAuth2 客户端
- Spring Boot DevTools
单击 **生成** 以创建 ZIP 文件,该文件提供完整的 Maven 基础结构和初始运行时类。将资源解压缩到您的项目目录中,并将其作为现有 Maven 项目导入 Eclipse。
在 Eclipse 中,选择 **文件** > **导入** 以显示此对话框
选择 **现有 Maven 项目** 并单击 **下一步** 以显示此对话框
选择您解压缩从 Spring Initializr 下载的文件的目录,选中您的项目旁边的复选框,然后单击 **完成**。
导入项目后,通过将此依赖项添加到 pom.xml 文件来启用 Bootstrap CSS:
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.0.0-2</version>
</dependency>
我们需要对网页进行其他更改,但我稍后会介绍。
此应用程序的完整源代码可在 GitHub 上获取。
准备核心 Java 代码
与第一篇文章一样,我从示例应用程序中删除了尽可能多的代码,以突出显示我们实现 SSO 所需的代码。以下 Java 类派生自相应的 C# 文件:
Java 类文件 | C# 类源文件 |
AppConfiguration.java | Startup.cs |
ChannelTabSsoApplication.java | Program.cs |
HomeController.java | HomeController.cs |
AuthController.java | AuthController.cs |
SSOAuthHelper.java | SSOAuthHelper.cs |
当 Spring Boot 启动我们的应用程序时,它会在 ChannelTabSsoApplication
类中运行 main
。此类使用 Spring Boot 启动器提供的默认类实现。
AppConfiguration
类配置 Spring Boot 引擎。我们必须记住,Teams 在 iframe 中启动我们的应用程序,而 Azure App Service 的 Web 应用程序服务器强制执行跨框架脚本安全性。因此,我们需要添加一些代码以允许我们的应用程序运行。
package com.contentlab.teams.java.channeltabsso;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@Order(value = 0)
public class AppConfiguration extends WebSecurityConfigurerAdapter
{
// @Value("${spring.security.oauth2.resourceserver.jwt.key-value}")
// RSAPublicKey key;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.contentSecurityPolicy(
"frame-ancestors 'self' https://*.microsoftonline.com https://*.microsoft.com;"
);
}
}
Mozilla 指出 content-security-policy
标头使 X-FRAME-OPTIONS
标头过时,因此我在本应用程序中实现了较新的方法。
HomeController 为 index
页面、configure
页面以及 SSO 流程所需的 /Auth/Start
和 Auth/End
URL 提供映射和处理程序。我使用 @Controller 注释此类,因为响应包含网页。
AuthController 类为 GetUserAccessToken
URL 提供映射和处理程序。我使用 @RestController
注释此控制器,它向调用者提供文本响应。 auth.js 中的代码在 SSO 序列将用户 ID 令牌交换为用户访问令牌时获取该 URL。
SsoAuthHelper
类提供 GetAccessTokenOnBehalfUser
,由 AuthController.GetUserAccessToken
调用。 GetAccessTokenOnBehalfUser
方法处理代表已认证用户访问 Teams 资源。此应用程序使用我们在 上一篇文章 中详细介绍的相同过程。
准备 Web 资源
我在三个 HTML 文件中实现了客户端代码:
Java 应用程序 HTML 文件 | C# HTML 源文件 |
index.html | Home/index.cshtml |
/Auth/Start.html | Auth/Start.cshtml |
/Auth/End.html | Auth/End.cshtml |
index.html 网页有一个指向 auth.js 的链接。 Auth.js 包含一个 ready
事件处理程序,该处理程序在文件加载后尽快触发。处理程序的代码如下所示:
$(document).ready(function () {
microsoftTeams.initialize();
getClientSideToken()
.then((clientSideToken) => {
console.log("clientSideToken: " + clientSideToken);
return getServerSideToken(clientSideToken);
})
.catch((error) => {
console.log(error);
if (error === "invalid_grant") {
// Display in-line button so user can consent
$("#divError").text("Error while exchanging for Server token - invalid_grant - User or admin consent is required.");
$("#divError").show();
$("#consent").show();
}
});
});
Microsoft Teams API 已初始化,并调用了 auth.js 中实现的 getClientSideToken
来对用户进行身份验证。如果成功,则调用 getServerSideToken
来将客户端令牌交换为 Teams 令牌。
对于此应用程序,页面显示信息以验证用户是否已通过身份验证以及应用程序是否可以访问 Teams 资源。如果身份验证失败(例如,由于当前访问令牌过期),它将提供一个按钮,使用户能够触发身份验证过程。
该应用程序还包含支持图像文件:IconRed.png、IconGray.png 和 TeamsIcon.png。
添加支持的 JavaScript
与上一篇文章一样,我从 Microsoft 示例应用程序中完整地提取了一个 JavaScript 文件 auth.js。我在 上一篇文章 中详细介绍了此文件中用于启动和处理 OAuth 2 流程的函数。
部署应用程序
现在我们已经有了应用程序的所有部分,我们需要构建并部署它。Maven 提供了创建 Azure App Service 计划的工具,我们可以在其中开发和部署应用程序。要使用这些工具,请首先打开命令行窗口。然后,将目录 (cd
) 更改为包含 pom.xml 文件的项目目录。然后,执行以下命令:
az login --tenant << 你的租户 ID >>
mvn com.microsoft.azure:azure-webapp-maven-plugin:2.2.0:config
mvn package azure-webapp:deploy
其中 << 你的租户 ID >>
是 Azure Active Directory 分配给你的租户的 ID。当你打开 Azure Active Directory 服务的门户页面时,你可以在“默认目录”的“概述”页面上找到它。
这些函数(我在 上一篇文章 中已详细介绍)的作用如下。首先,az login
命令登录到 Azure,以便 Maven 可以创建资源。第一个 mvn
命令捕获创建 Azure App Service 计划所需的信息,第二个 mvn
命令将应用程序部署到该计划。
修复应用注册和 application.properties 文件
现在你已经部署了应用程序,你需要更新 Azure Active Directory 应用注册门户 中的信息。此过程分为四个部分:捕获应用服务 URL、更新应用注册信息、修改 application.properties 文件以及重新部署应用程序。
你可以从部署过程的文本响应中捕获新的 Azure 应用服务 URL。
[INFO] Successfully deployed the artifact to https://channeltabsso-1634231313958.azurewebsites.net
在上一篇文章中,我曾指出你需要更新 **重定向 URL** 和 **应用程序 ID URL** 中的主机名,以匹配 Azure 应用服务 URL 中的主机名。如果你需要帮助,可以在 该文章 中找到屏幕截图进行指导。
application.properties 文件的格式如下。你需要将 << 你的租户 ID >>
和其他占位符替换为你注册应用程序时使用的 ID。
# Specifies your Active Directory ID:
azure.activedirectory.tenant-id=<< Your Tenant ID >>
# Specifies your App Registration's Application ID:
azure.activedirectory.client-id=<< application ID >>
# Specifies your App Registration's secret key:
azure.activedirectory.client-secret=<< your app secret >>
azure.auth.url=/oauth2/v2.0/token
azure.instance=https://login.microsoftonline.com
azure.api=api://<< Registered hostname >>/<< your client ID >>
azure.scopes=https://graph.microsoft.com/User.Read
azure.valid.issuers="https://login.microsoftonline.com/<< Your tenant ID >>/v2.0,https://sts.windows.net/<< your tenant ID >>/"
spring.thymeleaf.prefix=classpath:/templates/
完成替换这些 ID 后,你可以重新部署应用程序。
在 Teams 中测试
此应用程序的清单文件如下。使此应用程序成为组应用程序而不是个人应用程序的关键元素是 configurableTabs
对象中的 scopes
对象,其值为 team
和 groupchat
。
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.11/MicrosoftTeams.schema.json",
"manifestVersion": "1.11",
"version": "1.0.0",
"id": "<< any random GUID >>",
"packageName": "com.contentlab.teams.java.channeltabsso",
"developer": {
"name": "Microsoft",
"websiteUrl": "https://www.microsoft.com",
"privacyUrl": "https://www.microsoft.com/privacy",
"termsOfUseUrl": "https://www.microsoft.com/termsofuse"
},
"name": {
"short": "Java Group Tab Teams Auth SSO",
"full": "Java Group Tab Teams Auth SSO"
},
"description": {
"short": "Java Group Tab Teams Auth SSO",
"full": "Java Group Tab Teams Auth SSO"
},
"icons": {
"color": "color.png",
"outline": "outline.png"
},
"accentColor": "#0000EE",
"configurableTabs": [
{
"configurationUrl": "https://channeltabsso-1634231313958.azurewebsites.net/Configure",
"canUpdateConfiguration": true,
"scopes": ["team", "groupchat"]
}
],
"permissions": ["identity","messageTeamMembers"],
"validDomains": [
"channeltabsso-1634231313958.azurewebsites.net",
"*.onmicrosoft.com",
"*.azurewebsites.net"
],
"webApplicationInfo": {
"id": "a2f5e45f-c3a7-4ba6-8e14-543e45e1be95",
"resource": "api://channeltabsso-1634231313958.azurewebsites.net/<< your client id >>"
}
}
按照我在 第一篇文章 中描述的方式构建 manifest.zip 文件。然后将文件上传到 Teams。当你将应用程序添加到 Teams 时,你会看到这个:
选择一个频道,然后单击 **设置选项卡**。
你可能需要等待 Azure App Service 启动。查看左下角的状态消息。
当应用程序加载时,你将看到 **配置** 选项卡。
此示例应用程序仅显示身份验证数据。你可以单击红色和灰色按钮来更改配置。选择颜色后,应用程序将启用 **保存** 按钮。由于这只是一个演示应用程序,按钮事件处理程序只是占位符,用于显示如何启用 **保存** 按钮并将配置已保存的通知发送到 Teams。
<script>
microsoftTeams.initialize();
let saveGray = () => {
microsoftTeams.settings.registerOnSaveHandler((saveEvent) => {
microsoftTeams.settings.setSettings({
websiteUrl: window.location.origin ,
contentUrl: window.location.origin + "",
entityId: "Java Channel Configure",
suggestedDisplayName: "Java Channel Configure - Grey Settings"
});
saveEvent.notifySuccess();
});
}
let saveRed = () => {
microsoftTeams.settings.registerOnSaveHandler((saveEvent) => {
microsoftTeams.settings.setSettings({
websiteUrl: window.location.origin ,
contentUrl: window.location.origin + "",
entityId: "Java Channel Configure",
suggestedDisplayName: "Java Channel Configure - Red Settings"
});
saveEvent.notifySuccess();
});
}
let icon = document.getElementById("icon");
const colorClickGray = () => {
microsoftTeams.settings.setValidityState(true);
saveGray()
}
const colorClickRed = () => {
microsoftTeams.settings.setValidityState(true);
saveRed();
}
</script>
你的应用程序需要呈现与你的应用程序支持的交互类型相关的选项。这可能包括选择转换类别、设置对话框标题,或者如果实现临时审批工作流,则命名审批者并指定审批顺序。
单击 **保存** 按钮后,将显示应用程序的主页面。你的应用程序在此处显示的内容将取决于你的应用程序和捕获的配置数据。
后续步骤
现在你已经拥有了一个工作中的频道选项卡应用程序的框架。我已经涵盖了将应用程序与 Teams 集成并使用 SSO 进行保护的所有详细信息。你需要添加配置详细信息和组应用程序,但这对于构建你已经知道的基于 Web 的单页应用程序来说是标准做法。
正如你所经历的,将 Teams 应用程序从 C# 转换为 Java 所需的工作量非常小。我只在 SsoAuthHelper
中更改了一个函数。 SSO 所需的其余 HTML 和 JavaScript 直接可用。你的 Java 技能是相关的,你可以继续使用你熟悉的工具来创建 Teams 应用。
本文还提供了一个转换 Microsoft C# 示例的过程。因此,你可以浏览库并找到其他示例,为你提供一个初始框架。
继续本系列的最后一篇文章,探索 创建对话式选项卡应用。