从零开始Blazor Server(9)–修改Layout

虚幻大学 xuhss 180℃ 0评论

? 优质资源分享 ?

学习路线指引(点击解锁) 知识定位 人群定位
? Python实战微信订餐小程序 ? 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
?Python量化交易实战? 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

目前我们的MainLayout还是默认的,这里我们需要修改为BootstrapBlazor的Layout,并且处理一下菜单。

修改MainLayout

BootstrapBlazor已经自带了一个Layout组件,这个组件里常用功能已经很全了,所以我们直接使用这个组件即可。

<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">BlazorLearnspan>
        <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>BlazorLearnspan>
                div>
            div>
        Side>
    <Main>
 <CascadingValue Value="this" IsFixed="true">
 @Body
 CascadingValue>
    Main>
    <Footer>
 <div class="text-center flex-fill">
 <a href="/" target="\_blank">BlazorLearna>
        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;
    }
}

这里没什么需要多说的,每个参数的意义在文档里都比较清楚,如果需要查询具体的含义,可以看这里

这里需要注意的是,Menus里面必须要定义一个变量,不能直接放一个方法,否则此方法每次跳转都会执行,导致菜单不正常。

另外Logout是一个独立的组件,这个组件其实叫Logout并不贴切,它是一个带有头像,欢迎信息以及下拉菜单的用户信息组件。

这里我们只放一个LogoutLink登出菜单。

修改AdminHandler

如果你直接启动项目,会发现Layout不见了,因为我们的Layout里面做了比较多的处理,会有一个需要权限验证的请求。这个请求不会携带Resource,所以不会返回true。就导致Layout一直不显示,所以我们需要处理这种情况,我们目前修改为Resource里不是RouteData的全部都通过验证。

    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);
    }

这样我们再启动应该就可以看到Layout了。

修改LoginController

我们之前只有一个登录,所以我们写了一个LoginController,现在我们需要加入登出,所以我们直接把LoginController改为AccountController,然后内容改为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 GetLogout()
    {
        await Furion.App.HttpContext.SignOutAsync();
        return new RedirectResult("/Login");
    }
}

这里我们直接给Logout[Authorize],只有登录以后才能访问。

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

转载请注明:xuhss » 从零开始Blazor Server(9)–修改Layout

喜欢 (0)

您必须 登录 才能发表评论!