如何从 blazor 中的 .cs 文件访问浏览器本地存储?

How do I access browser local storage from .cs files in blazor?

首先,我可以访问 .razor 页面中的本地存储数据。我的意思是我无法访问 .cs 文件中的本地存储数据。如何访问?

_Imports.razor:

@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
@inject ProtectedLocalStorage protectedLocalStorage

任何人.razor 文件:

await protectedLocalStorage.SetAsync(key, JsonSerializer.Serialize(instance));

以上代码适用于我,但我想另外从 .cs 文件调用 protectedLocalStorage。

P.S对语法错误表示抱歉

编辑: 我在 startup.cs 中使用 IHttpClientFactory,我想在 api 请求之前将令牌添加为 header。

startup.cs

    services.AddHttpClient("api", hc =>
    {
        hc.BaseAddress = new Uri("http://localhost:5000/");

        string tokenVal = tokenService.GetToken();

        if (!String.IsNullOrEmpty(tokenVal))
            hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenVal);
    });

我想从这个 .cs 文件的本地存储中获取令牌值

public class TokenService : ITokenService
{
    private IHttpContextAccessor httpContextAccessor;

    public TokenService(IHttpContextAccessor HttpContextAccessor, IProtected) => httpContextAccessor = HttpContextAccessor;

    public string GetToken()
    {
        return "";
    }
}

How do I access browser local storage from .cs files in blazor?

ASP.NET 在大多数构造函数中支持注入。扩展 OP 的示例:

// Startup.cs -> ConfigureServices(IServiceCollection services)
    // Probably not necessary in your case but, to be thorough:
    services.AddScoped<ProtectedLocalStorage>();

// SomeFile.cs
public class TokenService : ITokenService
{
    // Ignore for the moment that these are being used in the same context
    private IHttpContextAccessor httpContextAccessor;
    private readonly ProtectedBrowserStorage _storage;

    // Injection can happen here in ASP.NET
    public TokenService(
        IHttpContextAccessor HttpContextAccessor, 
        ProtectedBrowserStorage storage) 
    {
        httpContextAccessor = HttpContextAccessor;
        // injection works but the PBS service might not: see below
        _storage = storage;
    }

    //..
}

但是,我不建议将此用于 ProtectedBrowserStorage,因为它在后台使用 IJSRuntime。如果您尝试在非 javascript 感知上下文中使用它(例如,在 Startup.Configure 期间,客户端仍在等待响应并且无法执行 javascript),您将 运行 进入错误。在 Blazor 中,ProtectedBrowserStorage 只能从 Blazor 组件直接或间接调用;为简单起见,将其包装在 class 中,您只使用组件,或将其保留在组件本身中。

因此,如果您尝试这样做:

I am using IHttpClientFactory in startup.cs and I want to add token as a header before api request.

ProtectedBrowserStorage 不是适合您的工具。使用 cookie 或其他网络服务器技术。

我最后是怎么解决的:

我创建了自定义身份验证 class 继承了 AuthenticationStateProvider。然后我设计了所有需要在 ProtectedLocalStorage 上解决的检查过程。

