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

使用 Blazor 和 Refresh Token 实现短暂的 Jwt

使用 Blazor 和 Refresh Token 实现短暂的 Jwt

C#
杨魅力 2023-09-16 17:23:35
我们目前正在开发一个Blazor应用程序,该应用程序使用带有刷新令牌的短期(10 分钟)Jwt 进行保护。目前我们已经实现了 Jwt,通过 Blazor 服务器端 Web api 可以登录、生成 Jwt 并生成刷新令牌。从客户端我使用了以下链接;使用客户端 Blazor 进行身份验证并扩展ApiAuthenticationStateProvider.cs如下;public class ApiAuthenticationStateProvider : AuthenticationStateProvider{    private readonly HttpClient _httpClient;    private readonly ILocalStorageService _localStorage;    public ApiAuthenticationStateProvider(HttpClient httpClient, ILocalStorageService localStorage)    {        _httpClient = httpClient;        _localStorage = localStorage;    }    public override async Task<AuthenticationState> GetAuthenticationStateAsync()    {        var savedToken = await _localStorage.GetItemAsync<string>("authToken");        var refreshToken = await _localStorage.GetItemAsync<string>("refreshToken");        if (string.IsNullOrWhiteSpace(savedToken) || string.IsNullOrWhiteSpace(refreshToken))        {            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));        }        var userResponse = await _httpClient.GetAsync<UserModel>("api/accounts/user", savedToken);        if(userResponse.HasError)        {            var response = await _httpClient.PostAsync<LoginResponse>("api/login/refreshToken", new RefreshTokenModel { RefreshToken = refreshToken });            //check result now            if (!response.HasError)            {                await _localStorage.SetItemAsync("authToken", response.Result.AccessToken);                await _localStorage.SetItemAsync("refreshToken", response.Result.RefreshToken);                userResponse = await _httpClient.GetAsync<UserModel>("api/accounts/user", response.Result.AccessToken);            }但是,我遇到的第二个问题是,如果 Jwt 在此调用期间过期,我将需要调用以使用刷新令牌来获取新的 Jwt。有没有办法可以使用中间件来执行此操作,以避免每次调用时都检查 401,然后以这种方式更新令牌?
查看完整描述

1 回答

?
慕后森

TA贡献1802条经验 获得超5个赞

我们经常将 Blazor 视为 MVC,但事实并非如此。它更像是在浏览器内运行的桌面应用程序。我以这种方式使用 JWT 和更新令牌:登录后,我有一个无限循环,正在 ping 后端并保持会话并更新令牌。简化:


class JWTAuthenticationStateProvider : AuthenticationStateProvider

{

    private bool IsLogedIn = false;

    private CustomCredentials credentials = null;

    // private ClaimsPrincipal currentClaimsPrincipal = null; (optinally)

    public Task Login( string user, string password )

    {

         credentials = go_backend_login_service( user, password );

         // do stuff with credentials and claims

         // I raise event here to notify login

         keepSession( );

    }

    public Task Logout(  )

    {

         go_bakcend_logout_service( credentials );

         // do stuff with claims

         IsLogedIn = false;

         // I raise event here to notify logout

    }

    public override Task<AuthenticationState> GetAuthenticationStateAsync()

    {

        // make a response from credentials or currentClaimsPrincipal

    }

    private async void KeepSession()

    {

        while(IsLogedIn)

        {

            credentials = go_backend_renewingJWT_service( credentials );

            // do stuff with new credentials: check are ok, update IsLogedIn, ...

            // I raise event here if server says logout

            await Task.Delay(1000);  // sleep for a while.

        }

    }

}

记得通过DI注册组件:


public void ConfigureServices(IServiceCollection services)

{

    // ... other services added here ...


    // One JWTAuthenticationStateProvider for each connection on server side.

    // A singleton for clientside.

    services.AddScoped<AuthenticationStateProvider, 

                       JWTAuthenticationStateProvider>();

}

这只是一个想法,您应该考虑它并使其适应您自己的解决方案。

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

添加回答

举报

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