当前位置:网站首页>Blazor Server (9) from scratch -- modify Layout

Blazor Server (9) from scratch -- modify Layout

2022-08-09 11:44:00 jvx

目前我们的MainLayout还是默认的,Here we need to modify to BootstrapBlazor的Layout,And deal with the menu.

修改MainLayout

BootstrapBlazor已经自带了一个Layout组件,The commonly used functions in this component are already very complete,So we can use this component directly.

<Layout SideWidth="0" IsPage="true" IsFullSide="true" IsFixedHeader="true" IsFixedFooter="true"
        ShowFooter="true" ShowCollapseBar="true" OnCollapsed="@OnCollapsed" Menus="@_menuItems">
    <Header>
            <span class="ms-3 flex-sm-fill d-none d-sm-block">BlazorLearn</span>
        <div class="flex-fill d-sm-none">
        </div>
        <Logout ImageUrl="images/argo-c.png" DisplayName="@_user.Name" UserName="@_user.UserName">
                    <LinkTemplate>
                        <LogoutLink Url="/api/account/logout"></LogoutLink>
                    </LinkTemplate>
                </Logout>
    </Header>
    <Side>
            <div class="layout-banner">
                <img class="layout-logo" src="images/Argo.png" />
                <div class="layout-title">
                    <span>BlazorLearn</span>
                </div>
            </div>
        </Side>
    <Main>
        <CascadingValue Value="this" IsFixed="true">
            @Body
        </CascadingValue>
    </Main>
    <Footer>
        <div class="text-center flex-fill">
            <a href="/" target="_blank">BlazorLearn</a>
        </div>
    </Footer>
</Layout>

@code
{
    private bool IsCollapsed { get; set; }
    
    private List<MenuItem>? _menuItems;

    [NotNull]
    private UserEntity? _user;
    
    private Task OnCollapsed(bool collapsed)
    {
        IsCollapsed = collapsed;
        return Task.CompletedTask;
    }
    
    protected override void OnInitialized()
    {
        base.OnInitialized();
        _user = UserEntity.Where(x => x.UserName == Furion.App.User.FindFirstValue(ClaimTypes.Name)).First();
        if (_user == null)
        {
            return;
        }
        _menuItems = CreateMenuItems(MenuEntity.Where(x => x.Roles!.Any(y => y.Id == _user.RoleId)).ToList(), 0);
    }

    private List<MenuItem> CreateMenuItems(List<MenuEntity> menus, int parentId)
    {
        var selectedMenus = new List<MenuItem>();
        var selectedMenuEntities = menus.Where(x => x.ParentId == parentId).ToList();

        foreach (var menuEntity in selectedMenuEntities)
        {
            var menuItem = new MenuItem(menuEntity.Name!, menuEntity.Url, menuEntity.Icon);
            menuItem.Items = CreateMenuItems(menus, menuEntity.Id);
            selectedMenus.Add(menuItem);
        }
        return selectedMenus;
    }
}

There's not much to say here,The meaning of each parameter is clear in the documentation,If you need to inquire about the specific meaning,可以看这里.


这里需要注意的是,MenusThere must be a variable defined in it,A method cannot be placed directly,Otherwise this method will execute every jump,cause the menu to be abnormal.


另外Logout是一个独立的组件,This component is actually called Logout并不贴切,It's one with an avatar,The welcome message and the user information component of the drop-down menu.


Here we only put oneLogoutLinklogout menu.

修改AdminHandler

If you start the project directly,会发现Layout不见了,因为我们的LayoutThere is a lot more processing in there,There will be a request that requires permission verification.This request will not carryResource,所以不会返回true.就导致Layout一直不显示,So we need to handle this situation,We currently modify it toResource里不是RouteDataAll are verified.

    public override Task<bool> PipelineAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext)
    {
        if (!int.TryParse(context.User.FindFirst(ClaimTypes.Role)?.Value, out var roleId))
        {
            return Task.FromResult(false);
        }
        if (context.Resource is RouteData routeData)
        {
            var routeAttr = routeData.PageType.CustomAttributes.FirstOrDefault(x =>
                x.AttributeType == typeof(RouteAttribute));
            if (routeAttr == null)
            {
                return Task.FromResult(true);
            }
            else
            {
                var url = routeAttr.ConstructorArguments[0].Value as string;
                var permission = MenuEntity
                    .Where(x => x.Roles!.Any(y => y.Id == roleId) && x.Url == url).First();
                if (permission != null)
                {
                    return Task.FromResult(true);
                }
            }
        }
        else
        {
            return Task.FromResult(true);
        }
        
        return Task.FromResult(false);
    }

This way we should be able to see it when we start it againLayout了.

修改LoginController

We only had one login before,So we wrote oneLoginController,Now we need to join and log out,所以我们直接把LoginController改为AccountController,Then the content is changed to PostLoginGetLogout.

public class AccountController: IDynamicApiController
{
    public async Task<object> PostLogin([FromBody]LoginVo loginVo)
    {
        if (string.IsNullOrEmpty(loginVo.UserName))
        {
            return new { code = 50000, message = "用户名不能为空" };
        }
        if (string.IsNullOrEmpty(loginVo.Password))
        {
            return new { code = 50000, message = "密码不能为空" };
        }

        var password = MD5Encryption.Encrypt(loginVo.Password);
        var user = await UserEntity.Where(x =>
            x.UserName == loginVo.UserName && x.Password == password).Include(x => x.Role).FirstAsync();
        if (user != null)
        {
            var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
            identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName!));
            identity.AddClaim(new Claim(ClaimTypes.Role, user.Role!.Id.ToString()));
            await Furion.App.HttpContext.SignInAsync(new ClaimsPrincipal(identity), new AuthenticationProperties(){IsPersistent = true, ExpiresUtc = loginVo.RememberMe? DateTimeOffset.Now.AddDays(5): DateTimeOffset.Now.AddMinutes(30)});

            return new { code = 20000, message = "登录成功" };
        }
        return new { code = 50000, message = "用户名或密码错误" };
    }

    [Authorize]
    public async Task<IActionResult> GetLogout()
    {
        await Furion.App.HttpContext.SignOutAsync();
        return new RedirectResult("/Login");
    }
}

这里我们直接给Logout[Authorize],Access is only possible after logging in.


代码在github:https://github.com/j4587698/BlazorLearnj,分支lesson9.

原网站

版权声明
本文为[jvx]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/221/202208091128011333.html