目前我们的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">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="data: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;
}
}

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

这里需要注意的是,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<IActionResult> GetLogout()
{
await Furion.App.HttpContext.SignOutAsync();
return new RedirectResult("/Login");
}
}

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

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

从零开始Blazor Server(9)--修改Layout的更多相关文章

  1. 从零开始Blazor Server(14)--修改密码

    目前,我们只做了在用户管理里强行修改密码,而没有做用户自行修改密码的功能,今天我们来实现它. 首先,我们的用户密码修改最好的位置应该就是在头像下面的下拉菜单里,所以我们在那里的LinkTemplate ...

  2. 从零开始Blazor Server(1)--项目搭建

    项目介绍 本次项目准备搭建一个使用Furion框架,Blazor的UI使用BootstrapBlazor.数据库ORM使用Freesql的后台管理系统. 目前的规划是实现简单的注册,登录.增加管理员跟 ...

  3. 从零开始Blazor Server(3)--添加cookie授权

    认证方式简述 Blazor Server微软官方还是推荐直接使用Cookie授权,因为本来Blazor Server就是前后端不分离的.不存在Cookie跨域等一系列问题. 只要不是使用SSO之类的统 ...

  4. 从零开始Blazor Server(15)--总结

    我们用了14篇文章,基本上把一个后台管理系统需要的UI部分都说的差不多了.所以这套文章也该到了结束的时候了. 这里面有很多问题,比如我们直接使用UI来拉数据库信息而没有使用service,再比如我们大 ...

  5. 从零开始Blazor Server(6)--基于策略的权限验证

    写这个的原因 现在BootstrapBlazor处于大更新时期,Menu组件要改为泛型模式. 本来我们的这一篇应该是把Layout改了,但是改Layout肯定要涉及到菜单,如果现在写了呢,就进入一个发 ...

  6. 从零开始Blazor Server(4)--登录系统

    说明 上一篇文章中我们添加了Cookie授权,可以跳转到登录页了.但是并没有完成登录,今天我们来完成它. 我们添加Cookie授权的时候也说了,这套跟MVC一模一样,所以我们登录也是跟MVC一模一样. ...

  7. 从零开始Blazor Server(5)--权限验证

    序 之前我们一直使用的是微软自带的身份验证方式,即使用[Authorize]标签来做. 但是这种方式十分不灵活,微软推荐的方式是加Policy,但是这种方式对我们来说还是不够灵活. 所以本节我们用完全 ...

  8. 从零开始Blazor Server(8)--增加菜单以及调整位置

    这篇干啥 这篇文章主要是把前面的一些东西稍微调整一下,使其更适合后面的内容. 主要是两个事,一个是把原来的PermissionEntity直接变成MenuEntity,直接让最后一级是菜单,这样后面就 ...

  9. 从零开始Blazor Server(10)--编辑角色

    例图 目前的样式是这样的: 其中角色在一个table里,然后可以增删改查,并且可以给指定的用户分配权限. 创建文件 首先我们在Pages/Admin目录下新建一个Role.razor.因为我们的Adm ...

随机推荐

  1. CSS中html的标签元素分类

    在CSS中,html中的标签元素大体被分为三种不同的类型: 块状元素.内联元素(又叫行内元素)和内联块状元素.    常用的块状元素有:  <div>.<p>.<h1&g ...

  2. JavaScript中的??和?.和??=操作符

    JS中两种不常使用但挺实用的操作符:??和?. 一起来了解并学会使用它们吧: 空值合并操作符:?? 只有当操作符左侧为null或undefined时才会返回操作符右侧的值,否则返回左侧的值. eg: ...

  3. 什么是Gerber文件?PCB电路板Gerber文件简介

    什么是Gerber文件: Gerber也叫"光绘",通常只代表一种格式如RS-274, 274D, 274X等,充任了将设计的图形数据转换成PCB制造的两头媒介,即一种CAD-CA ...

  4. Hyperledger Fabric 智能合约开发及 fabric-sdk-go/fabric-gateway 使用示例

    前言 在上个实验 Hyperledger Fabric 多组织多排序节点部署在多个主机上 中,我们已经实现了多组织多排序节点部署在多个主机上,但到目前为止,我们所有的实验都只是研究了联盟链的网络配置方 ...

  5. 在海思芯片上使用GDB远程调试

    1 前言 使用海思平台上(编译工具链:arm-himix200-linux)交叉编译 GDB 工具(使用版本8.2,之前用过10.2的版本,在编译 gdbserver 遇到编译出错的问题,因为关联了其 ...

  6. WAVE音频格式及及转换代码

    音频信号的读写.播放及录音 python已经支持WAV格式的书写,而实时的声音输入输出需要安装pyAudio(http://people.csail.mit.edu/hubert/pyaudio).最 ...

  7. 31.Squid缓存代理服务器应用

    Squid缓存代理服务器应用 Squid安装介绍 web缓存的工作机制 缓存网页对象,减少重复请求 squid 主要提供缓存加速.应用层过滤控制的功能. 工作机制 代替客户机问网站请求数据,从而可以隐 ...

  8. 26.MySQL数据库基础

    MySQL数据库基础 目录 MySQL数据库基础 数据库的概念 数据 表 数据库 数据库的管理系(DBMS) 数据库系统 访问数据库的流程 数据库系统发展史 当今主流数据库介绍 关系数据库 关系数据库 ...

  9. 雪花算法及微服务集群唯一ID解决方案

    雪花算法(SnowFlake) 简介 现在的服务基本是分布式.微服务形式的,而且大数据量也导致分库分表的产生,对于水平分表就需要保证表中 id 的全局唯一性. 对于 MySQL 而言,一个表中的主键 ...

  10. SAP APO-供应链监控

    供应链监控(SCM)是一种有效的工具,可以为供应商和购买者做出明智的决策. 供应链流程中的关键人物基于供应链监控做出决策. 供应链包括两个工具- 库存需求清单MD04 物流信息系统(LIS) 事务MD ...