AuthenticationService

    public class AuthenticationService : AuthenticationStateProvider
    {
        private const string USER_SESSION_OBJECT_KEY = "user_session_obj";
        private const string ACCESS_TOKEN = "accesstoken";
        private const string USER_PERMISSIONS = "userpermissions";

        private readonly ProtectedLocalStorage _protectedLocalStorage;
        private readonly IHttpContextAccessor _httpContextAccessor;

        public AuthenticationService(ProtectedLocalStorage protectedSessionStore, IHttpContextAccessor httpContextAccessor)
        {
            _protectedLocalStorage = protectedSessionStore;
            _httpContextAccessor = httpContextAccessor;
        }

        public string IpAddress => _httpContextAccessor?.HttpContext?.Connection?.RemoteIpAddress?.ToString() ?? string.Empty;

        private User User { get; set; }
        private List<UserPermission> UserPermissionList { get; set; }

        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            try
            {
                User userSession = await GetUserSession();
                List<UserPermission> userPermissions = await GetUserPermission();

                if (userSession != null)
                    return await GenerateAuthenticationState(userSession, userPermissions);
                return await GenerateEmptyAuthenticationState();
            }
            catch
            {
                await LogoutAsync();
                return null;
            }
          
        }

        public async Task LoginAsync(User user,List<UserPermission> userPermissions)
        {
            await SetUserSession(user);
            await SetUserPermissionSession(userPermissions);

            NotifyAuthenticationStateChanged(GenerateAuthenticationState(user, userPermissions));
        }

        public async Task LogoutAsync()
        {
            //await SetUserSession(null);
            RefreshUserSession(null);
            await _protectedLocalStorage.DeleteAsync(USER_SESSION_OBJECT_KEY);
            await _protectedLocalStorage.DeleteAsync(ACCESS_TOKEN);
            await _protectedLocalStorage.DeleteAsync(USER_PERMISSIONS);

            NotifyAuthenticationStateChanged(GenerateEmptyAuthenticationState());
        }

        public async Task<User> GetUserSession()
        {
            if (User != null)
                return User;
            //TODO burda localUserJson get yaparken hata alıyor. try catch işi çözmezse buraya tekrardan bakılacak.
            try
            {
                var localUserJson = await _protectedLocalStorage.GetAsync<string>(USER_SESSION_OBJECT_KEY);

                if (string.IsNullOrEmpty(localUserJson.Value))
                    return null;

                return RefreshUserSession(JsonConvert.DeserializeObject<User>(localUserJson.Value));
            }
            catch
            {
                await LogoutAsync();
                return null;
            }
        }
        public async Task<List<UserPermission>> GetUserPermission()
        {
            if (UserPermissionList != null)
                return UserPermissionList;
            try
            {
                var localUserPermissionJson = await _protectedLocalStorage.GetAsync<string>(USER_PERMISSIONS);

                if (string.IsNullOrEmpty(localUserPermissionJson.Value))
                    return null;

                return RefreshUserPermissionSession(JsonConvert.DeserializeObject<List<UserPermission>>(localUserPermissionJson.Value));
            }
            catch
            {
                await LogoutAsync();
                return null;
            }
        }
        private async Task SetUserSession(User user)
        {
            RefreshUserSession(user);

            await _protectedLocalStorage.SetAsync(USER_SESSION_OBJECT_KEY, JsonConvert.SerializeObject(user));
        }

        private async Task SetUserPermissionSession(List<UserPermission> userPermissions)
        {
            RefreshUserPermissionSession(userPermissions);

            await _protectedLocalStorage.SetAsync(USER_PERMISSIONS, JsonConvert.SerializeObject(userPermissions));
        }

        private User RefreshUserSession(User user) => User = user;
        private List<UserPermission> RefreshUserPermissionSession(List<UserPermission> userPermission) => UserPermissionList = userPermission;

        private Task<AuthenticationState> GenerateAuthenticationState(User user, List<UserPermission> userPermission)
        {
            ClaimsIdentity claimsIdentity = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.Name, user.Id.ToString()),
                new Claim(ClaimTypes.Role, userPermission.ToString()),
            }, "auth");

            ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
            return Task.FromResult(new AuthenticationState(claimsPrincipal));
        }

        private Task<AuthenticationState> GenerateEmptyAuthenticationState() => Task.FromResult(new AuthenticationState(new ClaimsPrincipal()));
    }

然后我在startup.cs

中注册了这个class

启动

services.AddScoped<AuthenticationStateProvider, AuthenticationService>();

在更改页面期间,身份验证系统中断显示页面以检查它是否通过以下代码。

_进口

@attribute [Authorize]

*您可以在登录页面设置localstorage。您可以通过这种方式创建自己的检查方式。