Blazor,自定义身份验证,然后基于授权策略

时间:2021-07-11 14:14:51

标签: c# .net asp.net-core authentication blazor-server-side

我正在创建一个 blazor 服务器端应用程序,我添加了一个 CustomAuthenticationStateProvider 并通过会话检查用户是否仍然处于活动状态等等。遵循我添加了基于策略的控件,因此我检查用户是否有权访问某个区域或执行某个操作。 我注意到如果我使用 @attribute [Authorize(Policy = "Insert_receipt")] 应用程序不再进入 CustomAuthenticationStateProvider,这样它就不会在发生更改时更新用户的状态。我必须强制重新加载页面 (F5) 才能重新进入 CustomAuthenticationStateProvider。

我在剃刀页面尝试过这个

@attribute [Authorize]
@attribute [Authorize(Policy = "Insert_receipt")] 

但应用程序会忽略第一个,它只会检查用户是否拥有该策略。

我也试过这个

@attribute [Authorize]

<h3>ReceiptEntry</h3>
<AuthorizeView Policy = "Insert_receipt">
    <Authorized>

                <p>Create</p>

                <p>@IdVehicle</p>
                @if (User != null) {
                    <p>@User.Username</p>
                }
                @if (User2 != null) {
                    <p>@User2.Username</p>
                }

    </Authorized>
</AuthorizeView>

但没什么,这行不通。

CustomAuthenticationStateProvider.cs

  public class CustomAuthenticationStateProvider : AuthenticationStateProvider {


        private ISessionStorageService _sessionStorageService;

        private int _exp_date = 1;

        private UserLoginService _userService = new UserLoginService();

        public CustomAuthenticationStateProvider(ISessionStorageService sessionStorageService) {
            _sessionStorageService = sessionStorageService;
        }

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public override async Task<AuthenticationState> GetAuthenticationStateAsync() {
            UserLogged User = null;
            //var username = await _sessionStorageService.GetItemAsync<UserLogged>("User");

            var token = await _sessionStorageService.GetItemAsync<string>("User");
            if (token != null) {
                try {
                    var u = Utility.Decrypt(token);
                    User = JsonConvert.DeserializeObject<UserLogged>(u);
                    DateTime dt = User.Expired_date;
                    User = _userService.GetUserLogged(User.Username);
                    User.Expired_date = dt;
                } catch (Exception) {
                    await _sessionStorageService.RemoveItemAsync("User");
                }
            }
            ClaimsIdentity identity;

            if (User != null) {
                if (User.Expired_date > DateTime.Now) {
                    // correggo l'ora della scadenza
                    User.Expired_date = DateTime.Now.AddDays(_exp_date);
                    var serializeObject = JsonConvert.SerializeObject(User);
                    var encrSerializeObject = Utility.Encrypt(serializeObject);
                    await _sessionStorageService.SetItemAsync("User", encrSerializeObject);

                    Claim encryptClaim = new Claim("Data", encrSerializeObject);
                    Claim userClaim = new Claim("User", serializeObject);
                    //identity = new ClaimsIdentity(new[] {
                    //    new Claim(ClaimTypes.Name,User.Username),
                    //    encryptClaim
                    //}, "auth_type");
                    identity = new ClaimsIdentity(new[] {
                        new Claim(ClaimTypes.Name,User.Username),
                        encryptClaim,
                        userClaim
                    }, "auth_type");

                } else {
                    //time session closed
                    identity = new ClaimsIdentity();
                }
            } else {
               identity = new ClaimsIdentity();
                //identity = null;
            }

            var user = new ClaimsPrincipal(identity);
            if (!user.Identity.IsAuthenticated) {
                NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
                
            }
            return await Task.FromResult(new AuthenticationState(user));
        }

  


        /// <summary>
        /// si notifica il cambiamento di stato, l utente é autentificato
        /// </summary>
        /// <param name="email"></param>
        public void MarkAuthenticationStateChanged(string username) {
            UserLogged userLogged = _userService.GetUserLogged(username);
            userLogged.Expired_date = DateTime.Now.AddDays(_exp_date);
            var serializeObject = JsonConvert.SerializeObject(userLogged);
            var encrSerializeObject = Utility.Encrypt(serializeObject);
            


            Claim encryptClaim = new Claim("Data", encrSerializeObject);
            Claim userClaim = new Claim("User", serializeObject);
            var identity = new ClaimsIdentity(new[] {
                new Claim(ClaimTypes.Name,userLogged.Username),
                encryptClaim,
                userClaim
            }, "auth_type");

            var user = new ClaimsPrincipal(identity);

            NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
            _sessionStorageService.SetItemAsync("User", encrSerializeObject);
        }


        /// <summary>
        /// si notifica il cambiamento di stato, l utente é autentificato
        /// </summary>
        /// <param name="email"></param>
        public void MarkAuthenticationStateChanged(UserLogged userLogged, string encrSerializeObject, string serializeObject) {


            Claim encryptClaim = new Claim("Data", encrSerializeObject);
            Claim userClaim = new Claim("User", serializeObject);
            var identity = new ClaimsIdentity(new[] {
                new Claim(ClaimTypes.Name,userLogged.Username),
                encryptClaim,
                userClaim
            }, "auth_type");

            var user = new ClaimsPrincipal(identity);

            NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
        }


        public void MarkUserAsLoggedOut() {

            _sessionStorageService.RemoveItemAsync("User");

            var identity = new ClaimsIdentity();

            var user = new ClaimsPrincipal(identity);

            NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
        }


    }

CustomActionHandler.cs

    public class CustomActionHandler : AuthorizationHandler<CustomActionRequirement> {


        protected  override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomActionRequirement requirement) {

            if (!context.User.HasClaim(c => c.Type == "User")) {
                return Task.CompletedTask;
            }
            var user = context.User.FindFirst(c => c.Type == "User").Value;
            

            if (user != null) {
                var userLogged = JsonConvert.DeserializeObject<UserLogged>(user);
                if (userLogged.Actions.Contains(requirement.authorized_Action)) {
                    context.Succeed(requirement);
                }
            }
            return Task.CompletedTask;
        }
    }


Startup.cs


            //custom auth
            services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();

            //custom policy for AuthorizeView Policy for action

            foreach (Authorized_action action in Enum.GetValues(typeof(Authorized_action))) {
                services.AddAuthorization(options => {
                    options.AddPolicy(action.ToString(), policy =>
                        policy.Requirements.Add(new CustomActionRequirement(action)));
                });
            }
            services.AddSingleton<IAuthorizationHandler, CustomActionHandler>();



...

            app.UseAuthentication();
            app.UseAuthorization();


MainLayout.razor

    <AuthorizeView>
        <Authorized>

            <MudLayout>
                <MudAppBar Elevation="1">
                    <MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
                    <MudText Typo="Typo.h5" Class="ml-3">Application</MudText>
                </MudAppBar>
                <MudDrawer @bind-Open="_drawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2">
                    <NavMenu />
                </MudDrawer>
                <MudMainContent>
                    <MudContainer Class="mt-16 px-8" MaxWidth="MaxWidth.False">
                        @Body
                    </MudContainer>
                </MudMainContent>
            </MudLayout>

        </Authorized>
        <NotAuthorized>
            @if (true) { NavManager.NavigateTo(""); }
        </NotAuthorized>
    </AuthorizeView>

0 个答案:

没有答案