猿问

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

我们目前正在开发一个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,然后以这种方式更新令牌?


杨魅力
浏览 98回答 1
1回答

慕后森

我们经常将 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>();}这只是一个想法,您应该考虑它并使其适应您自己的解决方案。
随时随地看视频慕课网APP
我要回答