多租户

  如果系统需要支持多租户,那么最好事先定义好多租户的存储部署方式,Abp提供了几种方式,根据需要选择,每一个用户身份认证与权限验证都需要完全的隔离

  这里设计的权限数据全部存储在缓存中,每个租户单独建立缓存Key,见权限系统服务章节介绍。

用户accesstoken

  accesstoken的定义就不多的介绍了,Abp其实就是直接使用微软IdentityModel这套组件,并且zero项目还直接使用的微软的用户角色相关管理,这里面性能存在一定的问题,而且使用相对比较复杂,还不利于扩展,其实功能就那么一些,完全没有必要用这一套用户角色管理。

  其实这里要做的核心扩展,就是自定义Claim信息,accesstoken信息其实是存在Claim集合里面的,我们可以自定义Claim信息,用户登录的时候,调用组件提供的接口,创建用户访问的accesstoken信息,我这里扩展了RoleIds集合信息和UserName信息,UserName在系统很多地方都可能用到,而RoleIds集合信息用于做权限控制。

  实现代码

public class AuthTokenProvider: IAuthTokenProvider
{
private readonly TokenAuthConfiguration _configuration;
public AuthTokenProvider(TokenAuthConfiguration configuration)
{
_configuration = configuration;
}
public AuthenticateResultModel Authenticate(LoginResultModel loginResultModel)
{
List<Claim> claims = new List<Claim>();
claims.Add(new Claim(AbpClaimTypes.UserId, loginResultModel.UserId.ToString()));
if (loginResultModel.TenantId.HasValue)
{
claims.Add(new Claim(AbpClaimTypes.TenantId, loginResultModel.TenantId.ToString()));
}
claims.Add(new Claim(AbpClaimTypes.RoleIds, loginResultModel.RoleIds)); // 自定义RoleIds和UserName申明
claims.Add(new Claim(AbpClaimTypes.UserName, loginResultModel.UserName)); var accessToken = CreateAccessToken(claims); return new AuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncrpyedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds,
UserId = loginResultModel.UserId
};
} private string CreateAccessToken(IEnumerable<Claim> claims, TimeSpan? expiration = null)
{
var now = DateTime.UtcNow; var jwtSecurityToken = new JwtSecurityToken(
issuer: _configuration.Issuer,
audience: _configuration.Audience,
claims: claims,
notBefore: now,
expires: now.Add(expiration ?? _configuration.Expiration),
signingCredentials: _configuration.SigningCredentials
); return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
} private static List<Claim> CreateJwtClaims(List<Claim> claims)
{
var nameIdClaim = claims.First(c => c.Type == ClaimTypes.NameIdentifier); // Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
claims.AddRange(new[]
{
//new Claim(JwtRegisteredClaimNames.Sub, nameIdClaim.Value),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
}); return claims;
} private string GetEncrpyedAccessToken(string accessToken)
{
return SimpleStringCipher.Instance.Encrypt(accessToken, CoreModule.DefaultPassPhrase);
}
}

Ng-alain前端页面Token

  ng-alain前端页面也有权限管理,主要是delon项目里面的权限管理,核心其实也是在Token的管理,ITokenService,定义了管理Token的接口,ITokenModel定义了token和一个自定义存储的数据字典,在路由拦截的时候,添加了对Token是否为空的验证,我们在登录的时候,对token进行赋值,退出登录清空token。

  默认Token是存储在LocalStorage里面的,根据需要,可以改为SessionStorage。

  用户登录

/**
* 登录结果回调
* @param authenticateResult 登录结果
*/
private processAuthenticateResult(authenticateResult: AuthenticateResultModel) {
if (authenticateResult.accessToken) {
// 设置用户Token信息
this.tokenService.set({
token: authenticateResult.accessToken, userId: authenticateResult.userId
, expireInSeconds: authenticateResult.expireInSeconds,encryptedAccessToken:authenticateResult.encryptedAccessToken
});
// 重新获取 StartupService 内容,我们始终认为应用信息一般都会受当前用户授权范围而影响
this.startupSrv.load().then(() => {
let url = this.tokenService.referrer.url || '/';
if (url.includes('/passport')) url = '/';
this.router.navigateByUrl(url);
}); } else {
this.error = "用户名或密码错误!";
return;
}
}

退出登录

logout() {
this.tokenService.clear();
this.signalRService.CloseSignalr();
this.router.navigateByUrl(this.tokenService.login_url);
}

  ng-alain权限管理

