zoukankan      html  css  js  c++  java
  • 从零开始一起学Blazor WebAssembly 开发(5_1)权限控制初识

    上篇讲了Blazor WebAssembly 实现登录以及获取Token,本篇讲一下如何实现在前端这块的权限控制。

    Blazor 实现权限控制主要实现以下两个:

    1、实现判断是否有权限

    2、打开没有权限页面跳转到登录页面

    3、没有权限的菜单不显示

    记住一点,客户端实现的权限控制不是真的控制不能使用某个功能,因为客户端是可以被破解的。所以想控制某个功能不被使用还是要依靠服务后端来控制。

    现在依次说下以上三点如何实现,第一点我利用了asp.net core 和 blazor提供的基于策略的权限框架。做了一些改造,主要是因为完全使用他们那种与我做的Token机制不能有效结合,还好比较容易扩展。改造的地方也不多。主要是做了一个自定义的CustomAuthStateProvider

    public class CustomAuthStateProvider : AuthenticationStateProvider
        {
            private readonly TokenUtil _tokenUtil;
            public CustomAuthStateProvider(TokenUtil tokenUtil)
            {
                _tokenUtil = tokenUtil;
            }
    
            public override async Task<AuthenticationState> GetAuthenticationStateAsync()
            {
                try
                {
                    string tokenJson = await _tokenUtil.GetAccessToken();
                    if (!String.IsNullOrEmpty(tokenJson))
                    {
                        TokenInfo token = JsonConvert.DeserializeObject<TokenInfo>(tokenJson);
    
                        if (token != null && token.TokenExpire>DateTime.Now)
                        {
                            var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token.TokenValue), "jwt"));
                            return new AuthenticationState(authenticatedUser);
                        }
                        else
                        {
                            return new AuthenticationState(new ClaimsPrincipal());
                        }
                    }
                    else
                    {
                        return new AuthenticationState(new ClaimsPrincipal());
                    }
                }
                catch (Exception ex)
                {
                    return new AuthenticationState(new ClaimsPrincipal());
                }
            }
            public void NotifyAuthenticationState()
            {
                NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
            }
            private IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
            {
                var claims = new List<Claim>();
                var payload = jwt.Split('.')[1];
                var jsonBytes = System.Text.Encoding.Default.GetString(ParseBase64WithoutPadding(payload));
                var keyValuePairs = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonBytes);
                keyValuePairs.TryGetValue(JwtClaimTypes.Name, out object roles);
                if (roles != null)
                {
                    if (roles.ToString().Trim().StartsWith("["))
                    {
                        var parsedRoles = JsonConvert.DeserializeObject<string[]>(roles.ToString());
                        foreach (var parsedRole in parsedRoles)
                        {
                            claims.Add(new Claim(JwtClaimTypes.Name, parsedRole));
                        }
                    }
                    else
                    {
                        claims.Add(new Claim(JwtClaimTypes.Name, roles.ToString()));
                    }
                    keyValuePairs.Remove(JwtClaimTypes.Name);
                }
                claims.AddRange(keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString())));
                return claims;
            }
            private byte[] ParseBase64WithoutPadding(string base64)
            {
                switch (base64.Length % 4)
                {
                    case 2: base64 += "=="; break;
                    case 3: base64 += "="; break;
                }
                return Convert.FromBase64String(base64);
            }
        }

    这里边主要是通过 重写了
    GetAuthenticationStateAsync方法来返回Token所具有的权限,代码仅供参考。因为ParseClaimsFromJwt 这步解析的我仅仅把JwtClaimTypes.Name的解析出来了。并没有完全解析出来。使用的时候根据自己个人情况来写权限策略。

    写好这个后在program里写一下注入相关的代码

     public static async Task Main(string[] args)
            {
                var builder = WebAssemblyHostBuilder.CreateDefault(args);
                builder.RootComponents.Add<App>("app");
    
                //builder.Services.AddTransient<CryptoKeyConfig>();
                builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri("https://localhost:44319") });
                builder.Services.AddTransient<TokenUtil>();
                builder.Services.AddTransient<TokenHttpClient>();
                builder.Services.AddScoped<CustomAuthStateProvider>();
                builder.Services.AddScoped<AuthenticationStateProvider>(s => s.GetRequiredService<CustomAuthStateProvider>());
                //在wasm中没有默认配置,所以需要设置一下
                builder.Services.AddOptions();
                builder.Services.AddAuthorizationCore();
                builder.Services.AddAntDesign();
                builder.Services.AddOidcAuthentication(options =>
                {
                    // Configure your authentication provider options here.
                    // For more information, see https://aka.ms/blazor-standalone-auth
                    builder.Configuration.Bind("Local", options.ProviderOptions);
                });
                await builder.Build().RunAsync();
            }
    share 文件夹下加一下无权限时跳转到登录页面的一个layout 名字叫 RedirectToLogin.razor
    
    @inject NavigationManager Navigation
    @using Microsoft.AspNetCore.Components.WebAssembly.Authentication
    @code {
        protected override void OnInitialized()
        {
            Navigation.NavigateTo($"/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
        }
    }

    App.razor 改成如下

    注意,这里实现了没有权限时跳转到登录窗口的代码

    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                <NotAuthorized>
                    @if (!context.User.Identity.IsAuthenticated)
                    {
                        <RedirectToLogin />
                    }
                    else
                    {
                        <p>You are not authorized to access this resource.</p>
                    }
                </NotAuthorized>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
    <AntContainer /> 

    这样基本的权限控制就实现了。下篇讲一下如何用AuthorizeView 组件 和[Authorize] 属性 实现页面内组件和页面本身的权限控制。也就是开头说的2 和 3如何实现。

  • 相关阅读:
    TeX系列: tikz-3dplot绘图宏包
    TeX系列: MATLAB和LaTeX结合绘图
    Tex系列: pgfplots安装
    C 标准库
    C 标准库
    C 标准库
    C 标准库
    C 标准库
    C 标准库
    C 标准库
  • 原文地址:https://www.cnblogs.com/wcoolly/p/15341565.html
Copyright © 2011-2022 走看看