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

ASP.NET Core站点实现Teams标签页与浏览器Azure AD双认证问询

实现ASP.NET Core站点在浏览器与Microsoft Teams标签页的双端兼容认证

核心思路

要同时支持浏览器端Azure AD OIDC认证和Teams标签页SSO认证,核心是区分请求来源,为两种场景分别配置认证逻辑:

  • 普通浏览器:沿用原有Azure AD OIDC流程完成登录
  • Teams标签页:接收前端通过microsoftTeams.authentication.getAuthToken()获取的JWT令牌,后端验证令牌有效性

1. 后端认证配置(Program.cs)

保留原有OIDC认证的同时,添加JWT Bearer认证以支持Teams令牌验证,通过授权策略允许两种认证方式共存:

var builder = WebApplication.CreateBuilder(args);

// 配置双认证方案:Cookie+OIDC(浏览器)、JWT Bearer(Teams)
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
    // 绑定appsettings.json中的AzureAd配置
    builder.Configuration.Bind("AzureAd", options);
    options.ResponseType = "code";
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("email");
})
.AddJwtBearer("TeamsBearer", options =>
{
    options.Authority = $"{builder.Configuration["AzureAd:Instance"]}{builder.Configuration["AzureAd:TenantId"]}/v2.0";
    options.Audience = builder.Configuration["AzureAd:ClientId"];
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidIssuer = $"https://sts.windows.net/{builder.Configuration["AzureAd:TenantId"]}/",
        ValidateLifetime = true,
        ClockSkew = TimeSpan.FromMinutes(5)
    };
});

// 配置默认授权策略,允许两种认证方式
builder.Services.AddAuthorization(options =>
{
    options.DefaultPolicy = new AuthorizationPolicyBuilder(
        CookieAuthenticationDefaults.AuthenticationScheme,
        "TeamsBearer")
    .RequireAuthenticatedUser()
    .Build();
});

builder.Services.AddControllersWithViews();

var app = builder.Build();

// 中间件配置
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

2. 前端适配逻辑

页面加载时先判断是否处于Teams环境,自动切换认证方式:

<!-- 引入Teams SDK和JWT解析库 -->
<script src="https://statics.teams.cdn.office.net/sdk/v1.11.0/js/MicrosoftTeams.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jwt-decode@3.1.2/build/jwt-decode.min.js"></script>

<script>
    // 检测当前环境是否为Teams
    function isInTeams() {
        return window.location.href.includes("teams.microsoft.com") || 
               window.navigator.userAgent.includes("Teams");
    }

    window.onload = function() {
        if (isInTeams()) {
            // Teams环境:使用SSO获取令牌
            microsoftTeams.initialize();
            const authTokenRequest = {
                successCallback: function(result) {
                    const token = jwtDecode(result);
                    document.getElementById("userAqui").innerHTML = `Welcome ${token.name}`;
                    // 全局设置请求头,后续API请求携带令牌
                    axios.defaults.headers.common['Authorization'] = `Bearer ${result}`;
                },
                failureCallback: function(error) {
                    alert(`Failed to get Teams token: ${error}`);
                }
            };
            microsoftTeams.authentication.getAuthToken(authTokenRequest);
        } else {
            // 普通浏览器:检查登录状态,未登录则跳转OIDC认证
            fetch('/api/account/isauthenticated')
                .then(res => res.json())
                .then(data => {
                    if (!data.isAuthenticated) {
                        window.location.href = "/signin-oidc";
                    } else {
                        // 已登录,获取用户信息
                        fetch('/api/account/userinfo')
                            .then(res => res.json())
                            .then(user => {
                                document.getElementById("userAqui").innerHTML = `Welcome ${user.name}`;
                            });
                    }
                });
        }
    }
</script>

3. 后端辅助API(AccountController)

用于浏览器端检查登录状态和获取用户信息:

[ApiController]
[Route("api/[controller]")]
public class AccountController : ControllerBase
{
    [HttpGet("isauthenticated")]
    public IActionResult IsAuthenticated()
    {
        return Ok(new { isAuthenticated = User.Identity.IsAuthenticated });
    }

    [HttpGet("userinfo")]
    public IActionResult GetUserInfo()
    {
        if (!User.Identity.IsAuthenticated)
        {
            return Unauthorized();
        }

        var userInfo = new
        {
            name = User.Claims.FirstOrDefault(c => c.Type == "name")?.Value,
            email = User.Claims.FirstOrDefault(c => c.Type == "email")?.Value
        };

        return Ok(userInfo);
    }
}

4. 关键注意事项

  • Teams应用注册配置:确保Azure AD应用已添加Teams平台,并且API权限中添加了User.Read等必要权限,已授予管理员同意。
  • 令牌验证一致性:JWT Bearer认证的Audience和Issuer必须与应用注册信息完全匹配。
  • Teams初始化时机:必须先调用microsoftTeams.initialize()再请求令牌,否则会失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 09:07:57