export interface ITokenModel {
[key: string]: any;
token: string;
}
export interface AuthReferrer {
url?: string;
}
export interface ITokenService {
set(data: ITokenModel): boolean;
/**
* 获取Token,形式包括:
* - `get()` 获取 Simple Token
* - `get<JWTTokenModel>(JWTTokenModel)` 获取 JWT Token
*/
get(type?: any): ITokenModel;
/**
* 获取Token,形式包括:
* - `get()` 获取 Simple Token
* - `get<JWTTokenModel>(JWTTokenModel)` 获取 JWT Token
*/
get<T extends ITokenModel>(type?: any): T;
clear(): void;
change(): Observable<ITokenModel>;
/** 获取登录地址 */
readonly login_url: string;
/** 获取授权失败前路由信息 */
readonly referrer?: AuthReferrer;
}

http拦截

  由于Abp后端需要验证accesstoken,abp对错误信息和请求结果信息进行了封装,因此,需要替换ng-alain的http拦截器,自定义拦截器。

  自定义拦截器主要是对每一个http请求,从ITokenService里面获取token,添加到请求Header里面;以及对答复内容,提取答复内容和显示错误信息。

  添加请求Token

protected addAuthorizationHeaders(headers: HttpHeaders): HttpHeaders {
let authorizationHeaders = headers ? headers.getAll('Authorization') : null;
if (!authorizationHeaders) {
authorizationHeaders = [];
} if (!this.itemExists(authorizationHeaders, (item: string) => item.indexOf('Bearer ') == 0)) {
let token = (this.injector.get(DA_SERVICE_TOKEN) as ITokenService).get();
// let token = this._tokenService.getToken();
if (headers && token) {
headers = headers.set('Authorization', 'Bearer ' + token.token);
}
} return headers;
}

  答复内容参照abp提供的前端框架代码即可

Ng-alain前端权限验证

  也是delon项目里面的acl功能模块,只需要在用户登录成功的时候,把用户能够访问的操作Code集合传递给acl,以及在页面使用的地方,定义权限控制的Code即可

// ACL:设置权限为全量
// this.aclService.setFull(true);
this.aclService.setAbility(res.operate);

控件控制

<button (click)="add()" acl [acl-ability]="'adminuser-add'" nz-button nzType="primary">新建</button>

列表按钮控制

{
text: '删除', type: 'del', acl:{ ability:['adminuser-delete']}, click: (item: any) => {
this.http.delete(`api/services/app/SEC_AdminUser/Delete?Id=${item.id}`).subscribe(() => this.st.reload());
}
},

路由控制

{ path: 'operate', loadChildren: './sec-operate/sec-operate.module#SecOperateModule', canActivate: [ACLGuard], data: {
guard: <ACLType>{ability: ['operate-mgt']}
}}, // 操作管理

