ASPNET Core SignalR 을 이용한 Push Server 구현 - 2 (인증처리)

2023. 7. 3. 00:00ASPNET/SignalR

반응형

SignalR 관련해서도 인증처리가 가능 하다.

일반적으로 인증서버를 만들고 해당 서버로 부터 인증처리 하도록 한다. 

https://yogingang.tistory.com/412

 

Rest API Template 만들기 - EP 08 (DB 를 통해 AccessToken 및 RefreshToken 관리)

이제 인증관련 하여 수정을 해야할 때이다. 기존에는 JWT 를 통해 AccessToken 을 사용하여 validation 처리를 aspnet core 내부적으로 하게 하였다. 이렇게 만든 JWT 는 일반적인 validation 처리를 하기 때문

yogingang.tistory.com

위  Rest API Template 의 인증을 이용하여 인증 서버를 활용하겠다.

 

 

이제 이 인증서버를 이용하여 SignalR 관련 인증을 처리해보자

ChannelHubAuthorizationHandler.cs

using Microsoft.AspNetCore.Authorization;

namespace SignalRTemplate.Authorization;

public class ChannelHubAuthorizationRequirement : IAuthorizationRequirement
{
}

public class ChannelHubAuthorizationHandler : AuthorizationHandler<ChannelHubAuthorizationRequirement>
{

    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IConfiguration _configuration;
    private readonly ILogger _logger;
    public ChannelHubAuthorizationHandler(IHttpContextAccessor httpContextAccessor, IConfiguration configuration, ILogger logger)
    {
        _httpContextAccessor = httpContextAccessor;
        _configuration = configuration;
        _logger = logger;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ChannelHubAuthorizationRequirement requirement)
    {
        string jwtToken = string.Empty;
        var token = request?.Headers["Authorization"];
        AuthenticationHeaderValue.TryParse(token, out var tokenValue);
        jwtToken = tokenValue?.Parameter ?? "";

        jwtToken = jwtToken =="" ? request?.Query["access_token"].FirstOrDefault() ?? string.Empty : jwtToken;

        if (await ValidateTokenAsync(jwtToken))
        {
            _logger.LogDebug("Signalr authorization succeed");
            context.Succeed(requirement);
        }
        else
        {
            _logger.LogDebug("Signalr authorization failed");
            context.Fail();
        }

    }

    private async ValueTask<bool> ValidateTokenAsync(string token)
    {
        try
        {
            var url = _configuration.GetSection("HostService").GetValue<string>("Identity");
            using (HttpClient client = new HttpClient())
            {
                client.DefaultRequestHeaders.Add("Authorization", $"bearer {token}");
                var response = await client.GetAsync(url);
                if (response.IsSuccessStatusCode)
                    return true;
            }

            return false;

        }
        catch (Exception e)
        {
            _logger.LogInformation(e.Message);
            return false;
        }
    }
}

appsettings.json

...
"HostService": {
    "Identity": "https://localhost:7207/user/authentication"
  },
...

 

Program.cs

...
builder.Services.AddScoped<IAuthorizationHandler, ChannelHubAuthorizationHandler>();
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("ChannelHubAuthorizationPolicy", policy =>
    {
        policy.Requirements.Add(new ChannelHubAuthorizationRequirement());
    });
});
...

 

ChannelHub.cs

[Authorize("ChannelHubAuthorizationPolicy")]
public class ChannelHub : Hub
{
...

 

이제 client 에서 작업을 해보자

 

SignalRClient

인증 서버로 부터 token 받아오기

var identityUrl = $"https://localhost:7207/user/login";
HttpClient client = new HttpClient();
var request = new 
{
    Id = "Test0001",
    Password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4",
};
var contents = new StringContent(request.SerializeToJson(), System.Text.Encoding.UTF8, "application/json");
var response =await client.PostAsync(identityUrl, contents);
string token = string.Empty;
if (response.IsSuccessStatusCode)
{
    var loginResponse = await response.Content.ReadAsAsync<Login.Response>();
    token = loginResponse?.AccessToken ?? "";
}

 

받은 token 을 이용하여 HubConnection 생성

// signalR 접속 url
var url = $"https://localhost:5004/channel";

var connection = new HubConnectionBuilder()
.WithUrl(url, options =>
{
    options.SkipNegotiation = true;
    options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets;
    options.Headers.Add("Authorization", $"bearer {token}");
})
.WithAutomaticReconnect()
.Build();

SignalR server 로 접속

// connection1 생성
var connection1 = await InitSignalRClient();

// server 접속
await connection1.StartAsync();

...

정상적으로 통신이 되는지 확인하자

 

이번에는 Headers token 을 빼고 인증해 보자

// signalR 접속 url
var url = $"https://localhost:5004/channel";

var connection = new HubConnectionBuilder()
.WithUrl(url, options =>
{
    options.SkipNegotiation = true;
    options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets;
    //options.Headers.Add("Authorization", $"bearer {token}");
})
.WithAutomaticReconnect()
.Build();

 

인증 처리 없이 method 호출 처리시 401, 403 또는 접속 실패가 발생한다. (500 error 가 발생하기도 한다)

 

 

관련영상

https://youtu.be/grgBgJk1jz0

 

반응형

'ASPNET > SignalR' 카테고리의 다른 글

ASPNET Core SignalR 을 이용한 Push Server 구현 - 1  (0) 2023.06.26