├── .gitignore ├── webapi.sln ├── webapi.sln.DotSettings.user └── webapi ├── AutoFac ├── ContainerBuilerCommon.cs └── Modules │ └── LoggingModule.cs ├── Common ├── EncryptHelper.cs ├── Enums.cs ├── IdManager.cs └── JWTHelper.cs ├── Configs ├── Config.cs └── WebApiConfig.cs ├── ConnectionStrings.config ├── Entities ├── BaseEntity.cs ├── DB.cs ├── Permission.cs ├── Resource.cs ├── Role.cs ├── TestTable.cs ├── URM.cs └── User.cs ├── Exceptions ├── KnownException.cs └── WebApiExceptionFilterAttribute.cs ├── Global.asax ├── Global.asax.cs ├── Log4net.config ├── Microsoft.Owin.Host.HttpListener.dll ├── Microsoft.Owin.Hosting.dll ├── Microsoft.Owin.dll ├── Migrations └── Configuration.cs ├── Owin.dll ├── Owin └── Startup.cs ├── OwinHost.exe ├── Properties └── AssemblyInfo.cs ├── Security ├── IdentityBasicAuthentication.cs └── RBAuthorizeAttribute.cs ├── Services ├── AuthorizeService.cs ├── BaseService.cs ├── PermissionService.cs └── ResourceService.cs ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── example ├── EFTestController.cs ├── ExceptionTestController.cs ├── IMyLog.cs ├── IOCTestController.cs ├── LogTestController.cs ├── SecurityTestController.cs └── TestController.cs ├── packages.config ├── readme.txt ├── webapi.csproj └── webapi.csproj.user /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | /packages 4 | .vs 5 | /webapi/log 6 | /webapiTests 7 | -------------------------------------------------------------------------------- /webapi.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27004.2008 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "webapi", "webapi\webapi.csproj", "{7A63DCA6-5F3F-440A-934E-A92C162C0E82}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyOwinSelfHost", "..\MyOwinSelfHost\MyOwinSelfHost.csproj", "{1B8731CF-BEE2-4650-849C-7E5CFB9C9A1C}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "webapiTests", "webapiTests\webapiTests.csproj", "{AA7BEC9D-0524-49DA-BF74-4ACE836CEE6A}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {7A63DCA6-5F3F-440A-934E-A92C162C0E82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {7A63DCA6-5F3F-440A-934E-A92C162C0E82}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {7A63DCA6-5F3F-440A-934E-A92C162C0E82}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {7A63DCA6-5F3F-440A-934E-A92C162C0E82}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {1B8731CF-BEE2-4650-849C-7E5CFB9C9A1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {1B8731CF-BEE2-4650-849C-7E5CFB9C9A1C}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {1B8731CF-BEE2-4650-849C-7E5CFB9C9A1C}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {1B8731CF-BEE2-4650-849C-7E5CFB9C9A1C}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {AA7BEC9D-0524-49DA-BF74-4ACE836CEE6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {AA7BEC9D-0524-49DA-BF74-4ACE836CEE6A}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {AA7BEC9D-0524-49DA-BF74-4ACE836CEE6A}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {AA7BEC9D-0524-49DA-BF74-4ACE836CEE6A}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {537610E8-BBB1-40B9-AF64-A2012ECEF865} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /webapi.sln.DotSettings.user: -------------------------------------------------------------------------------- 1 |  2 | <AssemblyExplorer> 3 | <Assembly Path="D:\我的框架\webapi\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll" /> 4 | <Assembly Path="D:\我的框架\webapi\webapi\Bin\JWT.dll" /> 5 | </AssemblyExplorer> -------------------------------------------------------------------------------- /webapi/AutoFac/ContainerBuilerCommon.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Autofac; 3 | using Autofac.Integration.WebApi; 4 | using webapi.AutoFac.Modules; 5 | using webapi.example; 6 | using webapi.Entities; 7 | 8 | namespace webapi.AutoFac 9 | { 10 | public static class ContainerBuilerCommon 11 | { 12 | public static IContainer GetWebApiContainer() 13 | { 14 | var builder = new ContainerBuilder(); 15 | // 注册当前程序集里的所有webapi控制器 16 | builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); 17 | 18 | #region 注册modules 19 | builder.RegisterModule(); 20 | #endregion 21 | 22 | #region 注册组件,如果项目比较大可以从此方法里单独移出 23 | //这里写注册组件的代码 24 | builder.RegisterType(); 25 | #region 测试 26 | builder.RegisterType().As(); 27 | #endregion 28 | #endregion 29 | 30 | return builder.Build(); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /webapi/AutoFac/Modules/LoggingModule.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | using Autofac.Core; 4 | using log4net; 5 | using Module = Autofac.Module; 6 | 7 | namespace webapi.AutoFac.Modules 8 | { 9 | public class LoggingModule:Module 10 | { 11 | private static void InjectLoggerProperties(object instance) 12 | { 13 | var instanceType = instance.GetType(); 14 | 15 | // Get all the injectable properties to set. 16 | // If you wanted to ensure the properties were only UNSET properties, 17 | // here's where you'd do it. 18 | var properties = instanceType 19 | .GetProperties(BindingFlags.Public | BindingFlags.Instance) 20 | .Where(p => p.PropertyType == typeof(ILog) && p.CanWrite && p.GetIndexParameters().Length == 0); 21 | 22 | // Set the properties located. 23 | foreach (var propToSet in properties) 24 | { 25 | propToSet.SetValue(instance, LogManager.GetLogger(instanceType), null); 26 | } 27 | } 28 | 29 | private static void OnComponentPreparing(object sender, PreparingEventArgs e) 30 | { 31 | e.Parameters = e.Parameters.Union( 32 | new[] 33 | { 34 | new ResolvedParameter( 35 | (p, i) => p.ParameterType == typeof(ILog), 36 | (p, i) => LogManager.GetLogger(p.Member.DeclaringType) 37 | ), 38 | }); 39 | } 40 | 41 | protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) 42 | { 43 | // Handle constructor parameters. 44 | registration.Preparing += OnComponentPreparing; 45 | 46 | // Handle properties. 47 | registration.Activated += (sender, e) => InjectLoggerProperties(e.Instance); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /webapi/Common/EncryptHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Security.Cryptography; 6 | using System.Text; 7 | using System.Web; 8 | 9 | namespace webapi.Common 10 | { 11 | public static class EncryptHelper 12 | { 13 | #region MD5加密 14 | public static string MD5Encrypt(string content) 15 | { 16 | if (content == null) return null; 17 | MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider(); 18 | var enStr = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.UTF8.GetBytes(content))).Replace("-", ""); 19 | md5.Dispose(); 20 | return enStr; 21 | } 22 | #endregion 23 | 24 | #region DES加密 解密 25 | public static string DESEncrypt(string content, string key) 26 | { 27 | 28 | var rgbkey = UTF8Encoding.UTF8.GetBytes((key + "00000000").Substring(0, 8));///des加密的key必须为8位,不然会报错,以后再研究des算法的细节 29 | using (DESCryptoServiceProvider des = new DESCryptoServiceProvider()) 30 | using (MemoryStream ms = new MemoryStream()) 31 | using (CryptoStream encStream = new CryptoStream(ms, des.CreateEncryptor(rgbkey, rgbkey), CryptoStreamMode.Write)) 32 | { 33 | encStream.Write(UTF8Encoding.UTF8.GetBytes(content), 0, UTF8Encoding.UTF8.GetBytes(content).Length); 34 | encStream.FlushFinalBlock(); 35 | var enByte = ms.ToArray(); 36 | var enBase64Str = Convert.ToBase64String(enByte); 37 | return enBase64Str; 38 | } 39 | } 40 | 41 | public static string DESDecrypt(string content, string key) 42 | { 43 | var rgbkey = UTF8Encoding.UTF8.GetBytes((key + "00000000").Substring(0, 8));///des加密的key必须为8位,不然会报错,以后再研究des算法的细节 44 | using (DESCryptoServiceProvider des = new DESCryptoServiceProvider()) 45 | using (MemoryStream ms = new MemoryStream()) 46 | using (CryptoStream encStream = new CryptoStream(ms, des.CreateDecryptor(rgbkey, rgbkey), CryptoStreamMode.Write)) 47 | { 48 | var deByte = Convert.FromBase64String(content); 49 | encStream.Write(deByte, 0, deByte.Length); 50 | encStream.FlushFinalBlock(); 51 | var deStr = UTF8Encoding.UTF8.GetString(ms.ToArray()); 52 | return deStr; 53 | } 54 | } 55 | #endregion 56 | } 57 | } -------------------------------------------------------------------------------- /webapi/Common/Enums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace webapi.Common 7 | { 8 | /// 9 | /// 数据删除标志 10 | /// 11 | public enum DeleteMark 12 | { 13 | Deleted = -1, 14 | NotDeleted = 0 15 | } 16 | /// 17 | /// 性别约定值 18 | /// 19 | public enum Gender 20 | { 21 | Unknow = 0, 22 | Male = 1, 23 | Female = 2 24 | } 25 | 26 | /// 27 | /// 用户类型 28 | /// 29 | public enum UserType 30 | { 31 | /// 32 | /// 超级管理员 33 | /// 34 | SuperAdmin, 35 | /// 36 | /// 管理员 37 | /// 38 | Admin, 39 | /// 40 | /// 普通用户 41 | /// 42 | User 43 | } 44 | 45 | public enum ResourceCategory 46 | { 47 | WebApi, 48 | Menu 49 | } 50 | } -------------------------------------------------------------------------------- /webapi/Common/IdManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using webapi.Entities; 4 | 5 | namespace webapi.Common 6 | { 7 | public class IdManager 8 | { 9 | private static string _lastUserId; 10 | private static string _lastRoleId; 11 | private static string _lastResourceId; 12 | private static string _lastPermissionId; 13 | private static string _lastURMId; 14 | 15 | public static string NewUserId() 16 | { 17 | if (string.IsNullOrEmpty(_lastUserId)) 18 | { 19 | using (DB db=new DB()) 20 | { 21 | var userId = db.Users.OrderByDescending(a => a.Id).FirstOrDefault()?.Id; 22 | if (string.IsNullOrEmpty(userId)) 23 | { 24 | _lastUserId = "1001"; 25 | } 26 | } 27 | } 28 | _lastUserId = (int.Parse(_lastUserId) + 1).ToString(); 29 | return _lastUserId; 30 | } 31 | 32 | public static string NewRoleId() 33 | { 34 | if (string.IsNullOrEmpty(_lastRoleId)) 35 | { 36 | using (DB db = new DB()) 37 | { 38 | var roleId = db.Roles.OrderByDescending(a => a.Id).FirstOrDefault()?.Id; 39 | if (string.IsNullOrEmpty(roleId)) 40 | { 41 | _lastRoleId = "1"; 42 | } 43 | } 44 | } 45 | _lastRoleId = (int.Parse(_lastRoleId) + 1).ToString(); 46 | return _lastRoleId; 47 | } 48 | 49 | public static string NewResourceId() 50 | { 51 | if (string.IsNullOrEmpty(_lastResourceId)) 52 | { 53 | using (DB db = new DB()) 54 | { 55 | var ResourceId = db.Resources.OrderByDescending(a => a.Id).FirstOrDefault()?.Id; 56 | if (string.IsNullOrEmpty(ResourceId)) 57 | { 58 | _lastResourceId = "1"; 59 | } 60 | } 61 | } 62 | _lastResourceId = (int.Parse(_lastResourceId) + 1).ToString(); 63 | return _lastResourceId; 64 | } 65 | 66 | public static string NewPermissionId() 67 | { 68 | if (string.IsNullOrEmpty(_lastPermissionId)) 69 | { 70 | using (DB db = new DB()) 71 | { 72 | var PermissionId = db.Permissions.OrderByDescending(a => a.Id).FirstOrDefault()?.Id; 73 | if (string.IsNullOrEmpty(PermissionId)) 74 | { 75 | _lastPermissionId = "1"; 76 | } 77 | } 78 | } 79 | _lastPermissionId = (int.Parse(_lastPermissionId) + 1).ToString(); 80 | return _lastPermissionId; 81 | } 82 | 83 | public static string NewURMId() 84 | { 85 | if (string.IsNullOrEmpty(_lastURMId)) 86 | { 87 | using (DB db = new DB()) 88 | { 89 | var URMId = db.URMs.OrderByDescending(a => a.Id).FirstOrDefault()?.Id; 90 | if (string.IsNullOrEmpty(URMId)) 91 | { 92 | _lastURMId = "1"; 93 | } 94 | } 95 | } 96 | _lastURMId = (int.Parse(_lastURMId) + 1).ToString(); 97 | return _lastURMId; 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /webapi/Common/JWTHelper.cs: -------------------------------------------------------------------------------- 1 | using JWT; 2 | using JWT.Algorithms; 3 | using JWT.Serializers; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace webapi.Common 8 | { 9 | public class JWTHelper 10 | { 11 | private IJsonSerializer _jsonSerializer; 12 | private IDateTimeProvider _dateTimeProvider; 13 | private IJwtValidator _jwtValidator; 14 | private IBase64UrlEncoder _base64UrlEncoder; 15 | private IJwtAlgorithm _jwtAlgorithm; 16 | private IJwtDecoder _jwtDecoder; 17 | private IJwtEncoder _jwtEncoder; 18 | public JWTHelper() 19 | { 20 | //非fluent写法 21 | this._jsonSerializer = new JsonNetSerializer(); 22 | this._dateTimeProvider = new UtcDateTimeProvider(); 23 | this._jwtValidator = new JwtValidator(_jsonSerializer, _dateTimeProvider); 24 | this._base64UrlEncoder = new JwtBase64UrlEncoder(); 25 | this._jwtAlgorithm = new HMACSHA256Algorithm(); 26 | this._jwtDecoder = new JwtDecoder(_jsonSerializer, _jwtValidator, _base64UrlEncoder); 27 | this._jwtEncoder = new JwtEncoder(_jwtAlgorithm, _jsonSerializer, _base64UrlEncoder); 28 | 29 | 30 | } 31 | public string Decode(string token, string key, out bool isValid, out string errMsg) 32 | { 33 | isValid = false; 34 | var result = string.Empty; 35 | try 36 | { 37 | result = _jwtDecoder.Decode(token, key, true); 38 | isValid = true; 39 | errMsg = "正确的token"; 40 | return result; 41 | } 42 | catch (TokenExpiredException) 43 | { 44 | errMsg = "token过期"; 45 | return result; 46 | } 47 | catch (SignatureVerificationException) 48 | { 49 | errMsg = "签名无效"; 50 | return result; 51 | } 52 | catch (Exception) 53 | { 54 | errMsg = "token无效"; 55 | return result; 56 | } 57 | } 58 | 59 | public T DecodeToObject(string token, string key, out bool isValid, out string errMsg) 60 | { 61 | isValid = false; 62 | try 63 | { 64 | var result = _jwtDecoder.DecodeToObject(token, key, true); 65 | isValid = true; 66 | errMsg = "正确的token"; 67 | return result; 68 | } 69 | catch (TokenExpiredException) 70 | { 71 | errMsg = "token过期"; 72 | return default(T); 73 | } 74 | catch (SignatureVerificationException) 75 | { 76 | errMsg = "签名无效"; 77 | return default(T); 78 | } 79 | catch (Exception) 80 | { 81 | errMsg = "token无效"; 82 | return default(T); 83 | } 84 | } 85 | 86 | public IDictionary DecodeToObject(string token, string key, out bool isValid, out string errMsg) 87 | { 88 | isValid = false; 89 | try 90 | { 91 | var result = _jwtDecoder.DecodeToObject(token, key, true); 92 | isValid = true; 93 | errMsg = "正确的token"; 94 | return result; 95 | } 96 | catch (TokenExpiredException) 97 | { 98 | errMsg = "token过期"; 99 | return null; 100 | } 101 | catch (SignatureVerificationException) 102 | { 103 | errMsg = "签名无效"; 104 | return null; 105 | } 106 | catch (Exception) 107 | { 108 | errMsg = "token无效"; 109 | return null; 110 | } 111 | } 112 | 113 | #region 解密 114 | public string Encode(Dictionary payload, string key, int expiredMinute = 30) 115 | { 116 | if (!payload.ContainsKey("exp")) 117 | { 118 | var exp = Math.Round((_dateTimeProvider.GetNow().AddMinutes(expiredMinute) - new DateTime(1970, 1, 1)).TotalSeconds); 119 | payload.Add("exp", exp); 120 | } 121 | return _jwtEncoder.Encode(payload, key); 122 | } 123 | #endregion 124 | 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /webapi/Configs/Config.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace webapi.Configs 7 | { 8 | public class Config 9 | { 10 | public const string JWTKey = "shengyu"; 11 | public const string SysUser = "sys"; 12 | } 13 | } -------------------------------------------------------------------------------- /webapi/Configs/WebApiConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Http; 2 | using webapi.Exceptions; 3 | using webapi.Security; 4 | 5 | namespace webapi.Configs 6 | { 7 | /// 8 | /// webapi 配置类 9 | /// 10 | public static class WebApiConfig 11 | { 12 | /// 13 | /// 做为委托提供给System.Web.Http.GlobalConfiguration.Configuration() 14 | /// 用于webapi以iis为服务器的情况 15 | /// 16 | /// 17 | public static void Register(HttpConfiguration config) 18 | { 19 | // Web API 配置和服务 20 | // Web API 路由 21 | config.MapHttpAttributeRoutes(); 22 | config.Routes.MapHttpRoute( 23 | name: "DefaultApi", 24 | routeTemplate: "api/{controller}/{id}", 25 | defaults: new { id = RouteParameter.Optional } 26 | ); 27 | } 28 | /// 29 | /// 返回webapi的httpconfiguration配置 30 | /// 用于webapi应用于owin技术时使用 31 | /// 32 | /// 33 | public static HttpConfiguration OwinWebApiConfiguration(HttpConfiguration config) 34 | { 35 | config.MapHttpAttributeRoutes();//开启属性路由 36 | config.Routes.MapHttpRoute( 37 | name: "DefaultApi", 38 | routeTemplate: "api/{controller}/{id}", 39 | defaults: new { id = RouteParameter.Optional } 40 | ); 41 | config.Filters.Add(new WebApiExceptionFilterAttribute()); 42 | config.Filters.Add(new IdentityBasicAuthentication()); 43 | return config; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /webapi/ConnectionStrings.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /webapi/Entities/BaseEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | namespace webapi.Entities 6 | { 7 | public class BaseEntity 8 | { 9 | 10 | /// 11 | /// 创建时间 12 | /// 13 | [Column(TypeName = "datetime")] 14 | public DateTime? CreateTime { set; get; } 15 | /// 16 | /// 创建人 17 | /// 18 | [Column(TypeName = "varchar"), MaxLength(50)] 19 | public string CreateUser { set; get; } 20 | /// 21 | /// 是否删除 22 | /// 23 | [Column(TypeName = "int"), DefaultValue(webapi.Common.DeleteMark.NotDeleted)] 24 | public int DeleteMark { get; set; } 25 | } 26 | } -------------------------------------------------------------------------------- /webapi/Entities/DB.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Entity; 2 | 3 | namespace webapi.Entities 4 | { 5 | public class DB : DbContext 6 | { 7 | /// 8 | /// name=DBConnection,DBConnection为数据库连接的名字,即web.config配置文件节点connectionStrings,name值为DBConnection的数据库连接字符串 9 | /// 10 | public DB() 11 | : base("name=DBConnection") 12 | { 13 | // 默认策略为CreateDatabaseIfNotExists,即如果数据库不存在则创建,用migrations时改成MigrateDatabaseToLatestVersion,即每次第一次访问数据库时同步最新的数据库结构 14 | Database.SetInitializer(new MigrateDatabaseToLatestVersion("DBConnection")); 15 | } 16 | 17 | 18 | #region 配置所有的数据库表 19 | 20 | public DbSet Users { set; get; } 21 | public DbSet Roles { set; get; } 22 | public DbSet Resources { set; get; } 23 | public DbSet URMs { set; get; } 24 | public DbSet Permissions { set; get; } 25 | public DbSet TestTables { set; get; } 26 | #endregion 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /webapi/Entities/Permission.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace webapi.Entities 5 | { 6 | /// 7 | /// 权限表,记录角色和资源的对应关系 8 | /// 9 | [Table("Permission")] 10 | public class Permission:BaseEntity 11 | { 12 | /// 13 | /// 主键 14 | /// 15 | [Key, Column(TypeName = "varchar"), MaxLength(50)] 16 | public string Id { set; get; } 17 | /// 18 | /// 资源类型,如webapi接口,菜单等 19 | /// 20 | [Column(TypeName = "varchar"), MaxLength(50)] 21 | public string RoleId { set; get; } 22 | /// 23 | /// 资源名,如“ControllerName.ActionName”,或是“url地址” 24 | /// 25 | [Column(TypeName = "varchar"), MaxLength(50)] 26 | public string ResourceId { set; get; } 27 | } 28 | } -------------------------------------------------------------------------------- /webapi/Entities/Resource.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace webapi.Entities 5 | { 6 | /// 7 | /// 需要做权限控制的资源 8 | /// 9 | [Table("Resource")] 10 | public class Resource:BaseEntity 11 | { 12 | /// 13 | /// 主键 14 | /// 15 | [Key,Column(TypeName = "varchar"),MaxLength(50)] 16 | public string Id { set; get; } 17 | /// 18 | /// 资源类型,如webapi接口,菜单等 19 | /// 20 | [Column(TypeName = "varchar"), MaxLength(20)] 21 | public string Category { set; get; } 22 | /// 23 | /// 资源名(唯一性),如“ControllerName.ActionName”,或是“url地址” 24 | /// 25 | [Column(TypeName = "varchar"), MaxLength(100)] 26 | public string Name { set; get; } 27 | /// 28 | /// 资源描述 29 | /// 30 | [Column(TypeName = "varchar"), MaxLength(200)] 31 | public string Description { set; get; } 32 | } 33 | } -------------------------------------------------------------------------------- /webapi/Entities/Role.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace webapi.Entities 5 | { 6 | /// 7 | /// 角色表 8 | /// 9 | [Table("Role")] 10 | public partial class Role:BaseEntity 11 | { 12 | /// 13 | /// 角色ID 14 | /// 15 | [Key, Column(TypeName = "varchar"), MaxLength(50)] 16 | public string Id { get; set; } 17 | /// 18 | /// 角色名 19 | /// 20 | [Column(TypeName = "varchar"), MaxLength(20)] 21 | public string Name { get; set; } 22 | 23 | } 24 | } -------------------------------------------------------------------------------- /webapi/Entities/TestTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace webapi.Entities 6 | { 7 | [Table("Test")] 8 | public class TestTable 9 | { 10 | [Key,Column(TypeName = "varchar"),MaxLength(50)] 11 | public string Id { set; get; } 12 | [Column(TypeName = "int")] 13 | public int? Age { set; get; } 14 | [Column(TypeName = "datetime")] 15 | public DateTime? CreateDateTime { get; set; } 16 | [Column(TypeName = "varchar"), MaxLength(20)] 17 | public string AddColumn1 { set; get; } 18 | 19 | [Column(TypeName = "varchar"), MaxLength(20)] 20 | public string AddColumn2 { set; get; } 21 | } 22 | } -------------------------------------------------------------------------------- /webapi/Entities/URM.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace webapi.Entities 5 | { 6 | /// 7 | /// 用户角色关系对应表,user role map 8 | /// 9 | [Table("URM")] 10 | public partial class URM:BaseEntity 11 | { 12 | /// 13 | /// ID主键 14 | /// 15 | [Key, Column(TypeName = "varchar"), MaxLength(50)] 16 | public string Id { get; set; } 17 | /// 18 | /// 用户ID 19 | /// 20 | [Column(TypeName = "varchar"), MaxLength(50)] 21 | public string UserId { get; set; } 22 | /// 23 | /// 角色ID 24 | /// 25 | [Column(TypeName = "varchar"), MaxLength(50)] 26 | public string RoleId { get; set; } 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /webapi/Entities/User.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace webapi.Entities 6 | { 7 | /// 8 | /// 用户表 9 | /// 10 | [Table("User")] 11 | public partial class User:BaseEntity 12 | { 13 | /// 14 | /// 主键 15 | /// 16 | [Key, Column(TypeName = "varchar"), MaxLength(50)] 17 | public string Id { get; set; } 18 | /// 19 | /// 登录名 20 | /// 21 | [Column(TypeName = "varchar"), MaxLength(50)] 22 | public string LoginName { get; set; } 23 | /// 24 | /// 真实姓名 25 | /// 26 | [Column(TypeName = "varchar"), MaxLength(50)] 27 | public string Name { get; set; } 28 | /// 29 | /// 密码,用于存储密码的md5加密 30 | /// 31 | [Column(TypeName = "varchar"), MaxLength(50)] 32 | public string Pwd { get; set; } 33 | /// 34 | /// 性别,1男2女,对应Gender枚举 35 | /// 36 | [Column(TypeName = "int")] 37 | public int? Gender { get; set; } 38 | /// 39 | /// 身份证 40 | /// 41 | [Column(TypeName = "varchar"), MaxLength(50)] 42 | public string IdentityCard { get; set; } 43 | /// 44 | /// 电话 45 | /// 46 | [Column(TypeName = "varchar"), MaxLength(50)] 47 | public string Tel { get; set; } 48 | /// 49 | /// 出生日期 50 | /// 51 | [Column(TypeName = "datetime")] 52 | public DateTime? Birthdate { get; set; } 53 | /// 54 | /// 头像 55 | /// 56 | [Column(TypeName = "varchar"), MaxLength(500)] 57 | public string UserPic { get; set; } 58 | } 59 | } -------------------------------------------------------------------------------- /webapi/Exceptions/KnownException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace webapi.Exceptions 5 | { 6 | public class KnownException : Exception 7 | { 8 | public KnownException():base() 9 | { 10 | } 11 | 12 | public KnownException(string message) : base(message) 13 | { 14 | } 15 | 16 | public KnownException(string message, Exception innerException) : base(message, innerException) 17 | { 18 | } 19 | 20 | protected KnownException(SerializationInfo info, StreamingContext context) : base(info, context) 21 | { 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /webapi/Exceptions/WebApiExceptionFilterAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http; 3 | using System.Web.Http.Filters; 4 | using log4net; 5 | 6 | namespace webapi.Exceptions 7 | { 8 | public class WebApiExceptionFilterAttribute : ExceptionFilterAttribute 9 | { 10 | public override void OnException(HttpActionExecutedContext actionExecutedContext) 11 | { 12 | var exception = actionExecutedContext.Exception;//获取产生的异常对象 13 | var exceptionMessage = exception.Message; 14 | var logMessage = 15 | $@"controller.action={actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerName}.{actionExecutedContext.ActionContext.ActionDescriptor.ActionName}:exception=" 16 | + exception.Message;//异常内容 17 | ILog log = LogManager.GetLogger(actionExecutedContext.ActionContext.ControllerContext.Controller.GetType()); 18 | if (exception is KnownException) 19 | { 20 | log.Debug(logMessage); 21 | } 22 | else 23 | { 24 | log.Error(logMessage, exception); 25 | } 26 | actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, exceptionMessage); 27 | } 28 | 29 | } 30 | } -------------------------------------------------------------------------------- /webapi/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="webapi.Global" Language="C#" %> 2 | -------------------------------------------------------------------------------- /webapi/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Http; 3 | using webapi.Configs; 4 | 5 | 6 | namespace webapi 7 | { 8 | /// 9 | /// 部署在iis里时,iis的入口为HttpApplication.Application_Start函数,所以webapi要在此函数里做配置。 10 | /// 如果用owin通道(iis的asp.net pipeline 将不再启用),则不需要Global.asax文件 11 | /// 在部署时如果是用owin技术,Global.asax不用删除,请求是不会进过这里的,除非删除了bin目录下的Microsoft.Owin.Host.SystemWeb.dll 12 | /// 13 | public class Global : System.Web.HttpApplication 14 | { 15 | protected void Application_Start(object sender, EventArgs e) 16 | { 17 | #region webapi的相关配置 18 | // GlobalConfiguration类在Microsoft.AspNet.WebApi.Core里,用nuget添加Microsoft.AspNet.WebApi 19 | //GlobalConfiguration类在Microsoft.AspNet.WebApi.WebHost里有也定义 20 | GlobalConfiguration.Configure(WebApiConfig.Register); 21 | 22 | #endregion 23 | 24 | } 25 | 26 | protected void Session_Start(object sender, EventArgs e) 27 | { 28 | 29 | } 30 | 31 | protected void Application_BeginRequest(object sender, EventArgs e) 32 | { 33 | 34 | } 35 | 36 | protected void Application_AuthenticateRequest(object sender, EventArgs e) 37 | { 38 | 39 | } 40 | 41 | protected void Application_Error(object sender, EventArgs e) 42 | { 43 | 44 | } 45 | 46 | protected void Session_End(object sender, EventArgs e) 47 | { 48 | 49 | } 50 | 51 | protected void Application_End(object sender, EventArgs e) 52 | { 53 | 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /webapi/Log4net.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /webapi/Microsoft.Owin.Host.HttpListener.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shengyu-kmust/webapi/35c9cb30ded1e3d232619e314237b57f35b55dce/webapi/Microsoft.Owin.Host.HttpListener.dll -------------------------------------------------------------------------------- /webapi/Microsoft.Owin.Hosting.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shengyu-kmust/webapi/35c9cb30ded1e3d232619e314237b57f35b55dce/webapi/Microsoft.Owin.Hosting.dll -------------------------------------------------------------------------------- /webapi/Microsoft.Owin.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shengyu-kmust/webapi/35c9cb30ded1e3d232619e314237b57f35b55dce/webapi/Microsoft.Owin.dll -------------------------------------------------------------------------------- /webapi/Migrations/Configuration.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shengyu-kmust/webapi/35c9cb30ded1e3d232619e314237b57f35b55dce/webapi/Migrations/Configuration.cs -------------------------------------------------------------------------------- /webapi/Owin.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shengyu-kmust/webapi/35c9cb30ded1e3d232619e314237b57f35b55dce/webapi/Owin.dll -------------------------------------------------------------------------------- /webapi/Owin/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Owin; 2 | using Owin; 3 | using System.Threading.Tasks; 4 | using System.Web.Http; 5 | using Autofac.Integration.WebApi; 6 | using webapi.AutoFac; 7 | using webapi.Configs; 8 | 9 | // 标识webapiOwin.Startup类为owin的启动类,也可写在AssemblyInfo.cs文件里 10 | [assembly: OwinStartup(typeof(webapi.Owin.Startup))] 11 | 12 | namespace webapi.Owin 13 | { 14 | public class Startup 15 | { 16 | /// 17 | /// owin的http请求管道配置函数 18 | /// 19 | /// 20 | public void Configuration(IAppBuilder app) 21 | { 22 | // 有关如何配置应用程序的详细信息,请访问 https://go.microsoft.com/fwlink/?LinkID=316888 23 | 24 | #region 测试用 25 | //app.Run(context => 26 | //{ 27 | // context.Response.Write("这是owin管道"); 28 | // return Task.FromResult(0); 29 | //}); 30 | #endregion 31 | 32 | #region 写在前面的配置 33 | // 获取webapi的配置 34 | var config = WebApiConfig.OwinWebApiConfiguration(new HttpConfiguration()); 35 | // 获取webapi的依赖注入容器 36 | var container = ContainerBuilerCommon.GetWebApiContainer(); 37 | // 配置webapi的依赖注入 38 | config.DependencyResolver = new AutofacWebApiDependencyResolver(container); 39 | #endregion 40 | 41 | #region owin组件注册(要注意顺序) 42 | 43 | app.UseAutofacMiddleware(container);// 先注册autofac组件,需要依赖注入功能的组件在此后注册 44 | app.UseAutofacWebApi(config);//注册AutofacWebApi组件后再注册WebApi组件 45 | app.UseWebApi(config); 46 | #endregion 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /webapi/OwinHost.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shengyu-kmust/webapi/35c9cb30ded1e3d232619e314237b57f35b55dce/webapi/OwinHost.exe -------------------------------------------------------------------------------- /webapi/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using log4net.Config; 5 | 6 | // 有关程序集的常规信息通过下列特性集 7 | // 控制。更改这些特性值可修改 8 | // 与程序集关联的信息。 9 | [assembly: AssemblyTitle("webapi")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("webapi")] 14 | [assembly: AssemblyCopyright("Copyright © 2018")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // 将 ComVisible 设置为 false 会使此程序集中的类型 19 | // 对 COM 组件不可见。如果需要 20 | // 从 COM 访问此程序集中的某个类型,请针对该类型将 ComVisible 特性设置为 true。 21 | [assembly: ComVisible(false)] 22 | 23 | // 如果此项目向 COM 公开,则下列 GUID 用于 typelib 的 ID 24 | [assembly: Guid("7a63dca6-5f3f-440a-934e-a92c162c0e82")] 25 | 26 | // 程序集的版本信息由下列四个值组成: 27 | // 28 | // 主版本 29 | // 次版本 30 | // 内部版本号 31 | // 修订版本 32 | // 33 | // 可以指定所有值,也可以使用“修订号”和“内部版本号”的默认值, 34 | // 方法是按如下所示使用 "*": 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | // log4net的配置文件,参考:http://logging.apache.org/log4net/release/manual/configuration.html 38 | [assembly: XmlConfigurator(Watch = true, ConfigFile = "Log4Net.config")] -------------------------------------------------------------------------------- /webapi/Security/IdentityBasicAuthentication.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Security.Claims; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using System.Web.Http.Filters; 8 | using System.Web.Http.Results; 9 | using webapi.Common; 10 | using webapi.Configs; 11 | 12 | namespace webapi.Security 13 | { 14 | public class IdentityBasicAuthentication:IAuthenticationFilter 15 | { 16 | public bool AllowMultiple { get; } 17 | /// 18 | /// 请求先经过AuthenticateAsync 19 | /// 20 | /// 21 | /// 22 | /// 23 | public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) 24 | { 25 | // 1、获取token 26 | context.Request.Headers.TryGetValues("token", out var tokenHeaders); 27 | // 2、如果没有token,不做任何处理 28 | if (tokenHeaders == null || !tokenHeaders.Any()) 29 | { 30 | return Task.FromResult(0); 31 | } 32 | // 3、如果token验证通过,则写入到identity,如果未通过则设置错误 33 | var jwtHelper=new JWTHelper(); 34 | var payLoadClaims=jwtHelper.DecodeToObject(tokenHeaders.FirstOrDefault(),Config.JWTKey, out bool isValid, out string errMsg); 35 | if (isValid) 36 | { 37 | var identity = new ClaimsIdentity("jwt", "user", "role");//只要ClaimsIdentity设置了authenticationType,authenticated就为true,后面的authority根据authenticated=true来做权限 38 | foreach (var keyValuePair in payLoadClaims) 39 | { 40 | // 一个用户可以拥有多种角色 41 | if (keyValuePair.Key=="role") 42 | { 43 | foreach (var roleItem in keyValuePair.Value.ToString().Split(',')) 44 | { 45 | identity.AddClaim(new Claim("role", roleItem)); 46 | } 47 | } 48 | else 49 | { 50 | identity.AddClaim(new Claim(keyValuePair.Key, keyValuePair.Value.ToString())); 51 | } 52 | } 53 | // 最好是http上下文的principal和进程的currentPrincipal都设置 54 | context.Principal = new ClaimsPrincipal(identity); 55 | Thread.CurrentPrincipal = new ClaimsPrincipal(identity); 56 | } 57 | else 58 | { 59 | context.ErrorResult = new ResponseMessageResult(new HttpResponseMessage() 60 | { 61 | StatusCode = HttpStatusCode.ProxyAuthenticationRequired, 62 | Content = new StringContent(errMsg) 63 | }); 64 | } 65 | return Task.FromResult(0); 66 | } 67 | 68 | /// 69 | /// 请求后经过AuthenticateAsync 70 | /// 71 | /// 72 | /// 73 | /// 74 | public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken) 75 | { 76 | return Task.FromResult(0); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /webapi/Security/RBAuthorizeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Security.Principal; 7 | using System.Web.Http; 8 | using System.Web.Http.Controllers; 9 | using webapi.Entities; 10 | using webapi.Services; 11 | 12 | namespace webapi.Security 13 | { 14 | /// 15 | /// Role Basic AuthorizeAttribute(基于角色的授权) 16 | /// 17 | public class RBAuthorizeAttribute : AuthorizeAttribute 18 | { 19 | public string Description { set; get; } 20 | protected override bool IsAuthorized(HttpActionContext actionContext) 21 | { 22 | // 这是base.IsAuthorized里的逻辑 23 | //IPrincipal principal = actionContext.ControllerContext.RequestContext.Principal; 24 | //return principal != null && principal.Identity != null 25 | // && principal.Identity.IsAuthenticated && 26 | // ( 27 | // (this._usersSplit.Length <= 0 || ((IEnumerable)this._usersSplit).Contains(principal.Identity.Name, (IEqualityComparer)StringComparer.OrdinalIgnoreCase)) 28 | // && 29 | // (this._rolesSplit.Length <= 0 || ((IEnumerable)this._rolesSplit).Any(new Func(principal.IsInRole))) 30 | // ); 31 | 32 | // 下在可替换成自己的授权逻辑代码 33 | AuthorizeService authorizeService =new AuthorizeService(new DB()); 34 | var resourceName = actionContext.ActionDescriptor.GetCustomAttributes().Any() 35 | ? actionContext.ActionDescriptor.ActionName 36 | : actionContext.ControllerContext.ControllerDescriptor.ControllerName; 37 | var roleNames = authorizeService.GetResourceRoleNames(resourceName); 38 | IPrincipal principal = actionContext.ControllerContext.RequestContext.Principal; 39 | return principal != null && principal.Identity != null 40 | && principal.Identity.IsAuthenticated && 41 | ( 42 | (((IEnumerable)roleNames).Any(new Func(principal.IsInRole))) 43 | ); 44 | } 45 | 46 | protected override void HandleUnauthorizedRequest(HttpActionContext actionContext) 47 | { 48 | actionContext.Response = 49 | actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "未授权"); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /webapi/Services/AuthorizeService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using webapi.Entities; 6 | 7 | 8 | namespace webapi.Services 9 | { 10 | public class AuthorizeService:BaseService 11 | { 12 | public AuthorizeService(DB db) : base(db) 13 | { 14 | } 15 | /// 16 | /// 获取资源的角色名数组 17 | /// 18 | /// 19 | /// 20 | public string[] GetResourceRoleNames(string resourceName) 21 | { 22 | var resource=_db.Resources.FirstOrDefault(a => a.Name == resourceName); 23 | var roleIds = _db.Permissions.Where(a => a.ResourceId == resource.Id).Select(a => a.RoleId).ToArray(); 24 | var roleNames = _db.Roles.Where(a => roleIds.Contains(a.Id)).Select(a => a.Name).ToArray(); 25 | return roleNames; 26 | } 27 | /// 28 | /// 获取所有资源的角色 29 | /// 30 | /// 31 | public List<(string resourceName, string roleNames)> GetAllResourceRoleNames() 32 | { 33 | var result=new List<(string resourceName, string roleNames)>(); 34 | var query = from a in _db.Permissions 35 | join b in _db.Resources on a.ResourceId equals b.Id 36 | join c in _db.Roles on a.RoleId equals c.Id 37 | group new{a,b,c} by b.Name into g 38 | select new 39 | { 40 | resourceName=g.Key, 41 | roleNames=g.Select(i => i.c.Name) 42 | }; 43 | 44 | var list = query.ToList().Select(a => new 45 | { 46 | a.resourceName, 47 | roleNames=string.Join(",", a.roleNames.ToArray().Distinct()) 48 | }); 49 | foreach (var x1 in list) 50 | { 51 | result.Add((x1.resourceName,x1.roleNames)); 52 | } 53 | return result; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /webapi/Services/BaseService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using webapi.Entities; 6 | 7 | namespace webapi.Services 8 | { 9 | public class BaseService:IDisposable 10 | { 11 | protected DB _db; 12 | 13 | public BaseService(DB db) 14 | { 15 | _db = db; 16 | } 17 | 18 | #region IDisposable Support 19 | private bool disposedValue = false; // 要检测冗余调用 20 | 21 | protected virtual void Dispose(bool disposing) 22 | { 23 | if (!disposedValue) 24 | { 25 | if (disposing) 26 | { 27 | // TODO: 释放托管状态(托管对象)。 28 | _db?.Dispose(); 29 | } 30 | // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。 31 | // TODO: 将大型字段设置为 null。 32 | 33 | disposedValue = true; 34 | } 35 | } 36 | 37 | // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。 38 | // ~BaseService() { 39 | // // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 40 | // Dispose(false); 41 | // } 42 | 43 | // 添加此代码以正确实现可处置模式。 44 | public void Dispose() 45 | { 46 | // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 47 | Dispose(true); 48 | // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。 49 | // GC.SuppressFinalize(this); 50 | } 51 | #endregion 52 | } 53 | } -------------------------------------------------------------------------------- /webapi/Services/PermissionService.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using webapi.Entities; 3 | 4 | namespace webapi.Services 5 | { 6 | public class PermissionService:BaseService 7 | { 8 | public PermissionService(DB db) : base(db) 9 | { 10 | } 11 | 12 | public string[] GetWebApiResourceRoleNames(string resourceName) 13 | { 14 | var resource = _db.Resources.FirstOrDefault(a => a.Name == resourceName); 15 | var roleIds= _db.Permissions.Where(a => a.ResourceId == resource.Id).Select(a => a.RoleId).ToArray(); 16 | var roleNames = _db.Roles.Where(a => roleIds.Contains(a.Id)).Select(a => a.Name).ToArray(); 17 | return roleNames; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /webapi/Services/ResourceService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity.Migrations; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Web.Http; 7 | using webapi.Common; 8 | using webapi.Entities; 9 | using webapi.Security; 10 | 11 | namespace webapi.Services 12 | { 13 | public class ResourceService : BaseService 14 | { 15 | public ResourceService(DB db) : base(db) 16 | { 17 | } 18 | 19 | public string[] GetResourceRoles(string resourceId) 20 | { 21 | return new string[] { }; 22 | } 23 | 24 | /// 25 | /// 增加或修改资源 26 | /// 27 | /// 28 | /// 29 | /// 30 | public void AddOrUpdateResource(string name, string description, string category) 31 | { 32 | var resource = _db.Resources.FirstOrDefault(a => a.Name == name); 33 | if (resource == null) 34 | { 35 | resource = new Resource() 36 | { 37 | Id = IdManager.NewResourceId(), 38 | Name = name, 39 | Description = description, 40 | Category = category, 41 | CreateTime = DateTime.Now, 42 | DeleteMark = (int)DeleteMark.NotDeleted 43 | }; 44 | } 45 | else 46 | { 47 | resource.Description = string.IsNullOrEmpty(description) ? resource.Description : description; 48 | resource.Name = string.IsNullOrEmpty(name) ? resource.Name : name; 49 | resource.Category = string.IsNullOrEmpty(category) ? resource.Category : category; ; 50 | } 51 | _db.Resources.AddOrUpdate(resource); 52 | _db.SaveChanges(); 53 | } 54 | 55 | /// 56 | /// 更新webapi的权限资源到数据库 57 | /// 58 | public void UpdateWebApiResource() 59 | { 60 | var resources = GetAllWebApiResource(); 61 | resources.ForEach(a => 62 | { 63 | AddOrUpdateResource(a.Name, a.Description, a.Category); 64 | }); 65 | } 66 | 67 | /// 68 | /// 获取所有webapi的授权资源列表 69 | /// 70 | /// 71 | public List GetAllWebApiResource() 72 | { 73 | var allController = Assembly.GetExecutingAssembly().ExportedTypes 74 | .Where(a => a.IsSubclassOf(typeof(ApiController))).ToList(); 75 | var resources = new List(); 76 | allController.ForEach(controller => 77 | { 78 | if (Attribute.IsDefined(controller, typeof(RBAuthorizeAttribute))) 79 | { 80 | var description = ((RBAuthorizeAttribute)controller.GetCustomAttribute(typeof(RBAuthorizeAttribute))).Description; 81 | resources.Add(new Resource() 82 | { 83 | Category = ResourceCategory.WebApi.ToString(), 84 | CreateUser = Configs.Config.SysUser, 85 | Description = description, 86 | Name = controller.Name 87 | }); 88 | } 89 | controller.GetMethods().Where(b => Attribute.IsDefined(b, typeof(RBAuthorizeAttribute))).ToList().ForEach( 90 | action => 91 | { 92 | var description = ((RBAuthorizeAttribute)action.GetCustomAttribute(typeof(RBAuthorizeAttribute))).Description; 93 | resources.Add(new Resource() 94 | { 95 | Category = ResourceCategory.WebApi.ToString(), 96 | CreateUser = Configs.Config.SysUser, 97 | Description = description, 98 | Name = action.Name 99 | }); 100 | }); 101 | }); 102 | return resources; 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /webapi/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 30 | 31 | -------------------------------------------------------------------------------- /webapi/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 31 | 32 | -------------------------------------------------------------------------------- /webapi/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /webapi/example/EFTestController.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Web.Http; 3 | using webapi.Entities; 4 | 5 | namespace webapi.example 6 | { 7 | public class EFTestController : ApiController 8 | { 9 | public IHttpActionResult Get() 10 | { 11 | using (DB db=new DB()) 12 | { 13 | var list = db.TestTables; 14 | return Ok(list.ToList()); 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /webapi/example/ExceptionTestController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Http; 3 | using webapi.Exceptions; 4 | 5 | namespace webapi.example 6 | { 7 | [RoutePrefix("api/exceptionTest")] 8 | public class ExceptionTestController : ApiController 9 | { 10 | /// 11 | /// 模拟程序bug抛出的异常 12 | /// 13 | /// 14 | [Route("unknown"),HttpGet] 15 | public IHttpActionResult UnKnow() 16 | { 17 | throw new Exception("未知的异常"); 18 | } 19 | /// 20 | /// 模拟主动抛出的业务异常 21 | /// 22 | /// 23 | [Route("known"), HttpGet] 24 | public IHttpActionResult Know() 25 | { 26 | throw new KnownException("已知的异常"); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /webapi/example/IMyLog.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | 3 | namespace webapi.example 4 | { 5 | public interface IMyLog:ILog 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /webapi/example/IOCTestController.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Http; 2 | /// 3 | /// 本代码用来测试依赖注入是否正常 4 | /// 5 | namespace webapi.example 6 | { 7 | public class IOCTestController : ApiController 8 | { 9 | private People _people; 10 | public IOCTestController(People people) 11 | { 12 | _people = people; 13 | } 14 | 15 | public IHttpActionResult GetLanguage() 16 | { 17 | return Ok(_people.Language()); 18 | } 19 | } 20 | 21 | public interface People 22 | { 23 | string Language(); 24 | } 25 | 26 | public class Chinese : People 27 | { 28 | public string Language() 29 | { 30 | return "汉语"; 31 | } 32 | } 33 | 34 | public class American:People 35 | { 36 | public string Language() 37 | { 38 | return "english"; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /webapi/example/LogTestController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Http; 3 | using log4net; 4 | 5 | /// 6 | /// 日志处理测试接口,使用log4net 7 | /// 8 | namespace webapi.example 9 | { 10 | public class LogTestController : ApiController 11 | { 12 | private ILog _log; 13 | 14 | public LogTestController(ILog log) 15 | { 16 | _log = log; 17 | } 18 | public IHttpActionResult Get() 19 | { 20 | _log.Debug("测试debug",new Exception("debug异常")); 21 | _log.Info("测试Info", new Exception("Info异常")); 22 | _log.Warn("测试Warn", new Exception("Warn异常")); 23 | _log.Error("测试Error", new Exception("Error异常")); 24 | _log.Fatal("测试Fatal", new Exception("Fatal异常")); 25 | return Ok("已经写入日志"); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /webapi/example/SecurityTestController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net.Http; 3 | using System.Security.Claims; 4 | using System.Web.Http; 5 | using webapi.Common; 6 | using webapi.Security; 7 | 8 | namespace webapi.example 9 | { 10 | [RoutePrefix("api/security"), RBAuthorize(Roles = "role",Description = "测试权限控制器")] 11 | //[RoutePrefix("api/security"),RBAuthorize(Description = "SecurityTestController")] 12 | public class SecurityTestController : ApiController 13 | { 14 | /// 15 | /// 通过get请求里传过来的值生成token 16 | /// 17 | /// 18 | [Route("token"),HttpGet,AllowAnonymous] 19 | public IHttpActionResult GetToken() 20 | { 21 | var dic=new Dictionary(); 22 | foreach (var queryNameValuePair in Request.GetQueryNameValuePairs()) 23 | { 24 | dic.Add(queryNameValuePair.Key,queryNameValuePair.Value); 25 | } 26 | var token=new JWTHelper().Encode(dic, "shengyu",30); 27 | return Ok(token); 28 | } 29 | 30 | /// 31 | /// 返回token里加密的信息 32 | /// 33 | /// 34 | [Route("GetUserInfoFromToken"),HttpGet, AllowAnonymous] 35 | public IHttpActionResult GetUser() 36 | { 37 | var user = (ClaimsPrincipal)User; 38 | var dic=new Dictionary(); 39 | foreach (var userClaim in user.Claims) 40 | { 41 | dic.Add(userClaim.Type,userClaim.Value); 42 | } 43 | return Ok(dic); 44 | } 45 | 46 | #region 硬编码的方式实现简单的权限控制 47 | 48 | /// 49 | /// 只有某种角色的用户才有权限访问 50 | /// 51 | /// 52 | [Route("byCode/onlyRoles"), RBAuthorize(Roles = "admin,superAdmin",Description = "OnlyRoles_SetByCode"),HttpGet] 53 | public IHttpActionResult OnlyRoles_SetByCode() 54 | { 55 | return Ok("OnlyRoles_SetByCode,仅管理员能访问"); 56 | } 57 | 58 | /// 59 | /// 只有某种角色的用户才有权限访问 60 | /// 61 | /// 62 | [Route("byCode/onlyRoles2"), RBAuthorize(Roles = "user,member",Description = "OnlyRoles_SetByCode2"), HttpGet] 63 | public IHttpActionResult OnlyRoles_SetByCode2() 64 | { 65 | return Ok("OnlyRoles_SetByCode2,仅角色为user,member能访问"); 66 | } 67 | 68 | /// 69 | /// 只有某几个用户才有权限访问 70 | /// 71 | /// 72 | [Route("byCode/onlyUsers"), RBAuthorize(Users = "张三,李四",Description = "OnlyUsers_SetByCode"),HttpGet] 73 | public IHttpActionResult OnlyUsers_SetByCode() 74 | { 75 | return Ok("OnlyRoles_SetByCode,仅张三和李四才能访问"); 76 | } 77 | #endregion 78 | 79 | #region 配置的方式实现基于角色的权限控制 80 | 81 | [Route("dynamic/onlyRoles1"), RBAuthorize(Description = "Dynamic_OnlyRoles1"), HttpGet] 82 | public IHttpActionResult Dynamic_OnlyRoles1() 83 | { 84 | return Ok("成功访问Dynamic_OnlyRoles1"); 85 | } 86 | [Route("dynamic/onlyRoles2"), RBAuthorize(Description = "Dynamic_OnlyRoles2"), HttpGet] 87 | public IHttpActionResult Dynamic_OnlyRoles2() 88 | { 89 | return Ok("成功访问Dynamic_OnlyRoles2"); 90 | } 91 | [Route("dynamic/onlyRoles3"), AllowAnonymous, HttpGet] 92 | public IHttpActionResult Dynamic_OnlyRoles3() 93 | { 94 | return Ok("成功访问Dynamic_OnlyRoles3,此方法不需要权限及可访问"); 95 | } 96 | #endregion 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /webapi/example/TestController.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Http; 2 | using webapi.Entities; 3 | using webapi.Services; 4 | 5 | namespace webapi.example 6 | { 7 | [RoutePrefix("api/Test")] 8 | public class TestController : ApiController 9 | { 10 | [Route("get"),HttpGet] 11 | public IHttpActionResult Get() 12 | { 13 | return Ok("this is TestController.Get()"); 14 | } 15 | 16 | [Route("Test"), HttpGet] 17 | public IHttpActionResult Test() 18 | { 19 | ResourceService service = new ResourceService(new DB()); 20 | service.UpdateWebApiResource(); 21 | return Ok("成功更新"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /webapi/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /webapi/readme.txt: -------------------------------------------------------------------------------- 1 | =============================================================================== 2 | 项目结构 3 | --Configs 4 | --Owin 5 | 6 | 7 | 8 | 9 | =============================================================================== 10 | 用到的技术 11 | Owin 12 | 实现webapi应用和服务器的解耦 13 | Autofac 14 | 依赖注入,面向接口编程 15 | Log4net 16 | 日志 17 | EF 18 | 数据库访问层,用code first 19 | 20 | 21 | 22 | 23 | 24 | =============================================================================== 25 | nuget包及dll介绍 26 | webapi相关的包 27 | --包Microsoft.AspNet.WebApi.Core 28 | packages里无dll,依赖于Microsoft.AspNet.WebApi.WebHost, 29 | webapi项目的必需包,安装后会下载Microsoft.AspNet.WebApi.WebHost和Microsoft.AspNet.WebApi.Core 30 | --包Microsoft.AspNet.WebApi.WebHost 31 | 在iis环境下用webapi时的必需包 32 | 含:System.Web.Http.WebHost.dll,依赖于包Microsoft.AspNet.WebApi.Core 33 | --包Microsoft.AspNet.WebApi.Core 34 | webapi技术的核心包 35 | 含:System.Web.Http.dll,依赖于包Microsoft.AspNet.WebApi.Client 36 | --包Microsoft.AspNet.WebApi.Client 37 | webapi核心包所依赖的类库 38 | 含:System.Net.Http.Formatting.dll 39 | 40 | owin相关 41 | --包Owin 42 | owin的接口规范 43 | --包Microsoft.Owin 44 | microsoft对owin规范的扩展 45 | --包Microsoft.Owin.Host.SystemWeb 46 | owin以iis为宿主时的必备包,负责拦截iis请求到owin管道,如果删除此dll,则会返回到iis asp.net request pipeline里 47 | 依赖:Microsoft.Owin和Owin包 48 | owin host相关 49 | --包Microsoft.Owin.SelfHost 50 | owin自宿主必备包,写自宿主程序时必需引用 51 | 依赖Microsoft.Owin.Hosting,Owin,Microsoft.Owin.Diagnostics,Microsoft.Owin.Host.HttpListener,Microsoft.Owin 52 | --包Microsoft.Owin.Hosting 53 | Provides default infrastructure types for hosting and running OWIN-based applications. 54 | --包Microsoft.Owin.Diagnostics 55 | Provides middleware components to assist in developing OWIN-based applications. 56 | --包Microsoft.Owin.Host.HttpListener 57 | OWIN server built on the .NET Framework's HttpListener class. Currently the default server used for self-hosting. 58 | 59 | webapi owin相关 60 | --包Microsoft.AspNet.WebApi.Owin 61 | 含:System.Web.Http.Owin.dll 62 | --包Microsoft.AspNet.WebApi.OwinSelfHost 63 | 无dll文件,依赖Microsoft.AspNet.WebApi.Owin ,Microsoft.Owin.Host.HttpListener,Microsoft.Owin.Hosting -------------------------------------------------------------------------------- /webapi/webapi.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | 9 | 10 | 2.0 11 | {7A63DCA6-5F3F-440A-934E-A92C162C0E82} 12 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 13 | Library 14 | Properties 15 | webapi 16 | webapi 17 | v4.6.1 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 12.0 28 | 29 | 30 | true 31 | full 32 | false 33 | bin\ 34 | DEBUG;TRACE 35 | prompt 36 | 4 37 | 38 | 39 | true 40 | pdbonly 41 | true 42 | bin\ 43 | TRACE 44 | prompt 45 | 4 46 | 47 | 48 | 49 | ..\packages\Autofac.3.5.0\lib\net40\Autofac.dll 50 | 51 | 52 | ..\packages\Autofac.Owin.4.1.0\lib\net45\Autofac.Integration.Owin.dll 53 | 54 | 55 | ..\packages\Autofac.WebApi2.4.1.0\lib\net45\Autofac.Integration.WebApi.dll 56 | 57 | 58 | ..\packages\Autofac.WebApi2.Owin.4.0.0\lib\net45\Autofac.Integration.WebApi.Owin.dll 59 | 60 | 61 | ..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll 62 | 63 | 64 | ..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll 65 | 66 | 67 | ..\packages\JWT.3.1.1\lib\net46\JWT.dll 68 | 69 | 70 | ..\packages\log4net.2.0.8\lib\net45-full\log4net.dll 71 | 72 | 73 | ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.7\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll 74 | 75 | 76 | 77 | ..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll 78 | 79 | 80 | ..\packages\Microsoft.Owin.Diagnostics.3.1.0\lib\net45\Microsoft.Owin.Diagnostics.dll 81 | 82 | 83 | ..\packages\Microsoft.Owin.Host.HttpListener.3.1.0\lib\net45\Microsoft.Owin.Host.HttpListener.dll 84 | 85 | 86 | ..\packages\Microsoft.Owin.Host.SystemWeb.3.1.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll 87 | 88 | 89 | ..\packages\Microsoft.Owin.Hosting.3.1.0\lib\net45\Microsoft.Owin.Hosting.dll 90 | 91 | 92 | ..\packages\MySql.Data.6.9.10\lib\net45\MySql.Data.dll 93 | 94 | 95 | ..\packages\MySql.Data.Entity.6.9.10\lib\net45\MySql.Data.Entity.EF6.dll 96 | 97 | 98 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 99 | 100 | 101 | ..\packages\Owin.1.0\lib\net40\Owin.dll 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll 110 | 111 | 112 | 113 | 114 | 115 | ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll 128 | 129 | 130 | ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll 131 | 132 | 133 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | Designer 146 | 147 | 148 | Designer 149 | 150 | 151 | 152 | Web.config 153 | 154 | 155 | Web.config 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | Global.asax 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 10.0 207 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | False 217 | True 218 | 10879 219 | / 220 | http://localhost:10879/ 221 | False 222 | True 223 | 224 | 225 | False 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 236 | 237 | 238 | 239 | 240 | 247 | -------------------------------------------------------------------------------- /webapi/webapi.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | true 5 | 6 | 7 | 8 | 9 | 10 | 11 | ApiControllerEmptyScaffolder 12 | root/Controller 13 | 600 14 | True 15 | False 16 | True 17 | 18 | False 19 | ShowAllFiles 20 | <_SelectedScaffolderID>ApiControllerEmptyScaffolder 21 | <_SelectedScaffolderCategoryPath>root/Common 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | NoStartPage 30 | True 31 | False 32 | False 33 | False 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | True 43 | True 44 | 45 | 46 | 47 | 48 | --------------------------------------------------------------------------------