企业级工作流解决方案(十二)--集成Abp和ng-alain--用户身份认证与权限验证的更多相关文章

  1. 企业级工作流解决方案(六)--微服务消息处理模型之与Abp集成

    身份认证传递 对于Abp比较熟悉的朋友应该对他里面的用户身份认证比较熟悉,他是通过实现微软提供的权限认证方式实现的,用户登录身份信息存储在System.Security.Claims.ClaimsPr ...

  2. JEECG 集成KiSSO单点登录实现统一身份认证

    JEECG 集成KiSSO单点登录实现统一身份认证 JEECG 如何为其他第三方系统实现统一身份认证服务,实现单点登录? 第三方系统如何对接呢? 今天为大家揭开这层面纱,让大家了解实质,使用它更快速的 ...

  3. 企业级工作流解决方案(十五)--集成Abp和ng-alain--Abp其他改造

    配置功能增强 Abp定义了各种配置接口,但是没有定义这些配置数据从哪里来,但是管理配置数据对于一个应用程序来说,是必不可少的一件事情. .net的配置数据管理,一般放在Web.config文件或者Ap ...

  4. 企业级工作流解决方案(十)--集成Abp和ng-alain--权限系统

    权限系统 应用系统离不开权限控制,权限中心不一定能抽象出所有的业务场景,这里定义的权限系统不一定能够满足所有的场景,但应该可以满足多数的业务需求. Abp的zero项目也定义了权限相关的表,但里面很多 ...

  5. 企业级工作流解决方案(十一)--集成Abp和ng-alain--权限系统服务

    权限系统主要定义为管理员增删改查权限数据,直接读取数据库,权限系统服务主要定义为供其他系统调用的权限验证接口,定义为两个不同的微服务. 权限系统有一个特点,数据变动比较小,数据量本身并不是很大,访问量 ...

  6. 企业级工作流解决方案(十四)--集成Abp和ng-alain--自动化脚本

    对于.net方向,做过自动化的,应该没有人不熟悉msbuild吧,非常强大的代码编译工具,.net平台的编译工作都是交给他来完成的,包括.net core的命令,本质上都是调用msbuild来执行的 ...

  7. 企业级工作流解决方案(十三)--集成Abp和ng-alain--数据库读写分离

    说到程序里面数据库管理,无非就是两件事情,一是数据库操作,对于数据库的操作,各种程序语言都有封装,也就是所谓的ORM框架,.net 方向一般用得比较多和就是.net framework和dapper, ...

  8. ABP源码分析三十二:ABP.SignalR

    Realtime Realtime是ABP底层模块提供的功能,用于管理在线用户.它是使用SignalR实现给在线用户发送通知的功能的前提 IOnlineClient/OnlineClient: 封装在 ...

  9. SpringCloud微服务实战——搭建企业级开发框架(十二):OpenFeign+Ribbon实现负载均衡

      Ribbon是Netflix下的负载均衡项目,它主要实现中间层应用程序的负载均衡.为Ribbon配置服务提供者地址列表后,Ribbon就会基于某种负载均衡算法,自动帮助服务调用者去请求.Ribbo ...

随机推荐

  1. Windos--jar包注册成服务

    1.下载资源 链接: https://pan.baidu.com/s/16asJXGudsRN23Rwra_qGZw 提取码: w2gv 解压后有五个文件 1.1注意事项 1.把你的生成的jar包放入 ...

  2. RPM与YUM使用

    1.RPM 1.1RPM简介 RPM全名RedHat Package Manager 优点: 1. 由于已经编译完成并且打包完毕,所以软件传输与安装上很方便 (不需要再重新编译): 2. 由于软件的信 ...

  3. 构造函数原理 - Js对象

    构造函数内部原理 有new之后,函数变成构造函数,产生三步隐式变化 1.函数执行,在函数体顶端隐式加上var this = {}; 2.执行赋值,AO{ this : {name:'zhangsan' ...

  4. 前端-jstree 一些常用功能

    最近使用到了jstree(v3.3.4)这个插件(官网:https://www.jstree.com/),在这里记录下我的使用过程的一些技巧和问题. 1. 获取数据 一般实际项目中用到的数据都是aja ...

  5. TypeScript魔法堂:枚举的超实用手册

    前言 也许前端的同学会问JavaScript从诞生至今都没有枚举类型,我们不是都活得挺好的吗?为什么TypeScript需要引入枚举类型呢? 也许被迫写前端的后端同学会问,TypeScript的枚举类 ...

  6. 简单粗暴套娃模式组json发送https请求

    各位童鞋大家好,向来简单粗暴的铁柱兄给大家来玩一手套娃模式来组Json数据,不说别的,无脑套. 当然,这一手比较适合临场用一下,若长期用的话建议搞一套适用的框架,只管set就好了.话不多说开始上课. ...

  7. Python的Opencv库怎么装

    原文章写于时间2019.4 当时鼓捣Opencv库弄了好长时间,前前后后弄了五天,找了好多帖子不知道删除重装了多少次,现在把我试出来正确的方法给大家分享一下. 1.Pycharm 我用的是win10系 ...

  8. Scrapy加Redis加IP代理池实现音乐爬虫

    音乐爬虫 关注公众号"轻松学编程"了解更多. 目的:爬取歌名,歌手,歌词,歌曲url. 一.创建爬虫项目 创建一个文件夹,进入文件夹,打开cmd窗口,输入: scrapy star ...

  9. 关于maven下,lombok的安装

    1.首先下载lombok的jar包,可至https://mvnrepository.com/下载 2.双击即会自动扫描eclipse.exe,如图: 选择eclipse.exe,点击install/u ...

  10. JS中使用for-each遍历数组

    1 let array = [1, 3, 6, 8, 9, 0, 5]; 2 /* 3 index是数组索引 4 value代表数组的值 5 arr是指整个数组 6 */ 7 array.forEac ...