教程目錄html
從零開始啓動Osharp前端
1.1. 使用OsharpNS項目模板建立項目git
1.2. 配置數據庫鏈接串並啓動項目github
1.3. OsharpNS.Swagger使用實例(登陸和受權)數據庫
1.4. Angular6的前端項目啓動緩存
Osharp代碼生成器的使用框架
2.1 生成器的使用async
2.2 生成代碼詳解(如何本身實現業務功能)ide
Osharp部分模塊使用學習
3.1 Osharp.Redis使用
Osharp深度學習和使用
4.2 多上下文配置(多個數據庫的使用)
4.3. 自定義模塊的定義(Senparc.Weixin的使用)
4.4. 繼續學習中....
OsharpNS官方資源
項目地址:https://github.com/i66soft/osharp-ns20
演示地址:https://www.osharp.org 直接使用QQ登陸能夠查看效果
文檔地址:https://docs.osharp.org 正在完善中....
發佈博客:https://www.cnblogs.com/guomingfeng/p/osharpns-publish.html 大神看這個文檔應該就能跑起來,從零開始啓動Osharp基於此文檔完成
VS生成器插件:https://marketplace.visualstudio.com/items?itemName=LiuliuSoft.osharp
官方交流QQ羣:85895249
系統受權檢查流程
核心代碼位於Osharp/Secutiry/FunctionAuthorizationBase
檢查過程以下:
檢查function是否爲null,爲null反饋錯誤,不然繼續檢查
檢查function是否被禁用,被禁用反饋錯誤,不然繼續檢查
檢查功能是否任何人可用,若是是,直接返回成功,不然繼續檢查
檢查用戶是否登錄,未登陸反饋錯誤,不然繼續檢查
用戶已登錄,判斷功能是否登錄便可使用,若是是,反饋成功,不然繼續檢查
獲取用戶的角色,判斷角色是否有角色容許執行功能,若是是,反饋成功,不然繼續檢查
獲取用戶能執行的全部功能,判斷是否包含功能,若是是,反饋成功;若是否,反饋失敗(系統除了給定用戶角色,還能根據用戶單獨給定功能受權,因此檢查完角色以後不知足條件,還要檢查用戶私有的功能是否包含)
/// <summary> /// 重寫以實現權限檢查覈心驗證操做 /// </summary> /// <param name="function">要驗證的功能信息</param> /// <param name="principal">當前用戶在線信息</param> /// <returns>功能權限驗證結果</returns> protected virtual AuthorizationResult AuthorizeCore(IFunction function, IPrincipal principal) { if (function == null) { return new AuthorizationResult(AuthorizationStatus.NoFound); } if (function.IsLocked) { return new AuthorizationResult(AuthorizationStatus.Locked, $"功能「{function.Name}」已被禁用,沒法執行"); } if (function.AccessType == FunctionAccessType.Anonymouse) { return AuthorizationResult.OK; } //未登陸 if (principal == null || !principal.Identity.IsAuthenticated) { return new AuthorizationResult(AuthorizationStatus.Unauthorized); } //已登陸,無角色限制 if (function.AccessType == FunctionAccessType.Logined) { return AuthorizationResult.OK; } return AuthorizeRoleLimit(function, principal); } /// <summary> /// 重寫以實現 角色限制 的功能的功能權限檢查 /// </summary> /// <param name="function">要驗證的功能信息</param> /// <param name="principal">用戶在線信息</param> /// <returns>功能權限驗證結果</returns> protected virtual AuthorizationResult AuthorizeRoleLimit(IFunction function, IPrincipal principal) { //角色限制 if (!(principal.Identity is ClaimsIdentity identity)) { return new AuthorizationResult(AuthorizationStatus.Error, "當前用戶標識IIdentity格式不正確,僅支持ClaimsIdentity類型的用戶標識"); } //檢查角色-功能的權限 string[] userRoleNames = identity.GetRoles().ToArray(); AuthorizationResult result = AuthorizeRoleNames(function, userRoleNames); if (result.IsOk) { return result; } result = AuthorizeUserName(function, principal.Identity.GetUserName()); return result; } /// <summary> /// 重寫以實現指定角色是否有執行指定功能的權限 /// </summary> /// <param name="function">功能信息</param> /// <param name="roleNames">角色名稱</param> /// <returns>功能權限檢查結果</returns> protected virtual AuthorizationResult AuthorizeRoleNames(IFunction function, params string[] roleNames) { Check.NotNull(roleNames, nameof(roleNames)); if (roleNames.Length == 0) { return new AuthorizationResult(AuthorizationStatus.Forbidden); } if (function.AccessType != FunctionAccessType.RoleLimit || roleNames.Contains(SuperRoleName)) { return AuthorizationResult.OK; } string[] functionRoleNames = FunctionAuthCache.GetFunctionRoles(function.Id); if (roleNames.Intersect(functionRoleNames).Any()) { return AuthorizationResult.OK; } return new AuthorizationResult(AuthorizationStatus.Forbidden); } /// <summary> /// 重寫以實現指定用戶是否有執行指定功能的權限 /// </summary> /// <param name="function">功能信息</param> /// <param name="userName">用戶名</param> /// <returns>功能權限檢查結果</returns> protected virtual AuthorizationResult AuthorizeUserName(IFunction function, string userName) { if (function.AccessType != FunctionAccessType.RoleLimit) { return AuthorizationResult.OK; } Guid[] functionIds = FunctionAuthCache.GetUserFunctions(userName); if (functionIds.Contains(function.Id)) { return AuthorizationResult.OK; } return new AuthorizationResult(AuthorizationStatus.Forbidden); }
Controller裏面對是否檢查權限的控制
文件路徑爲CanDoo.Test.Web.Areas.Admin.Controllers
,注意看文件中的[RoleLimit]
,帶了這個就要作檢查
// ----------------------------------------------------------------------- // <copyright file="AdminApiController.cs" company="OSharp開源團隊"> // Copyright (c) 2014-2018 OSharp. All rights reserved. // </copyright> // <site>http://www.osharp.org</site> // <last-editor>郭明鋒</last-editor> // <last-date>2018-06-27 4:50</last-date> // ----------------------------------------------------------------------- using Microsoft.AspNetCore.Mvc; using OSharp.AspNetCore.Mvc; using OSharp.Core; namespace CanDoo.Test.Web.Areas.Admin.Controllers { [Area("Admin")] [RoleLimit] public abstract class AdminApiController : AreaApiController { } }
不經過數據庫強制給定用戶角色的方法
3.1 經過Claim實現
在`IdentityController.cs`中,用戶登錄後,生成Claim時,將角色給定
private async Task<string> CreateJwtToken(User user) { //在線用戶緩存 IOnlineUserCache onlineUserCache = HttpContext.RequestServices.GetService<IOnlineUserCache>(); if (onlineUserCache != null) { await onlineUserCache.GetOrRefreshAsync(user.UserName); } //生成Token,這裏只包含最基本信息,其餘信息從在線用戶緩存中獲取 Claim[] claims = { new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), new Claim(ClaimTypes.Name, user.UserName), new Claim("ExtendRoles", "學生") //這行是新增的,強制給定學生角色,用戶角色表中不存在 用戶和學生 角色的關聯 }; OsharpOptions options = HttpContext.RequestServices.GetService<IOptions<OsharpOptions>>().Value; string token = JwtHelper.CreateToken(claims, options); return token; }
在`CanDoo.Test.Core`中新建類`OnlineUserJwtSecurityTokenHandler.cs`
// ----------------------------------------------------------------------- // <copyright file="OnlineUserJwtSecurityTokenHandler.cs" company="OSharp開源團隊"> // Copyright (c) 2014-2018 OSharp. All rights reserved. // </copyright> // <site>http://www.osharp.org</site> // <last-editor>郭明鋒</last-editor> // <last-date>2018-07-09 15:01</last-date> // ----------------------------------------------------------------------- using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using Microsoft.IdentityModel.Tokens; using OSharp.Collections; using OSharp.Dependency; using OSharp.Identity; using OSharp.Secutiry.Claims; namespace CanDoo.Test.Identity { /// <summary> /// 使用在線用戶信息和JwtToken生成在線ClaimsIdentity /// </summary> public class OnlineUserJwtSecurityTokenHandler : JwtSecurityTokenHandler { /// <summary> /// Creates a <see cref="T:System.Security.Claims.ClaimsIdentity" /> from a <see cref="T:System.IdentityModel.Tokens.Jwt.JwtSecurityToken" />. /// </summary> /// <param name="jwtToken">The <see cref="T:System.IdentityModel.Tokens.Jwt.JwtSecurityToken" /> to use as a <see cref="T:System.Security.Claims.Claim" /> source.</param> /// <param name="issuer">The value to set <see cref="P:System.Security.Claims.Claim.Issuer" /></param> /// <param name="validationParameters"> Contains parameters for validating the token.</param> /// <returns>A <see cref="T:System.Security.Claims.ClaimsIdentity" /> containing the <see cref="P:System.IdentityModel.Tokens.Jwt.JwtSecurityToken.Claims" />.</returns> protected override ClaimsIdentity CreateClaimsIdentity(JwtSecurityToken jwtToken, string issuer, TokenValidationParameters validationParameters) { ClaimsIdentity identity = base.CreateClaimsIdentity(jwtToken, issuer, validationParameters); var extendRoles = identity.GetClaimValueFirstOrDefault("ExtendRoles");//從Claim中獲取強制給定的角色 if (identity.IsAuthenticated) { //由在線緩存獲取用戶信息賦給IIdentity IOnlineUserCache onlineUserCache = ServiceLocator.Instance.GetService<IOnlineUserCache>(); OnlineUser user = onlineUserCache.GetOrRefresh(identity.Name); if (user == null) { return null; } if (!string.IsNullOrEmpty(user.NickName)) { identity.AddClaim(new Claim(ClaimTypes.GivenName, user.NickName)); } if (!string.IsNullOrEmpty(user.Email)) { identity.AddClaim(new Claim(ClaimTypes.Email, user.Email)); } //這部分將從Claim中獲取的角色進行賦值 string roles = ""; if (user.Roles.Length > 0) roles = user.Roles.ExpandAndToString() + "," + extendRoles; else roles = extendRoles; if (roles != "") identity.AddClaim(new Claim(ClaimTypes.Role, user.Roles.ExpandAndToString())); } ScopedDictionary dict = ServiceLocator.Instance.GetService<ScopedDictionary>(); dict.Identity = identity; return identity; } } }
對`CanDoo.Test.Core`中`IdentityPack`中的代碼進行調整
jwt.SecurityTokenValidators.Clear(); jwt.SecurityTokenValidators.Add(new OnlineUserJwtSecurityTokenHandler());//這裏要使用本文中建立的OnlineUserJwtSecurityTokenHandler jwt.Events = new JwtBearerEvents() { // 生成SignalR的用戶信息 OnMessageReceived = context => { string token = context.Request.Query["access_token"]; string path = context.HttpContext.Request.Path; if (!string.IsNullOrEmpty(token) && path.Contains("hub")) { context.Token = token; } return Task.CompletedTask; } };
3.2 經過替換現有OnlineUserProvider緩存方法實現
在`CanDoo.Test.Core`中新建`MyOnlineUserProvider`
// ----------------------------------------------------------------------- // <copyright file="OnlineUserProvider.cs" company="OSharp開源團隊"> // Copyright (c) 2014-2018 OSharp. All rights reserved. // </copyright> // <site>http://www.osharp.org</site> // <last-editor>郭明鋒</last-editor> // <last-date>2018-08-17 22:36</last-date> // ----------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using OSharp.Identity; namespace CanDoo.Test.Identity { /// <summary> /// 在線用戶信息提供者 /// </summary> public class MyOnlineUserProvider<TUser, TUserKey, TRole, TRoleKey> : IOnlineUserProvider where TUser : UserBase<TUserKey> where TUserKey : IEquatable<TUserKey> where TRole : RoleBase<TRoleKey> where TRoleKey : IEquatable<TRoleKey> { /// <summary> /// 建立在線用戶信息 /// </summary> /// <param name="provider">服務提供器</param> /// <param name="userName">用戶名</param> /// <returns>在線用戶信息</returns> public virtual async Task<OnlineUser> Create(IServiceProvider provider, string userName) { UserManager<TUser> userManager = provider.GetService<UserManager<TUser>>(); TUser user = await userManager.FindByNameAsync(userName); if (user == null) { return null; } IList<string> roles = await userManager.GetRolesAsync(user); roles.Add("學生");//這樣就強制給用戶賦值了,固然能夠對其餘東西也作手腳 RoleManager<TRole> roleManager = provider.GetService<RoleManager<TRole>>(); bool isAdmin = roleManager.Roles.Any(m => roles.Contains(m.Name) && m.IsAdmin); return new OnlineUser() { Id = user.Id.ToString(), UserName = user.UserName, NickName = user.NickName, Email = user.Email, HeadImg = user.HeadImg, IsAdmin = isAdmin, Roles = roles.ToArray() }; } } }
對`CanDoo.Test.Core`中的`IdentityPack`修改代碼,將原有的`OnlineUserProvider`換爲`MyOnlineUserProvider`
/// <summary> /// 將模塊服務添加到依賴注入服務容器中 /// </summary> /// <param name="services">依賴注入服務容器</param> /// <returns></returns> public override IServiceCollection AddServices(IServiceCollection services) { services.AddScoped<IIdentityContract, IdentityService>(); base.AddServices(services); services.Replace(new ServiceDescriptor(typeof(IOnlineUserProvider), typeof(MyOnlineUserProvider<User, int, Role, int>), ServiceLifetime.Scoped)); return services; }