【问题标题】:Logout automatically on token expiration time in blazor web assembly在 Blazor Web 程序集中的令牌到期时间自动注销
【发布时间】:2021-08-23 10:11:44
【问题描述】:

我正在开发一个 blazor Web 程序集应用程序。我创建了登录和注销方法,对于令牌到期时间的注销,我将到期日期存储在本地存储中。但检查此日期需要加载整页。我想自动检查那个日期,或者当我打开一个页面并重定向到登录页面时,如果那个时间过去了。

这是我的 CustomAuthenticationStateProvider.cs

public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
    private readonly HttpClient _httpClient;
    private readonly ILocalStorageService _localStorageService;

    public CustomAuthenticationStateProvider(HttpClient httpClient, ILocalStorageService localStorageService)
    {
        _httpClient = httpClient;
        _localStorageService = localStorageService;
    }

    private async Task<bool> TokenExpired()
    {
        bool expire = false;

        var exist = await _localStorageService.ContainKeyAsync(ClientConstantKeys.AppTokenExpireDate);

        if (exist)
        {
            var dateString = await _localStorageService.GetItemAsync<string>(ClientConstantKeys.AppTokenExpireDate);
            var date = DateTime.Parse(dateString);

            if (DateTime.Now >= date)
            {
                expire = true;
                await NotifyUserLoggedOut();
            }
        }
        else
        {
            expire = true;
            await NotifyUserLoggedOut();
        }

        return expire;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var token = await _localStorageService.GetItemAsync<string>(ClientConstantKeys.AppToken);
        var expired = await TokenExpired();

        if (string.IsNullOrEmpty(token) || expired)
        {
            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
        }

        var claimsValueTypes = await _localStorageService.GetItemAsync<Dictionary<string, object>>(ClientConstantKeys.AppClaims);
        var claims = ClaimParser.GetClaims(claimsValueTypes);

        _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);


        return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(claims, "jwtAuthType")));
    }

    public void NotifyUserLogIn(List<Claim> claims)
    {
        var authState = Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(claims, "jwtAuthType"))));
        base.NotifyAuthenticationStateChanged(authState);
    }

    public async Task NotifyUserLoggedOut()
    {
        var authState = Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())));
        await _localStorageService.RemoveItemAsync(ClientConstantKeys.AppToken);
        await _localStorageService.RemoveItemAsync(ClientConstantKeys.AppClaims);
        await _localStorageService.RemoveItemAsync(ClientConstantKeys.AppTokenExpireDate);
        _httpClient.DefaultRequestHeaders.Authorization = null;
        base.NotifyAuthenticationStateChanged(authState);
    }
}

这是 App.Razor

<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
            <NotAuthorized>
              <AccessDenied></AccessDenied>
            </NotAuthorized>
        </AuthorizeRouteView>
    </Found>
    <NotFound>
        <LayoutView Layout="@typeof(MainLayout)">
            <PageNotFound></PageNotFound>
        </LayoutView>
    </NotFound>
</Router>
</CascadingAuthenticationState>

当我点击登录或注销时一切正常,但我想自动检查过期时间。

我尝试用 AuthorizedView 标签包裹我的整个页面,但没有任何反应。

谢谢

【问题讨论】:

  • 你找到解决办法了吗?
  • @SBU 也许这不是一个好主意,但我创建了一个没有任何标记的组件,并且在它的 OnInitializedAsync 方法中检查令牌过期时间,如果令牌无效,请调用 NotifyUserLoggedOut 方法并导航到登录页面。在打开令牌之前,我必须将此组件添加到要检查令牌的每个组件中。
  • 其实我也有类似的想法。我正在检查返回 401 的过滤器管道上的令牌过期。我在 MainLayout 上创建了一个函数来处理错误并通过 CascadingParameter 将该函数发送到其他组件。如果捕获状态捕获 401,我会注销用户并重定向到 Login。
  • @SUB 是的,看来他们的想法是一样的,我试试,谢谢

标签: c# asp.net-web-api blazor blazor-webassembly


【解决方案1】:

我使用 FilterPipeline 检查令牌过期时间,然后在每次请求后检查 Blazor WASM 上的响应类型。制作了一个使代码干净的功能。方法如下:

WebAPI->过滤器->JwtTokenValidateAttribute.cs

 public class JwtTokenValidateAttribute : Attribute, IAuthorizationFilter
    {

        public void OnAuthorization(AuthorizationFilterContext context)
        {
            string token = context.HttpContext.Request.Headers[HeaderNames.Authorization].ToString().Replace("Bearer ", "");
            if (string.IsNullOrWhiteSpace(token))
            {
                context.Result = new UnauthorizedResult();
                return;
            }

            var tokenManager = context.HttpContext.RequestServices.GetService(typeof(ICustomTokenManager)) as ICustomTokenManager;
            if(tokenManager != null && !tokenManager.VerifyToken(token))
            {
                context.Result = new UnauthorizedResult();
                return;
            }
        }
    }

创建属性后,我们可以像这样在控制器上调用它:

 [Route("api/[controller]")]
    [ApiVersion("1.0")]
    [ApiController]
    [JwtTokenValidateAttribute] //here we call the filter pipeline
    public class SupplierCompaniesController : ControllerBase
    {
       //your controller goes here
    }

MainLayout.razor:

@code{
 public async Task HandleException(Exception exception)
    {
        if (exception.Message.Contains("401"))
        {
            await AuthenticationUseCases.Logout();
            navigationManager.NavigateTo("/login/Expired", true);
            return;
        }
//If you use AutoWrapper or other packages, you can send messages here based on your response type, don't forget to parse the values. 
    }
}

之后,我们可以在任何向 API 发送请求的页面中调用 HandleErrors,例如:

首先我们需要用 CascadingValue 包裹@body

<CascadingValue Value="this" Name="MainLayout">
     @Body
</CascadingValue>

现在我们需要转到任何要向 API 发送请求的 Razor 组件

@code{
[CascadingParameter(Name = "MainLayout")]
public MainLayout MainLayout { get; set; }
async Task HandleException(Exception e) => await MainLayout.HandleException(e);

async Task OnCreateRow(RoleDto role)
    {
        try
        {
            //Your api call goes here
        }
        catch (Exception e)
        {
            await MainLayout.HandleException(e);
        }
    }
}

此解决方案可能不是最好的,希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 2018-10-21
    • 2021-03-30
    • 2022-01-16
    • 2021-12-14
    • 2011-02-13
    • 2017-04-02
    • 2019-12-25
    • 1970-01-01
    • 2021-08-22
    相关资源
    最近更新 更多