博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
企业级工作流解决方案(十二)--集成Abp和ng-alain--用户身份认证与权限验证
阅读量:7226 次
发布时间:2019-06-29

本文共 6673 字,大约阅读时间需要 22 分钟。

多租户

  如果系统需要支持多租户,那么最好事先定义好多租户的存储部署方式,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
claims = new List
(); 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
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
CreateJwtClaims(List
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)` 获取 JWT Token */ get(type?: any): ITokenModel; /** * 获取Token,形式包括: * - `get()` 获取 Simple Token * - `get
(JWTTokenModel)` 获取 JWT Token */ get
(type?: any): T; clear(): void; change(): Observable
; /** 获取登录地址 */ 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);

控件控制

列表按钮控制

{              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: 
{ability: ['operate-mgt']} }}, // 操作管理

 

转载于:https://www.cnblogs.com/spritekuang/p/10818858.html

你可能感兴趣的文章
sofa-pbrpc高级用法
查看>>
Oracle 函数返回表实例2种写法实例
查看>>
mysql数据库主从复制
查看>>
Shell标准输出、标准错误 >/dev/null 2>&1
查看>>
Android自定义对话框(Dialog)位置,大小
查看>>
设置python的默认编码为utf8
查看>>
简易sqlhelper-java
查看>>
通过案例对SparkStreaming 透彻理解三板斧之一:解密SparkStreaming运行机制
查看>>
HBuilder 学习笔记
查看>>
利用OpenStreetMap(OSM)数据搭建一个地图服务
查看>>
TopN算法与排行榜
查看>>
lucene排序算法之向量空间模型(一)
查看>>
新浪微博数据Json格式解析
查看>>
WLAN 802.11 wifl区别
查看>>
oracle授权动态视图权限给用户
查看>>
Debian – 出现-bash: pip: command not found错误解决办法
查看>>
Zxing扫描二维码
查看>>
我的友情链接
查看>>
aspcms后台拿shell漏洞(非添加模块)及修复方法
查看>>
C语言冒泡排序法
查看>>