为了账号安全,请及时绑定邮箱和手机立即绑定

ASP.NET Core SignalR 使用 Azure AD 返回 401 未经授权

ASP.NET Core SignalR 使用 Azure AD 返回 401 未经授权

C#
慕斯709654 2023-09-24 17:19:29
我有一个 SPA (Angular 7) 和一个 API (.Net Core),我使用 Azure AD 对其进行身份验证。我正在使用adal-angular4将我的角度应用程序与 AAD 集成。一切都很好,但我也使用 SignalR 和 API 作为服务器,当我尝试从 SPA 连接时,我在协商“请求”上收到 401 Unauthorized 消息,并在响应标头中得到此消息:该请求在 Authorization 标头中包含我的 Bearer 令牌,当我通过jwt.io运行该令牌时,我可以看到“aud”值是我的 SPA 的 Azure AD ClientId。对 API 的所有常规请求都包含相同的令牌,我对此没有任何问题。我的所有控制器和集线器上都有[授权],但只有 SignalR 集线器会导致此问题。我的 SignalR 中心:[Authorize]public class MainHub : Hub{    private readonly IEntityDbContext _ctx;    public MainHub(IEntityDbContext ctx)    {        _ctx = ctx;        _signalRService = signalRService;    }    public override Task OnConnectedAsync()    {        return base.OnConnectedAsync();    }    public override Task OnDisconnectedAsync(Exception exception)    {        return base.OnDisconnectedAsync(exception);    }}这是我的 Angular 客户端上的 SignalRService。我在 app.component.ts 的构造函数中运行 startConnection() 。export class SignalRService {    private hubConnection: signalR.HubConnection;    constructor(private adal: AdalService) {}    startConnection(): void {        this.hubConnection = new signalR.HubConnectionBuilder()            .withUrl(AppConstants.SignalRUrl, { accessTokenFactory: () => this.adal.userInfo.token})            .build();        this.hubConnection.serverTimeoutInMilliseconds = 60000;        this.hubConnection.on('userConnected', (user) =>         {            console.log(user);        });        this.hubConnection.start()            .then(() => console.log('Connection started'))            .catch(err =>             {                console.log('Error while starting connection: ' + err);            });    }}我已经尝试过这个解决方案,但我也无法让它发挥作用。
查看完整描述

1 回答

?
泛舟湖上清波郎朗

TA贡献1818条经验 获得超3个赞

您需要对 JWT Bearer 事件进行特殊处理,以便您的身份验证正常工作。令牌需要转发到集线器。看看我说的部分

那部分不见了

public void ConfigureServices(IServiceCollection services)

{

    services.AddDbContext<ApplicationDbContext>(options =>

        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));


    services.AddIdentity<ApplicationUser, IdentityRole>()

        .AddEntityFrameworkStores<ApplicationDbContext>()

        .AddDefaultTokenProviders();


    services.AddAuthentication(options =>

        {

            // Identity made Cookie authentication the default.

            // However, we want JWT Bearer Auth to be the default.

            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;

            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

        })

        .AddJwtBearer(options =>

        {

            // Configure JWT Bearer Auth to expect our security key

            options.TokenValidationParameters =

                new TokenValidationParameters

                {

                    LifetimeValidator = (before, expires, token, param) =>

                    {

                        return expires > DateTime.UtcNow;

                    },

                    ValidateAudience = false,

                    ValidateIssuer = false,

                    ValidateActor = false,

                    ValidateLifetime = true,

                    IssuerSigningKey = SecurityKey

                };


            //THAT IS THE PART WHICH IS MISSING IN YOUR CONFIG !

            // We have to hook the OnMessageReceived event in order to

            // allow the JWT authentication handler to read the access

            // token from the query string when a WebSocket or 

            // Server-Sent Events request comes in.

            options.Events = new JwtBearerEvents

            {

                OnMessageReceived = context =>

                {

                    var accessToken = context.Request.Query["access_token"];


                    // If the request is for our hub...

                    var path = context.HttpContext.Request.Path;

                    if (!string.IsNullOrEmpty(accessToken) &&

                        (path.StartsWithSegments("/hubs/chat")))

                    {

                        // Read the token out of the query string

                        context.Token = accessToken;

                    }

                    return Task.CompletedTask;

                }

            };

        });


    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);


    services.AddSignalR();


    // Change to use Name as the user identifier for SignalR

    // WARNING: This requires that the source of your JWT token 

    // ensures that the Name claim is unique!

    // If the Name claim isn't unique, users could receive messages 

    // intended for a different user!

    services.AddSingleton<IUserIdProvider, NameUserIdProvider>();


    // Change to use email as the user identifier for SignalR

    // services.AddSingleton<IUserIdProvider, EmailBasedUserIdProvider>();


    // WARNING: use *either* the NameUserIdProvider *or* the 

    // EmailBasedUserIdProvider, but do not use both. 

}


查看完整回答
反对 回复 2023-09-24
  • 1 回答
  • 0 关注
  • 133 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信