1
0
Selaa lähdekoodia

添加项目文件。

Administrator 5 vuotta sitten
commit
e4fe549c64
100 muutettua tiedostoa jossa 4525 lisäystä ja 0 poistoa
  1. 63 0
      .gitattributes
  2. 348 0
      .gitignore
  3. 22 0
      Admin.Core.Common/Admin.Core.Common.csproj
  4. 13 0
      Admin.Core.Common/Attributes/TransactionAttribute.cs
  5. 14 0
      Admin.Core.Common/Auth/IUser.cs
  6. 9 0
      Admin.Core.Common/Auth/IUserToken.cs
  7. 132 0
      Admin.Core.Common/Auth/User.cs
  8. 36 0
      Admin.Core.Common/Auth/UserToken.cs
  9. 24 0
      Admin.Core.Common/Cache/CacheKey.cs
  10. 12 0
      Admin.Core.Common/Cache/CacheType.cs
  11. 108 0
      Admin.Core.Common/Cache/ICache.cs
  12. 128 0
      Admin.Core.Common/Cache/MemoryCache.cs
  13. 89 0
      Admin.Core.Common/Cache/RedisCache.cs
  14. 28 0
      Admin.Core.Common/Configs/AppConfig.cs
  15. 30 0
      Admin.Core.Common/Configs/CacheConfig.cs
  16. 61 0
      Admin.Core.Common/Configs/DbConfig.cs
  17. 31 0
      Admin.Core.Common/Configs/JwtConfig.cs
  18. 28 0
      Admin.Core.Common/Extensions/GuidExtensions.cs
  19. 22 0
      Admin.Core.Common/Extensions/MethodInfoExtensions.cs
  20. 93 0
      Admin.Core.Common/Extensions/StringExtensions.cs
  21. 54 0
      Admin.Core.Common/Helpers/ConfigHelper.cs
  22. 56 0
      Admin.Core.Common/Helpers/ConsoleHelper.cs
  23. 135 0
      Admin.Core.Common/Helpers/DESEncrypt.cs
  24. 112 0
      Admin.Core.Common/Helpers/FileHelper.cs
  25. 66 0
      Admin.Core.Common/Helpers/MD5Encrypt.cs
  26. 45 0
      Admin.Core.Common/Helpers/StringHelper.cs
  27. 40 0
      Admin.Core.Common/Helpers/UnicodeHelper.cs
  28. 189 0
      Admin.Core.Common/Helpers/UtilConvert.cs
  29. 81 0
      Admin.Core.Common/Helpers/VerifyCodeHelper.cs
  30. 16 0
      Admin.Core.Model/Admin.Core.Model.csproj
  31. 60 0
      Admin.Core.Model/Admin/ApiEntity.cs
  32. 52 0
      Admin.Core.Model/Admin/DictionaryEntity.cs
  33. 96 0
      Admin.Core.Model/Admin/PermissionEntity.cs
  34. 22 0
      Admin.Core.Model/Admin/PermissionType.cs
  35. 41 0
      Admin.Core.Model/Admin/RoleEntity.cs
  36. 49 0
      Admin.Core.Model/Admin/RolePermissionEntity.cs
  37. 59 0
      Admin.Core.Model/Admin/UserEntity.cs
  38. 34 0
      Admin.Core.Model/Admin/UserRoleEntity.cs
  39. 53 0
      Admin.Core.Model/Admin/ViewEntity.cs
  40. 22 0
      Admin.Core.Model/Base/Entity.cs
  41. 35 0
      Admin.Core.Model/Base/EntityAdd.cs
  42. 65 0
      Admin.Core.Model/Base/EntityBase.cs
  43. 20 0
      Admin.Core.Model/Base/EntitySoftDelete.cs
  44. 35 0
      Admin.Core.Model/Base/EntityUpdate.cs
  45. 20 0
      Admin.Core.Model/Base/EntityVersion.cs
  46. 11 0
      Admin.Core.Model/Base/IEntityAdd.cs
  47. 11 0
      Admin.Core.Model/Base/IEntitySoftDelete.cs
  48. 11 0
      Admin.Core.Model/Base/IEntityUpdate.cs
  49. 13 0
      Admin.Core.Model/Base/IEntityVersion.cs
  50. 23 0
      Admin.Core.Model/Input/PageInput.cs
  51. 28 0
      Admin.Core.Model/Output/IResponseOutput.cs
  52. 20 0
      Admin.Core.Model/Output/PageOutput.cs
  53. 127 0
      Admin.Core.Model/Output/ResponseOutput.cs
  54. 20 0
      Admin.Core.Repository/Admin.Core.Repository.csproj
  55. 13 0
      Admin.Core.Repository/Admin/Api/ApiRepository.cs
  56. 11 0
      Admin.Core.Repository/Admin/Api/IApiRepository.cs
  57. 13 0
      Admin.Core.Repository/Admin/Dictionary/DictionaryRepository.cs
  58. 9 0
      Admin.Core.Repository/Admin/Dictionary/IDictionaryRepository.cs
  59. 9 0
      Admin.Core.Repository/Admin/Permission/IPermissionRepository.cs
  60. 13 0
      Admin.Core.Repository/Admin/Permission/PermissionRepository.cs
  61. 8 0
      Admin.Core.Repository/Admin/Role/IRoleRepository.cs
  62. 13 0
      Admin.Core.Repository/Admin/Role/RoleRepository.cs
  63. 8 0
      Admin.Core.Repository/Admin/RolePermission/IRolePermissionRepository.cs
  64. 15 0
      Admin.Core.Repository/Admin/RolePermission/RolePermissionRepository.cs
  65. 8 0
      Admin.Core.Repository/Admin/User/IUserRepository.cs
  66. 13 0
      Admin.Core.Repository/Admin/User/UserRepository.cs
  67. 10 0
      Admin.Core.Repository/Admin/UserRole/IUserRoleRepository.cs
  68. 13 0
      Admin.Core.Repository/Admin/UserRole/UserRoleRepository.cs
  69. 11 0
      Admin.Core.Repository/Admin/View/IViewRepositoryRepository.cs
  70. 14 0
      Admin.Core.Repository/Admin/View/ViewRepositoryRepository.cs
  71. 30 0
      Admin.Core.Repository/Base/IRepositoryBase.cs
  72. 48 0
      Admin.Core.Repository/Base/RepositoryBase.cs
  73. 33 0
      Admin.Core.Services/Admin.Core.Service.csproj
  74. 217 0
      Admin.Core.Services/Admin/Api/ApiService.cs
  75. 78 0
      Admin.Core.Services/Admin/Api/IApiService.cs
  76. 38 0
      Admin.Core.Services/Admin/Api/Input/ApiAddInput.cs
  77. 28 0
      Admin.Core.Services/Admin/Api/Input/ApiSyncDto.cs
  78. 12 0
      Admin.Core.Services/Admin/Api/Input/ApiSyncInput.cs
  79. 18 0
      Admin.Core.Services/Admin/Api/Input/ApiUpdateInput.cs
  80. 8 0
      Admin.Core.Services/Admin/Api/Output/ApiGetOutput.cs
  81. 45 0
      Admin.Core.Services/Admin/Api/Output/ApiListOutput.cs
  82. 19 0
      Admin.Core.Services/Admin/Api/_MapConfig.cs
  83. 196 0
      Admin.Core.Services/Admin/Auth/AuthService.cs
  84. 21 0
      Admin.Core.Services/Admin/Auth/IAuthService.cs
  85. 33 0
      Admin.Core.Services/Admin/Auth/Input/AuthLoginInput.cs
  86. 17 0
      Admin.Core.Services/Admin/Auth/_MapConfig.cs
  87. 92 0
      Admin.Core.Services/Admin/Dictionary/DictionaryService.cs
  88. 25 0
      Admin.Core.Services/Admin/Dictionary/IDictionaryService.cs
  89. 38 0
      Admin.Core.Services/Admin/Dictionary/Input/DictionaryAddInput.cs
  90. 18 0
      Admin.Core.Services/Admin/Dictionary/Input/DictionaryUpdateInput.cs
  91. 8 0
      Admin.Core.Services/Admin/Dictionary/Output/DictionaryGetOutput.cs
  92. 47 0
      Admin.Core.Services/Admin/Dictionary/Output/DictionaryListOutput.cs
  93. 18 0
      Admin.Core.Services/Admin/Dictionary/_MapConfig.cs
  94. 43 0
      Admin.Core.Services/Admin/Permission/IPermissionService.cs
  95. 47 0
      Admin.Core.Services/Admin/Permission/Input/PermissionAddApiInput.cs
  96. 47 0
      Admin.Core.Services/Admin/Permission/Input/PermissionAddGroupInput.cs
  97. 67 0
      Admin.Core.Services/Admin/Permission/Input/PermissionAddMenuInput.cs
  98. 10 0
      Admin.Core.Services/Admin/Permission/Input/PermissionAssignInput.cs
  99. 15 0
      Admin.Core.Services/Admin/Permission/Input/PermissionUpdateApiInput.cs
  100. 16 0
      Admin.Core.Services/Admin/Permission/Input/PermissionUpdateGroupInput.cs

+ 63 - 0
.gitattributes

@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs     diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following 
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln       merge=binary
+#*.csproj    merge=binary
+#*.vbproj    merge=binary
+#*.vcxproj   merge=binary
+#*.vcproj    merge=binary
+#*.dbproj    merge=binary
+#*.fsproj    merge=binary
+#*.lsproj    merge=binary
+#*.wixproj   merge=binary
+#*.modelproj merge=binary
+#*.sqlproj   merge=binary
+#*.wwaproj   merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg   binary
+#*.png   binary
+#*.gif   binary
+
+###############################################################################
+# diff behavior for common document formats
+# 
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the 
+# entries below.
+###############################################################################
+#*.doc   diff=astextplain
+#*.DOC   diff=astextplain
+#*.docx  diff=astextplain
+#*.DOCX  diff=astextplain
+#*.dot   diff=astextplain
+#*.DOT   diff=astextplain
+#*.pdf   diff=astextplain
+#*.PDF   diff=astextplain
+#*.rtf   diff=astextplain
+#*.RTF   diff=astextplain

+ 348 - 0
.gitignore

@@ -0,0 +1,348 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
+**/wwwroot/lib/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database 
+healthchecksdb
+
+
+# wwwroot/images
+*images/
+.1YourProject
+!Admin.Core.Webapi.Template.1.0.0.nupkg
+/Admin.Core/.config

+ 22 - 0
Admin.Core.Common/Admin.Core.Common.csproj

@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="CSRedisCore" Version="3.5.1" />
+    <PackageReference Include="FreeSql" Version="1.2.1" />
+    <PackageReference Include="FreeSql.Provider.MySql" Version="1.2.1" />
+    <PackageReference Include="FreeSql.Provider.Sqlite" Version="1.2.1" />
+    <PackageReference Include="FreeSql.Repository" Version="1.2.1" />
+    <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
+    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.2" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.2" />
+    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.2" />
+    <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="5.6.0" />
+    <PackageReference Include="System.Drawing.Common" Version="4.7.0" />
+    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.6.0" />
+  </ItemGroup>
+
+</Project>

+ 13 - 0
Admin.Core.Common/Attributes/TransactionAttribute.cs

@@ -0,0 +1,13 @@
+using System;
+
+namespace Admin.Core.Common
+{
+    /// <summary>
+    /// 启用事物
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Method, Inherited = true)]
+    public class TransactionAttribute : Attribute
+    {
+
+    }
+}

+ 14 - 0
Admin.Core.Common/Auth/IUser.cs

@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using System.Security.Claims;
+
+namespace Admin.Core.Common.Auth
+{
+    public interface IUser
+    {
+        long Id { get; }
+        string Name { get; }
+        bool IsAuthenticated();
+        IEnumerable<Claim> GetClaimsIdentity();
+        List<string> GetClaimValueByType(string ClaimType);
+    }
+}

+ 9 - 0
Admin.Core.Common/Auth/IUserToken.cs

@@ -0,0 +1,9 @@
+using System.Security.Claims;
+
+namespace Admin.Core.Common.Auth
+{
+    public interface IUserToken
+    {
+        string Build(Claim[] claims);
+    }
+}

+ 132 - 0
Admin.Core.Common/Auth/User.cs

@@ -0,0 +1,132 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using Microsoft.AspNetCore.Http;
+
+namespace Admin.Core.Common.Auth
+{
+    /// <summary>
+    /// 用户信息
+    /// </summary>
+    public class User : IUser
+    {
+        private readonly IHttpContextAccessor _accessor;
+
+        public User(IHttpContextAccessor accessor)
+        {
+            _accessor = accessor;
+        }
+
+        /// <summary>
+        /// 用户Id
+        /// </summary>
+        public long Id
+        {
+            get
+            {
+                var id = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.UserId);
+                if (id != null && id.Value.NotNull())
+                {
+                    return id.Value.ToLong();
+                }
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 用户名
+        /// </summary>
+        public string Name
+        {
+            get
+            {
+                var name = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.UserName);
+
+                if (name != null && name.Value.NotNull())
+                {
+                    return name.Value;
+                }
+
+                return "";
+            }
+        }
+
+
+        /// <summary>
+        /// 用户IP
+        /// </summary>
+        public string IP
+        {
+            get
+            {
+                if (_accessor?.HttpContext?.Connection == null)
+                    return "";
+
+                return _accessor.HttpContext.Connection.RemoteIpAddress.ToString();
+            }
+        }
+
+        /// <summary>
+        /// 用户IPv4
+        /// </summary>
+        public string IPv4
+        {
+            get
+            {
+                if (_accessor?.HttpContext?.Connection == null)
+                    return "";
+
+                return _accessor.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
+            }
+        }
+
+        /// <summary>
+        /// 用户IPv6
+        /// </summary>
+        public string IPv6
+        {
+            get
+            {
+                if (_accessor?.HttpContext?.Connection == null)
+                    return "";
+
+                return _accessor.HttpContext.Connection.RemoteIpAddress.MapToIPv6().ToString();
+            }
+        }
+
+        public bool IsAuthenticated()
+        {
+            return _accessor.HttpContext.User.Identity.IsAuthenticated;
+        }
+
+        public IEnumerable<Claim> GetClaimsIdentity()
+        {
+            return _accessor.HttpContext.User.Claims;
+        }
+
+        public List<string> GetClaimValueByType(string ClaimType)
+        {
+
+            return (from item in GetClaimsIdentity()
+                    where item.Type == ClaimType
+                    select item.Value).ToList();
+
+        }
+    }
+
+    /// <summary>
+    /// Claim属性
+    /// </summary>
+    public static class ClaimAttributes
+    {
+        /// <summary>
+        /// 用户Id
+        /// </summary>
+        public const string UserId = "id";
+
+        /// <summary>
+        /// 用户名
+        /// </summary>
+        public const string UserName = "na";
+    }
+}

+ 36 - 0
Admin.Core.Common/Auth/UserToken.cs

@@ -0,0 +1,36 @@
+
+using System;
+using System.Text;
+using System.Security.Claims;
+using System.IdentityModel.Tokens.Jwt;
+using Microsoft.IdentityModel.Tokens;
+using Admin.Core.Common.Configs;
+
+namespace Admin.Core.Common.Auth
+{
+    public class UserToken : IUserToken
+    {
+        private readonly JwtConfig _jwtConfig;
+
+        public UserToken(JwtConfig jwtConfig)
+        {
+            _jwtConfig = jwtConfig;
+        }
+
+        public string Build(Claim[] claims)
+        {
+            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtConfig.SecurityKey));
+            var signingCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
+
+            var token = new JwtSecurityToken(
+                issuer: _jwtConfig.Issuer,
+                audience: _jwtConfig.Audience,
+                claims: claims,
+                notBefore: DateTime.Now,
+                expires: DateTime.Now.AddMinutes(_jwtConfig.Expires),
+                signingCredentials: signingCredentials
+            );
+            return new JwtSecurityTokenHandler().WriteToken(token);
+        }
+    }
+}

+ 24 - 0
Admin.Core.Common/Cache/CacheKey.cs

@@ -0,0 +1,24 @@
+
+namespace Admin.Core.Common.Cache
+{
+    /// <summary>
+    /// 缓存键
+    /// </summary>
+    public static class CacheKey
+    {
+        /// <summary>
+        /// 验证码 admin:verify:code:guid
+        /// </summary>
+        public const string VerifyCodeKey = "admin:verify:code:{0}";
+
+        /// <summary>
+        /// 密码 admin:password:guid
+        /// </summary>
+        public const string PassWordKey = "admin:password:{0}";
+
+        /// <summary>
+        /// 用户权限 admin:user:用户主键:permissions
+        /// </summary>
+        public const string UserPermissions = "admin:user:{0}:permissions";
+    }
+}

+ 12 - 0
Admin.Core.Common/Cache/CacheType.cs

@@ -0,0 +1,12 @@
+
+namespace Admin.Core.Common.Cache
+{
+    /// <summary>
+    /// 缓存类型
+    /// </summary>
+    public enum CacheType
+    {
+        Memory,
+        Redis
+    }
+}

+ 108 - 0
Admin.Core.Common/Cache/ICache.cs

@@ -0,0 +1,108 @@
+
+using System;
+using System.Threading.Tasks;
+
+namespace Admin.Core.Common.Cache
+{
+    /// <summary>
+    /// 缓存接口
+    /// </summary>
+    public interface ICache
+    {
+        /// <summary>
+        /// 用于在 key 存在时删除 key
+        /// </summary>
+        /// <param name="key">键</param>
+        long Del(params string[] key);
+
+        /// <summary>
+        /// 用于在 key 存在时删除 key
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns></returns>
+        Task<long> DelAsync(params string[] key);
+
+        /// <summary>
+        /// 用于在 key 模板存在时删除
+        /// </summary>
+        /// <param name="pattern">key模板</param>
+        /// <returns></returns>
+        Task<long> DelByPatternAsync(string pattern);
+
+        /// <summary>
+        /// 检查给定 key 是否存在
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns></returns>
+        bool Exists(string key);
+
+        /// <summary>
+        /// 检查给定 key 是否存在
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns></returns>
+        Task<bool> ExistsAsync(string key);
+
+        /// <summary>
+        /// 获取指定 key 的值
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns></returns>
+        string Get(string key);
+
+        /// <summary>
+        /// 获取指定 key 的值
+        /// </summary>
+        /// <typeparam name="T">byte[] 或其他类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns></returns>
+        T Get<T>(string key);
+
+        /// <summary>
+        /// 获取指定 key 的值
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns></returns>
+        Task<string> GetAsync(string key);
+
+        /// <summary>
+        /// 获取指定 key 的值
+        /// </summary>
+        /// <typeparam name="T">byte[] 或其他类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns></returns>
+        Task<T> GetAsync<T>(string key);
+
+        /// <summary>
+        /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        bool Set(string key, object value);
+
+        /// <summary>
+        /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        /// <param name="expire">有效期</param>
+        bool Set(string key, object value, TimeSpan expire);
+
+        /// <summary>
+        /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        /// <returns></returns>
+        Task<bool> SetAsync(string key, object value);
+
+        /// <summary>
+        /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        /// <param name="expire">有效期</param>
+        /// <returns></returns>
+        Task<bool> SetAsync(string key, object value, TimeSpan expire);
+    }
+}

+ 128 - 0
Admin.Core.Common/Cache/MemoryCache.cs

@@ -0,0 +1,128 @@
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Caching.Memory;
+
+namespace Admin.Core.Common.Cache
+{
+    /// <summary>
+    /// 内存缓存
+    /// </summary>
+    public class MemoryCache : ICache
+    {
+        private readonly IMemoryCache _memoryCache;
+        public MemoryCache(IMemoryCache memoryCache)
+        {
+            _memoryCache = memoryCache;
+        }
+
+        public long Del(params string[] key)
+        {
+            foreach(var k in key)
+            {
+                _memoryCache.Remove(k);
+            }
+            return key.Length;
+        }
+
+        public Task<long> DelAsync(params string[] key)
+        {
+            foreach (var k in key)
+            {
+                _memoryCache.Remove(k);
+            }
+
+            return Task.FromResult(key.Length.ToLong());
+        }
+
+        public async Task<long> DelByPatternAsync(string pattern)
+        {
+            if (pattern.IsNull())
+                return default;
+
+            pattern = Regex.Replace(pattern, @"\{.*\}", "(.*)");
+
+            var keys = GetAllKeys().Where(k => Regex.IsMatch(k, pattern));
+            
+            if(keys != null && keys.Count() > 0)
+            {
+                return await DelAsync(keys.ToArray());
+            }
+
+            return default;
+        }
+
+        public bool Exists(string key)
+        {
+            return _memoryCache.TryGetValue(key, out _);
+        }
+
+        public Task<bool> ExistsAsync(string key)
+        {
+            return Task.FromResult(_memoryCache.TryGetValue(key, out _));
+        }
+
+        public string Get(string key)
+        {
+            return _memoryCache.Get(key)?.ToString();
+        }
+
+        public T Get<T>(string key)
+        {
+            return _memoryCache.Get<T>(key);
+        }
+
+        public Task<string> GetAsync(string key)
+        {
+            return Task.FromResult(Get(key));
+        }
+
+        public Task<T> GetAsync<T>(string key)
+        {
+            return Task.FromResult(Get<T>(key));
+        }
+
+        public bool Set(string key, object value)
+        {
+            _memoryCache.Set(key, value);
+            return true;
+        }
+
+        public bool Set(string key, object value, TimeSpan expire)
+        {
+            _memoryCache.Set(key, value, expire);
+            return true;
+        }
+
+        public Task<bool> SetAsync(string key, object value)
+        {
+            Set(key, value);
+            return Task.FromResult(true);
+        }
+
+        public Task<bool> SetAsync(string key, object value, TimeSpan expire)
+        {
+            Set(key, value, expire);
+            return Task.FromResult(true);
+        }
+
+        private List<string> GetAllKeys()
+        {
+            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
+            var entries = _memoryCache.GetType().GetField("_entries", flags).GetValue(_memoryCache);
+            var cacheItems = entries as IDictionary;
+            var keys = new List<string>();
+            if (cacheItems == null) return keys;
+            foreach (DictionaryEntry cacheItem in cacheItems)
+            {
+                keys.Add(cacheItem.Key.ToString());
+            }
+            return keys;
+        }
+    }
+}

+ 89 - 0
Admin.Core.Common/Cache/RedisCache.cs

@@ -0,0 +1,89 @@
+
+using System;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace Admin.Core.Common.Cache
+{
+    /// <summary>
+    /// Redis缓存
+    /// </summary>
+    public class RedisCache : ICache
+    {
+        public long Del(params string[] key)
+        {
+            return RedisHelper.Del(key);
+        }
+
+        public Task<long> DelAsync(params string[] key)
+        {
+            return RedisHelper.DelAsync(key);
+        }
+
+        public async Task<long> DelByPatternAsync(string pattern)
+        {
+            if (pattern.IsNull())
+                return default;
+
+            pattern = Regex.Replace(pattern, @"\{.*\}", "*");
+
+            var keys = (await RedisHelper.KeysAsync(pattern));
+            if(keys != null && keys.Length > 0)
+            {
+                return await RedisHelper.DelAsync(keys);
+            }
+
+            return default;
+        }
+
+        public bool Exists(string key)
+        {
+            return RedisHelper.Exists(key);
+        }
+
+        public Task<bool> ExistsAsync(string key)
+        {
+            return RedisHelper.ExistsAsync(key);
+        }
+
+        public string Get(string key)
+        {
+            return RedisHelper.Get(key);
+        }
+
+        public T Get<T>(string key)
+        {
+            return RedisHelper.Get<T>(key);
+        }
+
+        public Task<string> GetAsync(string key)
+        {
+            return RedisHelper.GetAsync(key);
+        }
+
+        public Task<T> GetAsync<T>(string key)
+        {
+            return RedisHelper.GetAsync<T>(key);
+        }
+
+        public bool Set(string key, object value)
+        {
+            return RedisHelper.Set(key, value);
+        }
+
+        public bool Set(string key, object value, TimeSpan expire)
+        {
+            return RedisHelper.Set(key, value, expire);
+        }
+
+        public Task<bool> SetAsync(string key, object value)
+        {
+            return RedisHelper.SetAsync(key, value);
+        }
+
+        public Task<bool> SetAsync(string key, object value, TimeSpan expire)
+        {
+            return RedisHelper.SetAsync(key, value, expire);
+        }
+    }
+}

+ 28 - 0
Admin.Core.Common/Configs/AppConfig.cs

@@ -0,0 +1,28 @@
+namespace Admin.Core.Common.Configs
+{
+    /// <summary>
+    /// 应用配置
+    /// </summary>
+    public class AppConfig
+    {
+        /// <summary>
+        /// Swagger文档
+        /// </summary>
+        public bool Swagger { get; set; }
+
+        /// <summary>
+        /// Api地址,默认 http://*:8081
+        /// </summary>
+        public string Urls { get; set; } = "http://*:8081";
+
+        public AopConfig Aop { get; set; }
+    }
+
+    public class AopConfig
+    {
+        /// <summary>
+        /// 事物
+        /// </summary>
+        public bool Transaction { get; set; }
+    }
+}

+ 30 - 0
Admin.Core.Common/Configs/CacheConfig.cs

@@ -0,0 +1,30 @@
+
+
+using Admin.Core.Common.Cache;
+
+namespace Admin.Core.Common.Configs
+{
+    /// <summary>
+    /// 缓存配置
+    /// </summary>
+    public class CacheConfig
+    {
+        /// <summary>
+        /// 缓存类型
+        /// </summary>
+        public CacheType Type { get; set; }
+
+        /// <summary>
+        /// Redis配置
+        /// </summary>
+        public RedisConfig Redis { get; set; }
+    }
+
+    public class RedisConfig
+    {
+        /// <summary>
+        /// 连接字符串
+        /// </summary>
+        public string ConnectionString { get; set; }
+    }
+}

+ 61 - 0
Admin.Core.Common/Configs/DbConfig.cs

@@ -0,0 +1,61 @@
+
+using DataType = FreeSql.DataType;
+
+namespace Admin.Core.Common.Configs
+{
+    /// <summary>
+    /// 数据库配置
+    /// </summary>
+    public class DbConfig
+    {
+        /// <summary>
+        /// 数据库类型
+        /// </summary>
+        public DataType Type { get; set; }
+
+        /// <summary>
+        /// 数据库字符串
+        /// </summary>
+        public string ConnectionString { get; set; }
+
+        /// <summary>
+        /// 生成数据
+        /// </summary>
+        public bool GenerateData { get; set; }
+
+        /// <summary>
+        /// 同步结构
+        /// </summary>
+        public bool SyncStructure { get; set; }
+
+        /// <summary>
+        /// 同步数据
+        /// </summary>
+        public bool SyncData { get; set; }
+
+        /// <summary>
+        /// 建库
+        /// </summary>
+        public bool CreateDb { get; set; }
+
+        /// <summary>
+        /// 建库连接字符串
+        /// </summary>
+        public string CreateDbConnectionString { get; set; }
+
+        /// <summary>
+        /// 建库脚本
+        /// </summary>
+        public string CreateDbSql { get; set; }
+
+        /// <summary>
+        /// 监听所有操作
+        /// </summary>
+        public bool MonitorCommand { get; set; }
+
+        /// <summary>
+        /// 监听Curd操作
+        /// </summary>
+        public bool Curd { get; set; }
+    }
+}

+ 31 - 0
Admin.Core.Common/Configs/JwtConfig.cs

@@ -0,0 +1,31 @@
+
+using DataType = FreeSql.DataType;
+
+namespace Admin.Core.Common.Configs
+{
+    /// <summary>
+    /// Jwt配置
+    /// </summary>
+    public class JwtConfig
+    {
+        /// <summary>
+        /// 发行者
+        /// </summary>
+        public string Issuer { get; set; }
+
+        /// <summary>
+        /// 订阅者
+        /// </summary>
+        public string Audience { get; set; }
+
+        /// <summary>
+        /// 秘钥
+        /// </summary>
+        public string SecurityKey { get; set; }
+
+        /// <summary>
+        /// 有效期(分钟)
+        /// </summary>
+        public int Expires { get; set; }
+    }
+}

+ 28 - 0
Admin.Core.Common/Extensions/GuidExtensions.cs

@@ -0,0 +1,28 @@
+using System;
+
+namespace Admin.Core
+{
+    public static class GuidExtensions
+    {
+        /// <summary>
+        /// 判断Guid是否为空
+        /// </summary>
+        /// <param name="s"></param>
+        /// <returns></returns>
+        public static bool IsNull(this Guid s)
+        {
+            return s == Guid.Empty;
+        }
+
+        /// <summary>
+        /// 判断Guid是否不为空
+        /// </summary>
+        /// <param name="s"></param>
+        /// <returns></returns>
+        public static bool NotNull(this Guid s)
+        {
+            return s != Guid.Empty;
+        }
+
+    }
+}

+ 22 - 0
Admin.Core.Common/Extensions/MethodInfoExtensions.cs

@@ -0,0 +1,22 @@
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace Admin.Core.Extensions
+{
+    public static class MethodInfoExtensions
+    {
+        public static bool HasAttribute<T>(this MethodInfo method)
+        {
+            return method.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(T)) is T;
+
+        }
+
+        public static bool IsAsync(this MethodInfo method)
+        {
+            return method.ReturnType == typeof(Task)
+                || (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>));
+
+        }
+    }
+}

+ 93 - 0
Admin.Core.Common/Extensions/StringExtensions.cs

@@ -0,0 +1,93 @@
+using System;
+using System.Linq;
+using System.Text;
+
+namespace Admin.Core
+{
+    public static class StringExtensions
+    {
+        /// <summary>
+        /// 判断字符串是否为Null、空
+        /// </summary>
+        /// <param name="s"></param>
+        /// <returns></returns>
+        public static bool IsNull(this string s)
+        {
+            return string.IsNullOrWhiteSpace(s);
+        }
+
+        /// <summary>
+        /// 判断字符串是否不为Null、空
+        /// </summary>
+        /// <param name="s"></param>
+        /// <returns></returns>
+        public static bool NotNull(this string s)
+        {
+            return !string.IsNullOrWhiteSpace(s);
+        }
+
+        /// <summary>
+        /// 与字符串进行比较,忽略大小写
+        /// </summary>
+        /// <param name="s"></param>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public static bool EqualsIgnoreCase(this string s, string value)
+        {
+            return s.Equals(value, StringComparison.OrdinalIgnoreCase);
+        }
+
+        /// <summary>
+        /// 首字母转小写
+        /// </summary>
+        /// <param name="s"></param>
+        /// <returns></returns>
+        public static string FirstCharToLower(this string s)
+        {
+            if (string.IsNullOrEmpty(s))
+                return s;
+
+            string str = s.First().ToString().ToLower() + s.Substring(1);
+            return str;
+        }
+
+        /// <summary>
+        /// 首字母转大写
+        /// </summary>
+        /// <param name="s"></param>
+        /// <returns></returns>
+        public static string FirstCharToUpper(this string s)
+        {
+            if (string.IsNullOrEmpty(s))
+                return s;
+
+            string str = s.First().ToString().ToUpper() + s.Substring(1);
+            return str;
+        }
+
+        /// <summary>
+        /// 转为Base64,UTF-8格式
+        /// </summary>
+        /// <param name="s"></param>
+        /// <returns></returns>
+        public static string ToBase64(this string s)
+        {
+            return s.ToBase64(Encoding.UTF8);
+        }
+
+        /// <summary>
+        /// 转为Base64
+        /// </summary>
+        /// <param name="s"></param>
+        /// <param name="encoding">编码</param>
+        /// <returns></returns>
+        public static string ToBase64(this string s, Encoding encoding)
+        {
+            if (s.IsNull())
+                return string.Empty;
+
+            var bytes = encoding.GetBytes(s);
+            return bytes.ToBase64();
+        }
+    }
+}

+ 54 - 0
Admin.Core.Common/Helpers/ConfigHelper.cs

@@ -0,0 +1,54 @@
+using System;
+using System.IO;
+using Microsoft.Extensions.Configuration;
+
+namespace Admin.Core.Common.Helpers
+{
+    /// <summary>
+    /// 配置帮助类
+    /// </summary>
+    public class ConfigHelper
+    {
+        /// <summary>
+        /// 加载配置文件
+        /// </summary>
+        /// <param name="fileName">文件名称</param>
+        /// <param name="environmentName">环境名称</param>
+        /// <param name="reloadOnChange">自动更新</param>
+        /// <returns></returns>
+        public IConfiguration Load(string fileName, string environmentName = "", bool reloadOnChange = false)
+        {
+            var filePath = Path.Combine(AppContext.BaseDirectory, "configs");
+            if (!Directory.Exists(filePath))
+                return null;
+
+            var builder = new ConfigurationBuilder()
+                .SetBasePath(filePath)
+                .AddJsonFile(fileName.ToLower() + ".json", true, reloadOnChange);
+
+            if (environmentName.NotNull())
+            {
+                builder.AddJsonFile(fileName.ToLower() + "." + environmentName + ".json", true, reloadOnChange);
+            }
+
+            return builder.Build();
+        }
+
+        /// <summary>
+        /// 获得配置信息
+        /// </summary>
+        /// <typeparam name="T">配置信息</typeparam>
+        /// <param name="fileName"></param>
+        /// <param name="environmentName">文件名称</param>
+        /// <param name="reloadOnChange">自动更新</param>
+        /// <returns></returns>
+        public T Get<T>(string fileName, string environmentName = "", bool reloadOnChange = false)
+        {
+            var configuration = Load(fileName, environmentName, reloadOnChange);
+            if (configuration == null)
+                return default;
+
+            return configuration.Get<T>();
+        }
+    }
+}

+ 56 - 0
Admin.Core.Common/Helpers/ConsoleHelper.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Admin.Core.Common.Helpers
+{
+    public static class ConsoleHelper
+    {
+        static void WriteColorLine(string str, ConsoleColor color)
+        {
+            ConsoleColor currentForeColor = Console.ForegroundColor;
+            Console.ForegroundColor = color;
+            Console.WriteLine(str);
+            Console.ForegroundColor = currentForeColor;
+        }
+
+        /// <summary>
+        /// 打印错误信息
+        /// </summary>
+        /// <param name="str">待打印的字符串</param>
+        /// <param name="color">想要打印的颜色</param>
+        public static void WriteErrorLine(this string str, ConsoleColor color = ConsoleColor.Red)
+        {
+            WriteColorLine(str, color);
+        }
+
+        /// <summary>
+        /// 打印警告信息
+        /// </summary>
+        /// <param name="str">待打印的字符串</param>
+        /// <param name="color">想要打印的颜色</param>
+        public static void WriteWarningLine(this string str, ConsoleColor color = ConsoleColor.Yellow)
+        {
+            WriteColorLine(str, color);
+        }
+        /// <summary>
+        /// 打印正常信息
+        /// </summary>
+        /// <param name="str">待打印的字符串</param>
+        /// <param name="color">想要打印的颜色</param>
+        public static void WriteInfoLine(this string str, ConsoleColor color = ConsoleColor.White)
+        {
+            WriteColorLine(str, color);
+        }
+        /// <summary>
+        /// 打印成功的信息
+        /// </summary>
+        /// <param name="str">待打印的字符串</param>
+        /// <param name="color">想要打印的颜色</param>
+        public static void WriteSuccessLine(this string str, ConsoleColor color = ConsoleColor.Green)
+        {
+            WriteColorLine(str, color);
+        }
+
+    }
+}

+ 135 - 0
Admin.Core.Common/Helpers/DESEncrypt.cs

@@ -0,0 +1,135 @@
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Admin.Core.Common.Helpers
+{
+    /// <summary>
+    /// Des加解密
+    /// </summary>
+    public class DesEncrypt
+    {
+        private const string Key = "desenc1!";
+
+        /// <summary>
+        /// DES+Base64加密
+        /// <para>采用ECB、PKCS7</para>
+        /// </summary>
+        /// <param name="encryptString">加密字符串</param>
+        /// <param name="key">秘钥</param>
+        /// <returns></returns>
+        public static string Encrypt(string encryptString, string key = null)
+        {
+            return Encrypt(encryptString, key, false, true);
+        }
+
+        /// <summary>
+        /// DES+Base64解密
+        /// <para>采用ECB、PKCS7</para>
+        /// </summary>
+        /// <param name="decryptString">解密字符串</param>
+        /// <param name="key">秘钥</param>
+        /// <returns></returns>
+        public static string Decrypt(string decryptString, string key = null)
+        {
+            return Decrypt(decryptString, key, false);
+        }
+
+        /// <summary>
+        /// DES+16进制加密
+        /// <para>采用ECB、PKCS7</para>
+        /// </summary>
+        /// <param name="encryptString">加密字符串</param>
+        /// <param name="key">秘钥</param>
+        /// <param name="lowerCase">是否小写</param>
+        /// <returns></returns>
+        public static string Encrypt4Hex(string encryptString, string key = null, bool lowerCase = false)
+        {
+            return Encrypt(encryptString, key, true, lowerCase);
+        }
+
+        /// <summary>
+        /// DES+16进制解密
+        /// <para>采用ECB、PKCS7</para>
+        /// </summary>
+        /// <param name="decryptString">解密字符串</param>
+        /// <param name="key">秘钥</param>
+        /// <returns></returns>
+        public static string Decrypt4Hex(string decryptString, string key = null)
+        {
+            return Decrypt(decryptString, key, true);
+        }
+
+        /// <summary>
+        /// DES加密
+        /// </summary>
+        /// <param name="encryptString"></param>
+        /// <param name="key"></param>
+        /// <param name="hex"></param>
+        /// <param name="lowerCase"></param>
+        /// <returns></returns>
+        private static string Encrypt(string encryptString, string key, bool hex, bool lowerCase = false)
+        {
+            if (encryptString.IsNull())
+                return null;
+            if (key.IsNull())
+                key = Key;
+            if (key.Length < 8)
+                throw new ArgumentException("秘钥长度为8位", nameof(key));
+
+            var keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 8));
+            var inputByteArray = Encoding.UTF8.GetBytes(encryptString);
+            var provider = new DESCryptoServiceProvider
+            {
+                Mode = CipherMode.ECB,
+                Key = keyBytes,
+                Padding = PaddingMode.PKCS7
+            };
+
+            using (var stream = new MemoryStream())
+            {
+                var cStream = new CryptoStream(stream, provider.CreateEncryptor(), CryptoStreamMode.Write);
+                cStream.Write(inputByteArray, 0, inputByteArray.Length);
+                cStream.FlushFinalBlock();
+
+                var bytes = stream.ToArray();
+                return hex ? bytes.ToHex(lowerCase) : bytes.ToBase64();
+            }
+        }
+
+        /// <summary>
+        /// DES解密
+        /// </summary>
+        /// <param name="decryptString"></param>
+        /// <param name="key"></param>
+        /// <param name="hex"></param>
+        /// <returns></returns>
+        private static string Decrypt(string decryptString, string key, bool hex)
+        {
+            if (decryptString.IsNull())
+                return null;
+            if (key.IsNull())
+                key = Key;
+            if (key.Length < 8)
+                throw new ArgumentException("秘钥长度为8位", nameof(key));
+
+            var keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 8));
+            var inputByteArray = hex ? decryptString.HexToBytes() : Convert.FromBase64String(decryptString);
+            var provider = new DESCryptoServiceProvider
+            {
+                Mode = CipherMode.ECB,
+                Key = keyBytes,
+                Padding = PaddingMode.PKCS7
+            };
+
+            using (var mStream = new MemoryStream())
+            {
+                var cStream = new CryptoStream(mStream, provider.CreateDecryptor(), CryptoStreamMode.Write);
+                cStream.Write(inputByteArray, 0, inputByteArray.Length);
+                cStream.FlushFinalBlock();
+                return Encoding.UTF8.GetString(mStream.ToArray());
+            }
+        }
+    }
+}

+ 112 - 0
Admin.Core.Common/Helpers/FileHelper.cs

@@ -0,0 +1,112 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace Admin.Core.Common.Helpers
+{
+    public class FileHelper : IDisposable
+    {
+        private bool _alreadyDispose = false;
+
+        public FileHelper()
+        {
+        }
+        ~FileHelper()
+        {
+            Dispose();
+        }
+
+        protected virtual void Dispose(bool isDisposing)
+        {
+            if (_alreadyDispose) return;
+            _alreadyDispose = true;
+        }
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        #region 写文件
+        /// <summary>
+        /// 写文件
+        /// </summary>
+        /// <param name="Path">文件路径</param>
+        /// <param name="Strings">文件内容</param>
+        public static void WriteFile(string Path, string Strings)
+        {
+            if (!File.Exists(Path))
+            {
+                File.Create(Path).Close();
+            }
+            StreamWriter streamWriter = new StreamWriter(Path, false);
+            streamWriter.Write(Strings);
+            streamWriter.Close();
+            streamWriter.Dispose();
+        }
+
+        /// <summary>
+        /// 写文件
+        /// </summary>
+        /// <param name="Path">文件路径</param>
+        /// <param name="Strings">文件内容</param>
+        /// <param name="encode">编码格式</param>
+        public static void WriteFile(string Path, string Strings, Encoding encode)
+        {
+            if (!File.Exists(Path))
+            {
+                File.Create(Path).Close();
+            }
+            StreamWriter streamWriter = new StreamWriter(Path, false, encode);
+            streamWriter.Write(Strings);
+            streamWriter.Close();
+            streamWriter.Dispose();
+        }
+        #endregion
+
+        #region 读文件
+        /// <summary>
+        /// 读文件
+        /// </summary>
+        /// <param name="Path">文件路径</param>
+        /// <returns></returns>
+        public static string ReadFile(string Path)
+        {
+            string s;
+            if (!File.Exists(Path))
+                s = "不存在相应的目录";
+            else
+            {
+                StreamReader streamReader = new StreamReader(Path);
+                s = streamReader.ReadToEnd();
+                streamReader.Close();
+                streamReader.Dispose();
+            }
+
+            return s;
+        }
+
+        /// <summary>
+        /// 读文件
+        /// </summary>
+        /// <param name="Path">文件路径</param>
+        /// <param name="encode">编码格式</param>
+        /// <returns></returns>
+        public static string ReadFile(string Path, Encoding encode)
+        {
+            string s;
+            if (!File.Exists(Path))
+                s = "不存在相应的目录";
+            else
+            {
+                StreamReader streamReader = new StreamReader(Path, encode);
+                s = streamReader.ReadToEnd();
+                streamReader.Close();
+                streamReader.Dispose();
+            }
+
+            return s;
+        }
+        #endregion
+    }
+}

+ 66 - 0
Admin.Core.Common/Helpers/MD5Encrypt.cs

@@ -0,0 +1,66 @@
+using System.Text;
+using System.Security.Cryptography;
+
+namespace Admin.Core.Common.Helpers
+{
+    /// <summary>
+    /// MD5加密
+    /// </summary>
+    public class MD5Encrypt
+    {
+        /// <summary>
+        /// 16位MD5加密
+        /// </summary>
+        /// <param name="password"></param>
+        /// <returns></returns>
+        public static string Encrypt16(string password)
+        {
+            if (password.IsNull())
+                return null;
+
+            using (var md5 = MD5.Create())
+            {
+                return md5.ComputeHash(Encoding.UTF8.GetBytes(password)).ToHex();
+            }
+        }
+
+        /// <summary>
+        /// 32位MD5加密
+        /// </summary>
+        /// <param name="password"></param>
+        /// <returns></returns>
+        public static string Encrypt32(string password = "")
+        {
+            if (password.IsNull())
+                return null;
+
+            using (var md5 = MD5.Create())
+            {
+                string pwd = string.Empty;
+                byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(password));
+                foreach (var item in s)
+                {
+                    pwd = string.Concat(pwd, item.ToString("X"));
+                }
+                return pwd;
+            }
+        }
+
+        /// <summary>
+        /// 64位MD5加密
+        /// </summary>
+        /// <param name="password"></param>
+        /// <returns></returns>
+        public static string Encrypt64(string password)
+        {
+            if (password.IsNull())
+                return null;
+
+            using(var md5 = MD5.Create())
+            {
+                byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(password));
+                return s.ToBase64();
+            }
+        }
+    }
+}

+ 45 - 0
Admin.Core.Common/Helpers/StringHelper.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Text;
+
+namespace Admin.Core.Common.Helpers
+{
+    /// <summary>
+    /// 字符串帮助类
+    /// </summary>
+    public class StringHelper
+    {
+        private static readonly char[] _constant = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
+
+        /// <summary>
+        /// 生成随机字符串,默认32位
+        /// </summary>
+        /// <param name="length">随机数长度</param>
+        /// <returns></returns>
+        public static string GenerateRandom(int length = 32)
+        {
+            var newRandom = new StringBuilder();
+            var rd = new Random();
+            for (int i = 0; i < length; i++)
+            {
+                newRandom.Append(_constant[rd.Next(_constant.Length)]);
+            }
+            return newRandom.ToString();
+        }
+
+        /// <summary>
+        /// 生成随机字符串,只包含数字
+        /// </summary>
+        /// <param name="length"></param>
+        /// <returns></returns>
+        public static string GenerateRandomNumber(int length = 6)
+        {
+            var newRandom = new StringBuilder();
+            var rd = new Random();
+            for (int i = 0; i < length; i++)
+            {
+                newRandom.Append(_constant[rd.Next(10)]);
+            }
+            return newRandom.ToString();
+        }
+    }
+}

+ 40 - 0
Admin.Core.Common/Helpers/UnicodeHelper.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Admin.Core.Common.Helpers
+{
+    public static class UnicodeHelper
+    {
+        /// <summary>
+        /// 字符串转Unicode码
+        /// </summary>
+        /// <returns>The to unicode.</returns>
+        /// <param name="value">Value.</param>
+        public static string StringToUnicode(string value)
+        {
+            byte[] bytes = Encoding.Unicode.GetBytes(value);
+            StringBuilder stringBuilder = new StringBuilder();
+            for (int i = 0; i < bytes.Length; i += 2)
+            {
+                // 取两个字符,每个字符都是右对齐。
+                stringBuilder.AppendFormat("u{0}{1}", bytes[i + 1].ToString("x").PadLeft(2, '0'), bytes[i].ToString("x").PadLeft(2, '0'));
+            }
+            return stringBuilder.ToString();
+        }
+
+        /// <summary>
+        /// Unicode转字符串
+        /// </summary>
+        /// <returns>The to string.</returns>
+        /// <param name="unicode">Unicode.</param>
+        public static string UnicodeToString(string unicode)
+        {
+            unicode = unicode.Replace("%", "\\");
+
+            return new Regex(@"\\u([0-9A-F]{4})", RegexOptions.IgnoreCase | RegexOptions.Compiled).Replace(
+                 unicode, x => string.Empty + Convert.ToChar(Convert.ToUInt16(x.Result("$1"), 16)));
+        }
+    }
+}

+ 189 - 0
Admin.Core.Common/Helpers/UtilConvert.cs

@@ -0,0 +1,189 @@
+using System;
+using System.Text;
+
+namespace Admin.Core
+{
+    /// <summary>
+    /// 数据类型转换
+    /// </summary>
+    public static class UtilConvert
+    {
+        public static int ToInt(this object thisValue)
+        {
+            int reval = 0;
+            if (thisValue == null) return 0;
+            if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
+            {
+                return reval;
+            }
+            return reval;
+        }
+        
+        public static int ToInt(this object thisValue, int errorValue)
+        {
+            int reval = 0;
+            if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
+            {
+                return reval;
+            }
+            return errorValue;
+        }
+
+        public static long ToLong(this object s)
+        {
+            if (s == null || s == DBNull.Value)
+                return 0L;
+
+            long.TryParse(s.ToString(), out long result);
+            return result;
+        }
+        
+        public static double ToMoney(this object thisValue)
+        {
+            double reval = 0;
+            if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
+            {
+                return reval;
+            }
+            return 0;
+        }
+        
+        public static double ToMoney(this object thisValue, double errorValue)
+        {
+            double reval = 0;
+            if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
+            {
+                return reval;
+            }
+            return errorValue;
+        }
+        
+        public static string ToString(this object thisValue)
+        {
+            if (thisValue != null) return thisValue.ToString().Trim();
+            return "";
+        }
+        
+        public static string ToString(this object thisValue, string errorValue)
+        {
+            if (thisValue != null) return thisValue.ToString().Trim();
+            return errorValue;
+        }
+        
+        public static decimal ToDecimal(this object thisValue)
+        {
+            Decimal reval = 0;
+            if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
+            {
+                return reval;
+            }
+            return 0;
+        }
+        
+        public static decimal ToDecimal(this object thisValue, decimal errorValue)
+        {
+            Decimal reval = 0;
+            if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
+            {
+                return reval;
+            }
+            return errorValue;
+        }
+        
+        public static DateTime ToDate(this object thisValue)
+        {
+            DateTime reval = DateTime.MinValue;
+            if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
+            {
+                reval = Convert.ToDateTime(thisValue);
+            }
+            return reval;
+        }
+        
+        public static DateTime ToDate(this object thisValue, DateTime errorValue)
+        {
+            DateTime reval = DateTime.MinValue;
+            if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
+            {
+                return reval;
+            }
+            return errorValue;
+        }
+        
+        public static bool ToBool(this object thisValue)
+        {
+            bool reval = false;
+            if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out reval))
+            {
+                return reval;
+            }
+            return reval;
+        }
+
+        public static byte ToByte(this object s)
+        {
+            if (s == null || s == DBNull.Value)
+                return 0;
+
+            byte.TryParse(s.ToString(), out byte result);
+            return result;
+        }
+
+        #region ==字节转换==
+        /// <summary>
+        /// 转换为16进制
+        /// </summary>
+        /// <param name="bytes"></param>
+        /// <param name="lowerCase">是否小写</param>
+        /// <returns></returns>
+        public static string ToHex(this byte[] bytes, bool lowerCase = true)
+        {
+            if (bytes == null)
+                return null;
+
+            var result = new StringBuilder();
+            var format = lowerCase ? "x2" : "X2";
+            for (var i = 0; i < bytes.Length; i++)
+            {
+                result.Append(bytes[i].ToString(format));
+            }
+
+            return result.ToString();
+        }
+
+        /// <summary>
+        /// 16进制转字节数组
+        /// </summary>
+        /// <param name="s"></param>
+        /// <returns></returns>
+        public static byte[] HexToBytes(this string s)
+        {
+            if (s.IsNull())
+                return null;
+            var bytes = new byte[s.Length / 2];
+
+            for (int x = 0; x < s.Length / 2; x++)
+            {
+                int i = (Convert.ToInt32(s.Substring(x * 2, 2), 16));
+                bytes[x] = (byte)i;
+            }
+
+            return bytes;
+        }
+
+        /// <summary>
+        /// 转换为Base64
+        /// </summary>
+        /// <param name="bytes"></param>
+        /// <returns></returns>
+        public static string ToBase64(this byte[] bytes)
+        {
+            if (bytes == null)
+                return null;
+
+            return Convert.ToBase64String(bytes);
+        }
+
+        #endregion
+    }
+}

+ 81 - 0
Admin.Core.Common/Helpers/VerifyCodeHelper.cs

@@ -0,0 +1,81 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Drawing;
+using System.Drawing.Imaging;
+
+namespace Admin.Core.Common.Helpers
+{
+    public class VerifyCodeHelper
+    {
+        private static string GenerateRandom(int length)
+        {
+            var chars = new StringBuilder();
+            //验证码的字符集,去掉了一些容易混淆的字符 
+            char[] character = { '2', '3', '4', '5', '6', '8', '9', 'a', 'b', 'd', 'e', 'f', 'h', 'k', 'm', 'n', 'r', 'x', 'y', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W', 'X', 'Y' };
+            Random rnd = new Random();
+            //生成验证码字符串 
+            for (int i = 0; i < length; i++)
+            {
+                chars.Append(character[rnd.Next(character.Length)]);
+            }
+            return chars.ToString();
+        }
+
+        public static byte[] Draw(out string code, int length = 4)
+        {
+            int codeW = 110;
+            int codeH = 36;
+            int fontSize = 22;
+           
+            //颜色列表,用于验证码、噪线、噪点 
+            Color[] color = { Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.Brown, Color.DarkBlue };
+            //字体列表,用于验证码 
+            string[] font = { "Times New Roman", "Verdana", "Arial", "Gungsuh", "Impact" };
+
+            code = GenerateRandom(length);
+
+            //创建画布
+            using (Bitmap bmp = new Bitmap(codeW, codeH))
+            using (Graphics g = Graphics.FromImage(bmp))
+            using (MemoryStream ms = new MemoryStream())
+            {
+                g.Clear(Color.White);
+                Random rnd = new Random();
+                //画噪线 
+                for (int i = 0; i < 1; i++)
+                {
+                    int x1 = rnd.Next(codeW);
+                    int y1 = rnd.Next(codeH);
+                    int x2 = rnd.Next(codeW);
+                    int y2 = rnd.Next(codeH);
+                    Color clr = color[rnd.Next(color.Length)];
+                    g.DrawLine(new Pen(clr), x1, y1, x2, y2);
+                }
+
+                //画验证码字符串 
+                {
+                    string fnt;
+                    Font ft;
+                    Color clr;
+                    for (int i = 0; i < code.Length; i++)
+                    {
+                        fnt = font[rnd.Next(font.Length)];
+                        ft = new Font(fnt, fontSize);
+                        clr = color[rnd.Next(color.Length)];
+                        g.DrawString(code[i].ToString(), ft, new SolidBrush(clr), (float)i * 24 + 2, (float)0);
+                    }
+                }
+
+                //将验证码图片写入内存流,并将其以 "image/Png" 格式输出
+                bmp.Save(ms, ImageFormat.Png);
+                return ms.ToArray();
+            }
+        }
+
+        public static string GetBase64String(out string code, int length = 4)
+        {
+            return Convert.ToBase64String(Draw(out code, length));
+        }
+    }
+}

+ 16 - 0
Admin.Core.Model/Admin.Core.Model.csproj

@@ -0,0 +1,16 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+    <DocumentationFile>..\Admin.Core\Admin.Core.Model.xml</DocumentationFile>
+    <NoWarn>1701;1702;1591</NoWarn>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Admin.Core.Common\Admin.Core.Common.csproj" />
+  </ItemGroup>
+
+</Project>

+ 60 - 0
Admin.Core.Model/Admin/ApiEntity.cs

@@ -0,0 +1,60 @@
+using System;
+using FreeSql.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
+
+namespace Admin.Core.Model.Admin
+{
+    /// <summary>
+    /// 接口管理
+    /// </summary>
+	[Table(Name = "ad_api")]
+    [Index("uk_api_path", "Path", true)]
+    public class ApiEntity : EntityBase
+    {
+        /// <summary>
+        /// 所属模块
+        /// </summary>
+		public long? ParentId { get; set; }
+
+        /// <summary>
+        /// 接口命名
+        /// </summary>
+        [MaxLength(50)]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 接口名称
+        /// </summary>
+        [MaxLength(500)]
+        public string Label { get; set; }
+
+        /// <summary>
+        /// 接口地址
+        /// </summary>
+        [MaxLength(500)]
+        public string Path { get; set; }
+
+        /// <summary>
+        /// 接口提交方法
+        /// </summary>
+        [MaxLength(50)]
+        public string HttpMethods { get; set; }
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        [MaxLength(500)]
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+        public int Sort { get; set; }
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+        public bool Enabled { get; set; } = true;
+
+    }
+}

+ 52 - 0
Admin.Core.Model/Admin/DictionaryEntity.cs

@@ -0,0 +1,52 @@
+using FreeSql.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
+
+namespace Admin.Core.Model.Admin 
+{
+    /// <summary>
+    /// 数据字典
+    /// </summary>
+	[Table(Name = "ad_dictionary")]
+    [Index("uk_role_parentid_name", "ParentId,Name", true)]
+    public class DictionaryEntity: EntityBase
+    {
+        /// <summary>
+        /// 字典父级
+        /// </summary>
+		public long ParentId { get; set; }
+
+        /// <summary>
+        /// 字典名称
+        /// </summary>
+        [MaxLength(50)]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 字典编码
+        /// </summary>
+        [MaxLength(50)]
+        public string Code { get; set; }
+
+        /// <summary>
+        /// 字典值
+        /// </summary>
+        [MaxLength(50)]
+        public string Value { get; set; }
+
+        /// <summary>
+        /// 描述
+        /// </summary>
+        [MaxLength(4000)]
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+		public bool Enabled { get; set; } = true;
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+		public int Sort { get; set; }
+    }
+}

+ 96 - 0
Admin.Core.Model/Admin/PermissionEntity.cs

@@ -0,0 +1,96 @@
+using System.ComponentModel.DataAnnotations;
+using Admin.Core.Model.Admin;
+using FreeSql.DataAnnotations;
+
+namespace Admin.Core.Model.Admin
+{
+    /// <summary>
+    /// 权限
+    /// </summary>
+	[Table(Name = "ad_permission")]
+    [Index("uk_permission_parentid_label", "ParentId,Label", true)]
+    public class PermissionEntity : EntityBase
+    {
+        /// <summary>
+        /// 父级节点
+        /// </summary>
+        public long ParentId { get; set; }
+
+        /// <summary>
+        /// 权限名称
+        /// </summary>
+        [MaxLength(50)]
+        public string Label { get; set; }
+
+        /// <summary>
+        /// 权限类型
+        /// </summary>
+        [Column(MapType = typeof(int),CanUpdate = false)]
+        public PermissionType Type { get; set; }
+
+        /// <summary>
+        /// 视图
+        /// </summary>
+        public long? ViewId { get; set; }
+        public ViewEntity View { get; set; }
+
+        /// <summary>
+        /// 接口
+        /// </summary>
+        public long? ApiId { get; set; }
+        public ApiEntity Api { get; set; }
+
+        /// <summary>
+        /// 菜单访问地址
+        /// </summary>
+        [MaxLength(500)]
+        public string Path { get; set; }
+
+        /// <summary>
+        /// 图标
+        /// </summary>
+        [MaxLength(100)]
+        public string Icon { get; set; }
+
+        /// <summary>
+        /// 隐藏
+        /// </summary>
+		public bool Hidden { get; set; } = false;
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+		public bool Enabled { get; set; } = true;
+
+        /// <summary>
+        /// 可关闭
+        /// </summary>
+        public bool? Closable { get; set; }
+
+        /// <summary>
+        /// 打开组
+        /// </summary>
+        public bool? Opened { get; set; }
+
+        /// <summary>
+        /// 打开新窗口
+        /// </summary>
+        public bool? NewWindow { get; set; }
+
+        /// <summary>
+        /// 链接外显
+        /// </summary>
+        public bool? External { get; set; }
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+        public int? Sort { get; set; } = 0;
+
+        /// <summary>
+        /// 描述
+        /// </summary>
+        [MaxLength(100)]
+        public string Description { get; set; }
+    }
+}

+ 22 - 0
Admin.Core.Model/Admin/PermissionType.cs

@@ -0,0 +1,22 @@
+
+namespace Admin.Core.Model.Admin
+{
+    /// <summary>
+    /// 权限类型
+    /// </summary>
+    public enum PermissionType
+    {
+        /// <summary>
+        /// 分组
+        /// </summary>
+        Group = 1,
+        /// <summary>
+        /// 菜单
+        /// </summary>
+        Menu = 2,
+        /// <summary>
+        /// 接口
+        /// </summary>
+        Api = 3
+    }
+}

+ 41 - 0
Admin.Core.Model/Admin/RoleEntity.cs

@@ -0,0 +1,41 @@
+using System;
+using FreeSql.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
+using System.Collections.Generic;
+
+namespace Admin.Core.Model.Admin
+{
+    /// <summary>
+    /// 角色
+    /// </summary>
+	[Table(Name = "ad_role")]
+    [Index("uk_role_name", "Name", true)]
+    public class RoleEntity: EntityBase
+    {
+        /// <summary>
+        /// 名称
+        /// </summary>
+        [MaxLength(50)]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        [Column(DbType = "varchar(100)")]
+		public string Description { get; set; }
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+		public bool Enabled { get; set; } = true;
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+		public int Sort { get; set; }
+
+        [Navigate(ManyToMany = typeof(UserRoleEntity))]
+        public virtual ICollection<UserEntity> Users { get; set; }
+    }
+
+}

+ 49 - 0
Admin.Core.Model/Admin/RolePermissionEntity.cs

@@ -0,0 +1,49 @@
+using FreeSql.DataAnnotations;
+
+namespace Admin.Core.Model.Admin
+{
+    /// <summary>
+    /// 角色权限
+    /// </summary>
+	[Table(Name = "ad_role_permission")]
+    [Index("uk_role_permissioin_roleid_permissionid", "RoleId,PermissionId", true)]
+    public class RolePermissionEntity: EntityAdd
+    {
+        /// <summary>
+        /// 角色Id
+        /// </summary>
+		public long RoleId { get; set; }
+
+        /// <summary>
+        /// 权限Id
+        /// </summary>
+		public long PermissionId { get; set; }
+
+        #region 外键 => 导航属性,ManyToMany
+        /// <summary>
+        /// 角色
+        /// </summary>
+        [Navigate("RoleId")]
+        public RoleEntity Role { get; set; }
+
+        /// <summary>
+        /// 权限
+        /// </summary>
+        [Navigate("PermissionId")]
+        public PermissionEntity Permission { get; set; }
+
+        /// <summary>
+        /// 角色名称
+        /// </summary>
+        [Column(IsIgnore = true)]
+        public string RoleName { get; set; }
+
+        /// <summary>
+        /// 路由
+        /// </summary>
+        [Column(IsIgnore = true)]
+        public string ApiPath { get; set; }
+        #endregion
+    }
+
+}

+ 59 - 0
Admin.Core.Model/Admin/UserEntity.cs

@@ -0,0 +1,59 @@
+using System;
+using FreeSql.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
+using System.Collections.Generic;
+
+namespace Admin.Core.Model.Admin
+{
+    /// <summary>
+    /// 用户
+    /// </summary>
+	[Table(Name = "ad_user")]
+    [Index("uk_user_username", "UserName", true)]
+    public class UserEntity: EntityBase
+    {
+        /// <summary>
+        /// 账号
+        /// </summary>
+        [MaxLength(60)]
+        public string UserName { get; set; }
+
+        /// <summary>
+        /// 密码
+        /// </summary>
+        [MaxLength(60)]
+        public string Password { get; set; }
+
+        /// <summary>
+        /// 姓名
+        /// </summary>
+        [MaxLength(60)]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 昵称
+        /// </summary>
+        [MaxLength(60)]
+        public string NickName { get; set; }
+
+        /// <summary>
+        /// 头像
+        /// </summary>
+        [MaxLength(100)]
+        public string Avatar { get; set; }
+
+        /// <summary>
+        /// 状态
+        /// </summary>
+        public int Status { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        [MaxLength(4000)]
+        public string Remark { get; set; }
+
+        [Navigate(ManyToMany = typeof(UserRoleEntity))]
+        public ICollection<RoleEntity> Roles { get; set; }
+    }
+}

+ 34 - 0
Admin.Core.Model/Admin/UserRoleEntity.cs

@@ -0,0 +1,34 @@
+using FreeSql.DataAnnotations;
+
+namespace Admin.Core.Model.Admin
+{
+    /// <summary>
+    /// 用户角色
+    /// </summary>
+	[Table(Name = "ad_user_role")]
+    [Index("uk_role_userid_roleid", "UserId,RoleId", true)]
+    public class UserRoleEntity: EntityAdd
+    {
+        public UserRoleEntity() { }
+
+        public UserRoleEntity(long userId, long roleId)
+        {
+            UserId = userId;
+            RoleId = roleId;
+        }
+
+        /// <summary>
+        /// 用户Id
+        /// </summary>
+        public long UserId { get; set; }
+        
+        public UserEntity User { get; set; }
+        
+        /// <summary>
+        /// 角色Id
+        /// </summary>
+        public long RoleId { get; set; }
+
+		public RoleEntity Role { get; set; }
+    }
+}

+ 53 - 0
Admin.Core.Model/Admin/ViewEntity.cs

@@ -0,0 +1,53 @@
+using System;
+using FreeSql.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
+
+namespace Admin.Core.Model.Admin
+{
+    /// <summary>
+    /// 视图管理
+    /// </summary>
+	[Table(Name = "ad_view")]
+    [Index("uk_view_path", "Path", true)]
+    public class ViewEntity : EntityBase
+    {
+        /// <summary>
+        /// 所属节点
+        /// </summary>
+		public long? ParentId { get; set; }
+
+        /// <summary>
+        /// 视图命名
+        /// </summary>
+        [MaxLength(50)]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 视图名称
+        /// </summary>
+        [MaxLength(500)]
+        public string Label { get; set; }
+
+        /// <summary>
+        /// 视图路径
+        /// </summary>
+        [MaxLength(500)]
+        public string Path { get; set; }
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        [MaxLength(500)]
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+        public bool Enabled { get; set; } = true;
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+        public int Sort { get; set; }
+    }
+}

+ 22 - 0
Admin.Core.Model/Base/Entity.cs

@@ -0,0 +1,22 @@
+using FreeSql.DataAnnotations;
+
+namespace Admin.Core.Model
+{
+    public interface IEntity
+    {
+    }
+
+    public class Entity<TKey> : IEntity
+    {
+        /// <summary>
+        /// 主键Id
+        /// </summary>
+        [Column(Position = 1,IsIdentity = true)]
+        public virtual TKey Id { get; set; }
+    }
+
+    public class Entity : Entity<long>
+    {
+
+    }
+}

+ 35 - 0
Admin.Core.Model/Base/EntityAdd.cs

@@ -0,0 +1,35 @@
+using FreeSql.DataAnnotations;
+using System;
+using System.ComponentModel.DataAnnotations;
+
+namespace Admin.Core.Model
+{
+    /// <summary>
+    /// 实体创建审计
+    /// </summary>
+    public class EntityAdd<TKey> : Entity<TKey>, IEntityAdd
+    {
+        /// <summary>
+        /// 创建者Id
+        /// </summary>
+        [Column(Position = -3, CanUpdate = false)]
+        public long? CreatedUserId { get; set; }
+
+        /// <summary>
+        /// 创建者
+        /// </summary>
+        [Column(Position = -2, CanUpdate = false), MaxLength(50)]
+        public string CreatedUserName { get; set; }
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [Column(Position = -1, CanUpdate = false, ServerTime = DateTimeKind.Local)]
+        public DateTime? CreatedTime { get; set; }
+    }
+
+    public class EntityAdd : EntityAdd<long>
+    {
+
+    }
+}

+ 65 - 0
Admin.Core.Model/Base/EntityBase.cs

@@ -0,0 +1,65 @@
+using FreeSql.DataAnnotations;
+using System;
+using System.ComponentModel.DataAnnotations;
+
+namespace Admin.Core.Model
+{
+    /// <summary>
+    /// 实体审计
+    /// </summary>
+    public class EntityBase<TKey> : Entity<TKey>, IEntityVersion, IEntitySoftDelete,IEntityAdd,IEntityUpdate
+    {
+        /// <summary>
+        /// 版本
+        /// </summary>
+        [Column(Position = -9, IsVersion = true)]
+        public long Version { get; set; }
+
+        /// <summary>
+        /// 是否删除
+        /// </summary>
+        [Column(Position = -8)]
+        public bool IsDeleted { get; set; } = false;
+
+        /// <summary>
+        /// 创建者Id
+        /// </summary>
+        [Column(Position = -7, CanUpdate = false)]
+        public long? CreatedUserId { get; set; }
+
+        /// <summary>
+        /// 创建者
+        /// </summary>
+        [Column(Position = -6, CanUpdate = false),MaxLength(50)]
+        public string CreatedUserName { get; set; }
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [Column(Position = -5, CanUpdate = false, ServerTime = DateTimeKind.Local)]
+        public DateTime? CreatedTime { get; set; }
+
+        /// <summary>
+        /// 修改者Id
+        /// </summary>
+        [Column(Position = -4, CanInsert = false)]
+        public long? ModifiedUserId { get; set; }
+
+        /// <summary>
+        /// 修改者
+        /// </summary>
+        [Column(Position = -2, CanInsert = false),MaxLength(50)]
+        public string ModifiedUserName { get; set; }
+
+        /// <summary>
+        /// 修改时间
+        /// </summary>
+        [Column(Position = -1, CanInsert = false,ServerTime = DateTimeKind.Local)]
+        public DateTime? ModifiedTime { get; set; }
+    }
+
+    public class EntityBase : EntityBase<long>
+    {
+
+    }
+}

+ 20 - 0
Admin.Core.Model/Base/EntitySoftDelete.cs

@@ -0,0 +1,20 @@
+using FreeSql.DataAnnotations;
+
+namespace Admin.Core.Model
+{
+    /// <summary>
+    /// 实体软删除
+    /// </summary>
+    public class EntitySoftDelete<TKey> : Entity<TKey>,IEntitySoftDelete
+    {
+        /// <summary>
+        /// 是否删除
+        /// </summary>
+        [Column(Position = -1)]
+        public bool IsDeleted { get; set; } = false;
+    }
+
+    public class EntitySoftDelete : EntitySoftDelete<long>
+    {
+    }
+}

+ 35 - 0
Admin.Core.Model/Base/EntityUpdate.cs

@@ -0,0 +1,35 @@
+using FreeSql.DataAnnotations;
+using System;
+using System.ComponentModel.DataAnnotations;
+
+namespace Admin.Core.Model
+{
+    /// <summary>
+    /// 实体修改审计
+    /// </summary>
+    public class EntityUpdate<TKey> : Entity<TKey>, IEntityUpdate
+    {
+        /// <summary>
+        /// 修改者Id
+        /// </summary>
+        [Column(Position = -3, CanInsert = false)]
+        public long? ModifiedUserId { get; set; }
+
+        /// <summary>
+        /// 修改者
+        /// </summary>
+        [Column(Position = -2, CanInsert = false), MaxLength(50)]
+        public string ModifiedUserName { get; set; }
+
+        /// <summary>
+        /// 修改时间
+        /// </summary>
+        [Column(Position = -1, CanInsert = false,ServerTime = DateTimeKind.Local)]
+        public DateTime? ModifiedTime { get; set; }
+    }
+
+    public class EntityUpdate : EntityUpdate<long>
+    {
+
+    }
+}

+ 20 - 0
Admin.Core.Model/Base/EntityVersion.cs

@@ -0,0 +1,20 @@
+using FreeSql.DataAnnotations;
+
+namespace Admin.Core.Model
+{
+    /// <summary>
+    /// 实体版本
+    /// </summary>
+    public class EntityVersion<TKey> : Entity<TKey>, IEntityVersion
+    {
+        /// <summary>
+        /// 版本
+        /// </summary>
+        [Column(Position = -1, IsVersion = true)]
+        public long Version { get; set; }
+    }
+
+    public class EntityVersion : EntityVersion<long>
+    {
+    }
+}

+ 11 - 0
Admin.Core.Model/Base/IEntityAdd.cs

@@ -0,0 +1,11 @@
+using System;
+
+namespace Admin.Core.Model
+{
+    public interface IEntityAdd
+    {
+        long? CreatedUserId { get; set; }
+        string CreatedUserName { get; set; }
+        DateTime? CreatedTime { get; set; }
+    }
+}

+ 11 - 0
Admin.Core.Model/Base/IEntitySoftDelete.cs

@@ -0,0 +1,11 @@
+
+namespace Admin.Core.Model
+{
+    public interface IEntitySoftDelete
+    {
+        /// <summary>
+        /// 是否删除
+        /// </summary>
+        bool IsDeleted { get; set; }
+    }
+}

+ 11 - 0
Admin.Core.Model/Base/IEntityUpdate.cs

@@ -0,0 +1,11 @@
+using System;
+
+namespace Admin.Core.Model
+{
+    public interface IEntityUpdate
+    {
+        long? ModifiedUserId { get; set; }
+        string ModifiedUserName { get; set; }
+        DateTime? ModifiedTime { get; set; }
+    }
+}

+ 13 - 0
Admin.Core.Model/Base/IEntityVersion.cs

@@ -0,0 +1,13 @@
+using FreeSql.DataAnnotations;
+using Newtonsoft.Json;
+
+namespace Admin.Core.Model
+{
+    public interface IEntityVersion
+    {
+        /// <summary>
+        /// 版本
+        /// </summary>
+        long Version { get; set; }
+    }
+}

+ 23 - 0
Admin.Core.Model/Input/PageInput.cs

@@ -0,0 +1,23 @@
+namespace Admin.Core.Model.Input
+{
+    /// <summary>
+    /// 通用分页信息输入类
+    /// </summary>
+    public class PageInput<T>
+    {
+        /// <summary>
+        /// 当前页标
+        /// </summary>
+        public int CurrentPage { get; set; } = 1;
+
+        /// <summary>
+        /// 每页大小
+        /// </summary>
+        public int PageSize { set; get; } = 50;
+
+        /// <summary>
+        /// 查询条件
+        /// </summary>
+        public T Filter { get; set; }
+    }
+}

+ 28 - 0
Admin.Core.Model/Output/IResponseOutput.cs

@@ -0,0 +1,28 @@
+using System.Text.Json.Serialization;
+
+namespace Admin.Core.Model.Output
+{
+    /// <summary>
+    /// 输出数据接口
+    /// </summary>
+    public interface IResponseOutput
+    {
+        /// <summary>
+        /// 是否成功
+        /// </summary>
+        [JsonIgnore]
+        bool Success { get; }
+    }
+
+    /// <summary>
+    /// 响应数据泛型接口
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public interface IResponseOutput<T> : IResponseOutput
+    {
+        /// <summary>
+        /// 返回数据
+        /// </summary>
+        T Data { get; }
+    }
+}

+ 20 - 0
Admin.Core.Model/Output/PageOutput.cs

@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+
+namespace Admin.Core.Model.Output
+{
+    /// <summary>
+    /// 通用分页信息输出类
+    /// </summary>
+    public class PageOutput<T>
+    {
+        /// <summary>
+        /// 数据总数
+        /// </summary>
+        public long Total { get; set; } = 0;
+
+        /// <summary>
+        /// 数据
+        /// </summary>
+        public IList<T> List { get; set; }
+    }
+}

+ 127 - 0
Admin.Core.Model/Output/ResponseOutput.cs

@@ -0,0 +1,127 @@
+using Newtonsoft.Json;
+
+namespace Admin.Core.Model.Output
+{
+    /// <summary>
+    /// 输出数据
+    /// </summary>
+    public class ResponseOutput<T> : IResponseOutput<T>
+    {
+        /// <summary>
+        /// 是否成功标记
+        /// </summary>
+        [JsonIgnore]
+        public bool Success { get; private set; }
+
+        /// <summary>
+        /// 状态码
+        /// </summary>
+        public int Code => Success ? 1 : 0;
+
+        /// <summary>
+        /// 消息
+        /// </summary>
+        public string Msg { get; private set; }
+
+        /// <summary>
+        /// 数据
+        /// </summary>
+        public T Data { get; private set; }
+
+        /// <summary>
+        /// 成功
+        /// </summary>
+        /// <param name="data">数据</param>
+        /// <param name="msg">消息</param>
+        public ResponseOutput<T> Ok(T data, string msg = null)
+        {
+            Success = true;
+            Data = data;
+            Msg = msg;
+
+            return this;
+        }
+
+        /// <summary>
+        /// 失败
+        /// </summary>
+        /// <param name="msg">消息</param>
+        /// <param name="data">数据</param>
+        /// <returns></returns>
+        public ResponseOutput<T> NotOk(string msg = null, T data = default(T))
+        {
+            Success = false;
+            Msg = msg;
+            Data = data;
+
+            return this;
+        }
+    }
+
+    /// <summary>
+    /// 输出数据静态类
+    /// </summary>
+    public static partial class ResponseOutput
+    {
+        /// <summary>
+        /// 成功
+        /// </summary>
+        /// <param name="data">数据</param>
+        /// <param name="msg">消息</param>
+        /// <returns></returns>
+        public static IResponseOutput Ok<T>(T data = default(T), string msg = null)
+        {
+            return new ResponseOutput<T>().Ok(data, msg);
+        }
+
+        /// <summary>
+        /// 成功
+        /// </summary>
+        /// <returns></returns>
+        public static IResponseOutput Ok()
+        {
+            return Ok<string>();
+        }
+
+        /// <summary>
+        /// 失败
+        /// </summary>
+        /// <param name="msg">消息</param>
+        /// <param name="data">数据</param>
+        /// <returns></returns>
+        public static IResponseOutput NotOk<T>(string msg = null,T data = default(T))
+        {
+            return new ResponseOutput<T>().NotOk(msg, data);
+        }
+
+        /// <summary>
+        /// 失败
+        /// </summary>
+        /// <param name="msg">消息</param>
+        /// <returns></returns>
+        public static IResponseOutput NotOk(string msg = null)
+        {
+            return new ResponseOutput<string>().NotOk(msg);
+        }
+
+        /// <summary>
+        /// 根据布尔值返回结果
+        /// </summary>
+        /// <param name="success"></param>
+        /// <returns></returns>
+        public static IResponseOutput Result<T>(bool success)
+        {
+            return success ? Ok<T>() : NotOk<T>();
+        }
+
+        /// <summary>
+        /// 根据布尔值返回结果
+        /// </summary>
+        /// <param name="success"></param>
+        /// <returns></returns>
+        public static IResponseOutput Result(bool success)
+        {
+            return success ? Ok() : NotOk();
+        }
+    }
+}

+ 20 - 0
Admin.Core.Repository/Admin.Core.Repository.csproj

@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+    <OutputPath></OutputPath>
+    <PlatformTarget>AnyCPU</PlatformTarget>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Compile Remove="Base\BaseRepository.cs" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Admin.Core.Model\Admin.Core.Model.csproj" />
+  </ItemGroup>
+
+</Project>

+ 13 - 0
Admin.Core.Repository/Admin/Api/ApiRepository.cs

@@ -0,0 +1,13 @@
+using FreeSql;
+using Admin.Core.Model.Admin;
+using Admin.Core.Common.Auth;
+
+namespace Admin.Core.Repository.Admin
+{
+    public class ApiRepository : RepositoryBase<ApiEntity>, IApiRepository
+    {
+        public ApiRepository(IFreeSql orm, IUnitOfWork uow, IUser user) : base(orm, uow, user)
+        {
+        }
+    }
+}

+ 11 - 0
Admin.Core.Repository/Admin/Api/IApiRepository.cs

@@ -0,0 +1,11 @@
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Repository.Admin
+{
+	public interface IApiRepository : IRepositoryBase<ApiEntity>
+    {
+    }
+}
+
+
+	

+ 13 - 0
Admin.Core.Repository/Admin/Dictionary/DictionaryRepository.cs

@@ -0,0 +1,13 @@
+using FreeSql;
+using Admin.Core.Model.Admin;
+using Admin.Core.Common.Auth;
+
+namespace Admin.Core.Repository.Admin
+{
+    public class DictionaryRepository : RepositoryBase<DictionaryEntity>, IDictionaryRepository
+    {
+        public DictionaryRepository(IFreeSql orm, IUnitOfWork uow, IUser user) : base(orm, uow, user)
+        {
+        }
+    }
+}

+ 9 - 0
Admin.Core.Repository/Admin/Dictionary/IDictionaryRepository.cs

@@ -0,0 +1,9 @@
+
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Repository.Admin
+{
+    public partial interface IDictionaryRepository : IRepositoryBase<DictionaryEntity>
+    {
+    }
+}

+ 9 - 0
Admin.Core.Repository/Admin/Permission/IPermissionRepository.cs

@@ -0,0 +1,9 @@
+
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Repository.Admin
+{
+    public partial interface IPermissionRepository : IRepositoryBase<PermissionEntity>
+    {
+    }
+}

+ 13 - 0
Admin.Core.Repository/Admin/Permission/PermissionRepository.cs

@@ -0,0 +1,13 @@
+using FreeSql;
+using Admin.Core.Model.Admin;
+using Admin.Core.Common.Auth;
+
+namespace Admin.Core.Repository.Admin
+{
+    public class PermissionRepository : RepositoryBase<PermissionEntity>, IPermissionRepository
+    {
+        public PermissionRepository(IFreeSql orm, IUnitOfWork uow, IUser user) : base(orm, uow, user)
+        {
+        }
+    }
+}

+ 8 - 0
Admin.Core.Repository/Admin/Role/IRoleRepository.cs

@@ -0,0 +1,8 @@
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Repository.Admin
+{	
+	public interface IRoleRepository : IRepositoryBase<RoleEntity>
+    {
+    }
+}

+ 13 - 0
Admin.Core.Repository/Admin/Role/RoleRepository.cs

@@ -0,0 +1,13 @@
+using FreeSql;
+using Admin.Core.Model.Admin;
+using Admin.Core.Common.Auth;
+
+namespace Admin.Core.Repository.Admin
+{	
+	public  class RoleRepository : RepositoryBase<RoleEntity>, IRoleRepository
+    {
+        public RoleRepository(IFreeSql orm, IUnitOfWork uow, IUser user) : base(orm, uow, user)
+        {
+        }
+    }
+}

+ 8 - 0
Admin.Core.Repository/Admin/RolePermission/IRolePermissionRepository.cs

@@ -0,0 +1,8 @@
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Repository.Admin
+{
+	public interface IRolePermissionRepository : IRepositoryBase<RolePermissionEntity>
+    {
+    }
+}

+ 15 - 0
Admin.Core.Repository/Admin/RolePermission/RolePermissionRepository.cs

@@ -0,0 +1,15 @@
+using FreeSql;
+using Admin.Core.Model.Admin;
+using Admin.Core.Common.Auth;
+
+namespace Admin.Core.Repository.Admin
+{
+    public class RolePermissionRepository : RepositoryBase<RolePermissionEntity>, IRolePermissionRepository
+    {
+        public RolePermissionRepository(IFreeSql orm, IUnitOfWork uow, IUser user) : base(orm, uow, user)
+        {
+        }
+    }
+
+}
+

+ 8 - 0
Admin.Core.Repository/Admin/User/IUserRepository.cs

@@ -0,0 +1,8 @@
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Repository.Admin
+{
+    public interface IUserRepository : IRepositoryBase<UserEntity>
+    {
+    }
+}

+ 13 - 0
Admin.Core.Repository/Admin/User/UserRepository.cs

@@ -0,0 +1,13 @@
+using FreeSql;
+using Admin.Core.Model.Admin;
+using Admin.Core.Common.Auth;
+
+namespace Admin.Core.Repository.Admin
+{
+    public class UserRepository : RepositoryBase<UserEntity>, IUserRepository
+    {
+        public UserRepository(IFreeSql orm, IUnitOfWork uow, IUser user) : base(orm, uow, user)
+        {
+        }
+    }
+}

+ 10 - 0
Admin.Core.Repository/Admin/UserRole/IUserRoleRepository.cs

@@ -0,0 +1,10 @@
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Repository.Admin
+{	
+	public interface IUserRoleRepository : IRepositoryBase<UserRoleEntity>
+    {
+    }
+}
+
+	

+ 13 - 0
Admin.Core.Repository/Admin/UserRole/UserRoleRepository.cs

@@ -0,0 +1,13 @@
+using FreeSql;
+using Admin.Core.Model.Admin;
+using Admin.Core.Common.Auth;
+
+namespace Admin.Core.Repository.Admin
+{	
+	public class UserRoleRepository : RepositoryBase<UserRoleEntity>, IUserRoleRepository
+    {
+        public UserRoleRepository(IFreeSql orm, IUnitOfWork uow, IUser user) : base(orm, uow, user)
+        {
+        }
+    }
+}

+ 11 - 0
Admin.Core.Repository/Admin/View/IViewRepositoryRepository.cs

@@ -0,0 +1,11 @@
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Repository.Admin
+{
+	public interface IViewRepository : IRepositoryBase<ViewEntity>
+    {
+	}
+}
+
+
+	

+ 14 - 0
Admin.Core.Repository/Admin/View/ViewRepositoryRepository.cs

@@ -0,0 +1,14 @@
+using FreeSql;
+using Admin.Core.Model.Admin;
+using Admin.Core.Common.Auth;
+
+namespace Admin.Core.Repository.Admin
+{
+    public class ViewRepository : RepositoryBase<ViewEntity>, IViewRepository
+    {
+        public ViewRepository(IFreeSql orm, IUnitOfWork uow, IUser user) : base(orm, uow, user)
+        {
+
+        }
+    }
+}

+ 30 - 0
Admin.Core.Repository/Base/IRepositoryBase.cs

@@ -0,0 +1,30 @@
+
+using FreeSql;
+using System.Threading.Tasks;
+
+namespace Admin.Core.Repository
+{
+    public interface IRepositoryBase<TEntity, TKey> : IBaseRepository<TEntity, TKey> where TEntity : class
+    {
+        Task<TDto> GetAsync<TDto>(TKey id);
+
+        /// <summary>
+        /// 软删除
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        Task<bool> SoftDeleteAsync(TKey id);
+
+        /// <summary>
+        /// 批量删除
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        Task<bool> SoftDeleteAsync(TKey[] id);
+    }
+
+    public interface IRepositoryBase<TEntity> : IRepositoryBase<TEntity,long> where TEntity : class
+    {
+    }
+
+}

+ 48 - 0
Admin.Core.Repository/Base/RepositoryBase.cs

@@ -0,0 +1,48 @@
+
+using FreeSql;
+using System.Threading.Tasks;
+using Admin.Core.Common.Auth;
+
+namespace Admin.Core.Repository
+{
+    public abstract class RepositoryBase<TEntity,TKey> : BaseRepository<TEntity, TKey> where TEntity : class,new()
+    {
+        private readonly IUser _user;
+        protected RepositoryBase(IFreeSql orm, IUnitOfWork uow, IUser user) : base(orm, null, null)
+        {
+            uow.Close();
+            UnitOfWork = uow;
+            _user = user;
+        }
+
+        public virtual Task<TDto> GetAsync<TDto>(TKey id)
+        {
+            return Select.WhereDynamic(id).ToOneAsync<TDto>();
+        }
+
+        public async Task<bool> SoftDeleteAsync(TKey id)
+        {
+            await UpdateDiy
+                .SetDto(new { IsDeleted = true, ModifiedUserId = _user.Id, ModifiedUserName = _user.Name })
+                .WhereDynamic(id)
+                .ExecuteAffrowsAsync();
+            return true;
+        }
+
+        public async Task<bool> SoftDeleteAsync(TKey[] ids)
+        {
+            await UpdateDiy
+                .SetDto(new { IsDeleted = true, ModifiedUserId = _user.Id, ModifiedUserName = _user.Name })
+                .WhereDynamic(ids)
+                .ExecuteAffrowsAsync();
+            return true;
+        }
+    }
+
+    public abstract class RepositoryBase<TEntity> : RepositoryBase<TEntity, long> where TEntity : class, new()
+    {
+        protected RepositoryBase(IFreeSql orm, IUnitOfWork uow, IUser user) : base(orm, uow, user)
+        {
+        }
+    }
+}

+ 33 - 0
Admin.Core.Services/Admin.Core.Service.csproj

@@ -0,0 +1,33 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+    <OutputPath>..\Admin.Core\bin\Debug\</OutputPath>
+    <DocumentationFile>..\Admin.Core\Admin.Core.Service.xml</DocumentationFile>
+    <NoWarn>1701;1702;1591</NoWarn>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Compile Remove="BASE\**" />
+    <EmbeddedResource Remove="BASE\**" />
+    <None Remove="BASE\**" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="AutoMapper" Version="9.0.0" />
+    <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="7.0.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Admin.Core.Model\Admin.Core.Model.csproj" />
+    <ProjectReference Include="..\Admin.Core.Repository\Admin.Core.Repository.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Folder Include="Admin\Auth\Output\" />
+  </ItemGroup>
+
+</Project>

+ 217 - 0
Admin.Core.Services/Admin/Api/ApiService.cs

@@ -0,0 +1,217 @@
+using System.Linq;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using AutoMapper;
+using Admin.Core.Common;
+using Admin.Core.Model.Input;
+using Admin.Core.Model.Output;
+using Admin.Core.Model.Admin;
+using Admin.Core.Repository.Admin;
+using Admin.Core.Service.Admin.Api.Input;
+using Admin.Core.Service.Admin.Api.Output;
+
+namespace Admin.Core.Service.Admin.Api
+{
+    public class ApiService : IApiService
+    {
+        private readonly IMapper _mapper;
+        private readonly IApiRepository _apiRepository;
+        public ApiService(IMapper mapper, IApiRepository moduleRepository)
+        {
+            _mapper = mapper;
+            _apiRepository = moduleRepository;
+        }
+
+        public async Task<IResponseOutput> GetAsync(long id)
+        {
+            var result = await _apiRepository.GetAsync<ApiGetOutput>(id);
+            return ResponseOutput.Ok(result);
+        }
+
+        public async Task<IResponseOutput> ListAsync(string key)
+        {
+            var data = await _apiRepository
+                .WhereIf(key.NotNull(), a => a.Path.Contains(key) || a.Label.Contains(key))
+                .ToListAsync<ApiListOutput>();
+
+            return ResponseOutput.Ok(data);
+        }
+
+        public async Task<IResponseOutput> PageAsync(PageInput<ApiEntity> input)
+        {
+            var key = input.Filter?.Label;
+
+            var list = await _apiRepository.Select
+            .WhereIf(key.NotNull(), a => a.Path.Contains(key) || a.Label.Contains(key))
+            .Count(out var total)
+            .OrderByDescending(true, c => c.Id)
+            .Page(input.CurrentPage, input.PageSize)
+            .ToListAsync();
+
+            var data = new PageOutput<ApiEntity>() 
+            { 
+                List = list,
+                Total = total
+            };
+
+            return ResponseOutput.Ok(data);
+        }
+
+        public async Task<IResponseOutput> AddAsync(ApiAddInput input)
+        {
+            var entity = _mapper.Map<ApiEntity>(input);
+            var id = (await _apiRepository.InsertAsync(entity)).Id;
+
+            return ResponseOutput.Result(id > 0);
+        }
+
+        public async Task<IResponseOutput> UpdateAsync(ApiUpdateInput input)
+        {
+            if (!(input?.Id > 0))
+            {
+                return ResponseOutput.NotOk();
+            }
+
+            var entity = await _apiRepository.GetAsync(input.Id);
+            if (!(entity?.Id > 0))
+            {
+                return ResponseOutput.NotOk("接口不存在!");
+            }
+
+            _mapper.Map(input, entity);
+            await _apiRepository.UpdateAsync(entity);
+            return ResponseOutput.Ok();
+        }
+
+        public async Task<IResponseOutput> DeleteAsync(long id)
+        {
+            var result = false;
+            if (id > 0)
+            {
+                result = (await _apiRepository.DeleteAsync(m => m.Id == id)) > 0;
+            }
+
+            return ResponseOutput.Result(result);
+        }
+
+        public async Task<IResponseOutput> SoftDeleteAsync(long id)
+        {
+            var result = await _apiRepository.SoftDeleteAsync(id);
+            return ResponseOutput.Result(result);
+        }
+
+        public async Task<IResponseOutput> BatchSoftDeleteAsync(long[] ids)
+        {
+            var result = await _apiRepository.SoftDeleteAsync(ids);
+
+            return ResponseOutput.Result(result);
+        }
+
+        [Transaction]
+        public async Task<IResponseOutput> SyncAsync(ApiSyncInput input)
+        {
+            //查询所有api
+            var apis = await _apiRepository.Select.ToListAsync();
+            var paths = apis.Select(a => a.Path).ToList();
+
+            //path处理
+            foreach (var api in input.Apis)
+            {
+                api.Path = api.Path?.Trim().ToLower();
+                api.ParentPath = api.ParentPath?.Trim().ToLower();
+            }
+
+            #region 执行插入
+            //执行父级api插入
+            var parentApis = input.Apis.FindAll(a => a.ParentPath.IsNull());
+            var pApis = (from a in parentApis where !paths.Contains(a.Path) select a).ToList();
+            if (pApis.Count > 0)
+            {
+                var insertPApis = _mapper.Map<List<ApiEntity>>(pApis);
+                insertPApis = await _apiRepository.InsertAsync(insertPApis);
+                apis.AddRange(insertPApis);
+            }
+
+            //执行子级api插入
+            var childApis = input.Apis.FindAll(a => a.ParentPath.NotNull());
+            var cApis = (from a in childApis where !paths.Contains(a.Path) select a).ToList();
+            if (cApis.Count > 0)
+            {
+                var insertCApis = _mapper.Map<List<ApiEntity>>(cApis);
+                insertCApis = await _apiRepository.InsertAsync(insertCApis);
+                apis.AddRange(insertCApis);
+            }
+            #endregion
+
+            #region 修改和禁用
+            {
+                //api修改
+                ApiEntity a;
+                List<string> labels;
+                string label;
+                string desc;
+                foreach (var api in parentApis)
+                {
+                    a = apis.Find(a => a.Path == api.Path);
+                    if (a?.Id > 0)
+                    {
+                        labels = api.Label?.Split("\r\n")?.ToList();
+                        label = labels != null && labels.Count > 0 ? labels[0] : string.Empty;
+                        desc = labels != null && labels.Count > 1 ? string.Join("\r\n", labels.GetRange(1, labels.Count() - 1)) : string.Empty;
+                        a.ParentId = 0;
+                        a.Label = label;
+                        a.Description = desc;
+                        a.Enabled = true;
+                    }
+                }
+            }
+
+            {
+                //api修改
+                ApiEntity a;
+                ApiEntity pa;
+                List<string> labels;
+                string label;
+                string desc;
+                foreach (var api in childApis)
+                {
+                    a = apis.Find(a => a.Path == api.Path);
+                    pa = apis.Find(a => a.Path == api.ParentPath);
+                    if (a?.Id > 0)
+                    {
+                        labels = api.Label?.Split("\r\n")?.ToList();
+                        label = labels != null && labels.Count > 0 ? labels[0] : string.Empty;
+                        desc = labels != null && labels.Count > 1 ? string.Join("\r\n", labels.GetRange(1, labels.Count() - 1)) : string.Empty;
+
+                        a.ParentId = pa?.Id;
+                        a.Label = label;
+                        a.Description = desc;
+                        a.HttpMethods = api.HttpMethods;
+                        a.Enabled = true;
+                    }
+                }
+            }
+
+            {
+                //api禁用
+                var inputPaths = input.Apis.Select(a => a.Path).ToList();
+                var disabledApis = (from a in apis where !inputPaths.Contains(a.Path) select a).ToList();
+                if (disabledApis.Count > 0)
+                {
+                    foreach (var api in disabledApis)
+                    {
+                        api.Enabled = false;
+                    }
+                }
+            }
+            #endregion
+
+            //批量更新
+            await _apiRepository.UpdateDiy.SetSource(apis)
+            .UpdateColumns(a => new { a.ParentId, a.Label, a.HttpMethods,a.Description,a.Enabled })
+            .ExecuteAffrowsAsync();
+
+            return ResponseOutput.Ok();
+        }
+    }
+}

+ 78 - 0
Admin.Core.Services/Admin/Api/IApiService.cs

@@ -0,0 +1,78 @@
+
+using Admin.Core.Model.Input;
+using Admin.Core.Service.Admin.Api.Input;
+using Admin.Core.Model.Output;
+using Admin.Core.Model.Admin;
+using System.Threading.Tasks;
+
+namespace Admin.Core.Service.Admin.Api
+{
+    /// <summary>
+    /// 接口服务
+    /// </summary>	
+    public interface IApiService
+    {
+        /// <summary>
+        /// 获得一条记录
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        Task<IResponseOutput> GetAsync(long id);
+
+        /// <summary>
+        /// 获得列表
+        /// </summary>
+        /// <param name="key"></param>
+        /// <returns></returns>
+        Task<IResponseOutput> ListAsync(string key);
+
+        /// <summary>
+        /// 获得分页
+        /// </summary>
+        /// <param name="model"></param>
+        /// <returns></returns>
+        Task<IResponseOutput> PageAsync(PageInput<ApiEntity> model);
+
+        /// <summary>
+        /// 添加
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        Task<IResponseOutput> AddAsync(ApiAddInput input);
+
+        /// <summary>
+        /// 修改
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        Task<IResponseOutput> UpdateAsync(ApiUpdateInput input);
+
+        /// <summary>
+        /// 删除
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        Task<IResponseOutput> DeleteAsync(long id);
+
+        /// <summary>
+        /// 软删除
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        Task<IResponseOutput> SoftDeleteAsync(long id);
+
+        /// <summary>
+        /// 批量软删除
+        /// </summary>
+        /// <param name="ids"></param>
+        /// <returns></returns>
+        Task<IResponseOutput> BatchSoftDeleteAsync(long[] ids);
+
+        /// <summary>
+        /// 同步
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        Task<IResponseOutput> SyncAsync(ApiSyncInput input);
+    }
+}

+ 38 - 0
Admin.Core.Services/Admin/Api/Input/ApiAddInput.cs

@@ -0,0 +1,38 @@
+namespace Admin.Core.Service.Admin.Api.Input
+{
+    /// <summary>
+    /// 添加
+    /// </summary>
+    public class ApiAddInput
+    {
+        /// <summary>
+        /// 所属模块
+        /// </summary>
+		public int? ParentId { get; set; }
+
+        /// <summary>
+        /// 接口名称
+        /// </summary>
+        public string Label { get; set; }
+
+        /// <summary>
+        /// 接口地址
+        /// </summary>
+        public string Path { get; set; }
+
+        /// <summary>
+        /// 接口提交方法
+        /// </summary>
+        public string HttpMethods { get; set; }
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+        public bool Enabled { get; set; }
+    }
+}

+ 28 - 0
Admin.Core.Services/Admin/Api/Input/ApiSyncDto.cs

@@ -0,0 +1,28 @@
+namespace Admin.Core.Service.Admin.Api.Input
+{
+    /// <summary>
+    /// 接口同步Dto
+    /// </summary>
+    public class ApiSyncDto
+    {
+        /// <summary>
+        /// 接口名称
+        /// </summary>
+        public string Label { get; set; }
+
+        /// <summary>
+        /// 接口地址
+        /// </summary>
+        public string Path { get; set; }
+        
+        /// <summary>
+        /// 父级路径
+        /// </summary>
+        public string ParentPath { get; set; }
+
+        /// <summary>
+        /// 接口提交方法
+        /// </summary>
+        public string HttpMethods { get; set; }
+    }
+}

+ 12 - 0
Admin.Core.Services/Admin/Api/Input/ApiSyncInput.cs

@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+
+namespace Admin.Core.Service.Admin.Api.Input
+{
+    /// <summary>
+    /// 接口同步
+    /// </summary>
+    public class ApiSyncInput
+    {
+        public List<ApiSyncDto> Apis { get; set; }
+    }
+}

+ 18 - 0
Admin.Core.Services/Admin/Api/Input/ApiUpdateInput.cs

@@ -0,0 +1,18 @@
+namespace Admin.Core.Service.Admin.Api.Input
+{
+    /// <summary>
+    /// 修改
+    /// </summary>
+    public partial class ApiUpdateInput :ApiAddInput
+    {
+        /// <summary>
+        /// 接口Id
+        /// </summary>
+        public int Id { get; set; }
+
+        /// <summary>
+        /// 版本
+        /// </summary>
+        public long Version { get; set; }
+    }
+}

+ 8 - 0
Admin.Core.Services/Admin/Api/Output/ApiGetOutput.cs

@@ -0,0 +1,8 @@
+using Admin.Core.Service.Admin.Api.Input;
+
+namespace Admin.Core.Service.Admin.Api.Output
+{
+    public class ApiGetOutput : ApiUpdateInput
+    {
+    }
+}

+ 45 - 0
Admin.Core.Services/Admin/Api/Output/ApiListOutput.cs

@@ -0,0 +1,45 @@
+namespace Admin.Core.Service.Admin.Api.Output
+{
+    public class ApiListOutput
+    {
+        /// <summary>
+        /// 接口Id
+        /// </summary>
+        public int Id { get; set; }
+
+        /// <summary>
+        /// 接口父级
+        /// </summary>
+		public long? ParentId { get; set; }
+
+        /// <summary>
+        /// 接口命名
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 接口名称
+        /// </summary>
+        public string Label { get; set; }
+
+        /// <summary>
+        /// 接口地址
+        /// </summary>
+        public string Path { get; set; }
+
+        /// <summary>
+        /// 接口提交方法
+        /// </summary>
+        public string HttpMethods { get; set; }
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+        public bool Enabled { get; set; }
+    }
+}

+ 19 - 0
Admin.Core.Services/Admin/Api/_MapConfig.cs

@@ -0,0 +1,19 @@
+using AutoMapper;
+using Admin.Core.Model.Admin;
+using Admin.Core.Service.Admin.Api.Input;
+
+namespace Admin.Core.Service.Admin.Api
+{
+    /// <summary>
+    /// 映射配置
+    /// </summary>
+    public class MapConfig : Profile
+    {
+        public MapConfig()
+        {
+            CreateMap<ApiAddInput, ApiEntity>();
+            CreateMap<ApiUpdateInput, ApiEntity>();
+            CreateMap<ApiSyncDto, ApiEntity>();
+        }
+    }
+}

+ 196 - 0
Admin.Core.Services/Admin/Auth/AuthService.cs

@@ -0,0 +1,196 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Security.Claims;
+using Admin.Core.Model.Admin;
+using Admin.Core.Model.Output;
+using Admin.Core.Repository.Admin;
+using Admin.Core.Common.Helpers;
+using Admin.Core.Common.Auth;
+using Admin.Core.Common.Cache;
+using Admin.Core.Service.Admin.Auth.Input;
+
+namespace Admin.Core.Service.Admin.Auth
+{
+    public class AuthService : IAuthService
+    {
+        private readonly IUser _user;
+        private readonly ICache _cache;
+        private readonly IUserToken _userToken;
+        private readonly IUserRepository _userRepository;
+        private readonly IRolePermissionRepository _rolePermissionRepository;
+
+        public AuthService(
+            IUser user,
+            ICache cache,
+            IUserToken userToken,
+            IUserRepository userRepository,
+            IRolePermissionRepository rolePermissionRepository
+        )
+        {
+            _user = user;
+            _cache = cache;
+            _userToken = userToken;
+            _userRepository = userRepository;
+            _rolePermissionRepository = rolePermissionRepository;
+        }
+
+        public async Task<IResponseOutput> LoginAsync(AuthLoginInput input)
+        {
+            if (input.UserName.IsNull())
+            {
+                return ResponseOutput.NotOk("用户名不能为空!");
+            }
+            if (input.Password.IsNull())
+            {
+                return ResponseOutput.NotOk("密码不能为空!");
+            }
+            if (input.VerifyCode.IsNull())
+            {
+                return ResponseOutput.NotOk("验证码不能为空!");
+            }
+
+            #region 验证码校验
+            var verifyCodeKey = string.Format(CacheKey.VerifyCodeKey, input.VerifyCodeKey);
+            var exists = await _cache.ExistsAsync(verifyCodeKey);
+            if (exists)
+            {
+                var verifyCode = await _cache.GetAsync(verifyCodeKey);
+                if (string.IsNullOrEmpty(verifyCode))
+                {
+                    return ResponseOutput.NotOk("验证码已过期!",1);
+                }
+                if (verifyCode.ToLower() != input.VerifyCode.ToLower())
+                {
+                    return ResponseOutput.NotOk("验证码输入有误!",2);
+                }
+                await _cache.DelAsync(verifyCodeKey);
+            }
+            else
+            {
+                return ResponseOutput.NotOk("验证码已过期!", 1);
+            }
+            #endregion
+
+            var user = (await _userRepository.Select.Where(a => a.UserName == input.UserName).ToOneAsync());
+            if (!(user?.Id > 0))
+            {
+                return ResponseOutput.NotOk("账号输入有误!", 3);
+            }
+
+            #region 解密
+            if (input.PasswordKey.NotNull())
+            {
+                var passwordKey = string.Format(CacheKey.PassWordKey, input.PasswordKey);
+                var existsPasswordKey = await _cache.ExistsAsync(passwordKey);
+                if (existsPasswordKey)
+                {
+                    var secretKey = await _cache.GetAsync(passwordKey);
+                    if (passwordKey.IsNull())
+                    {
+                        return ResponseOutput.NotOk("解密失败!",1);
+                    }
+                    input.Password = DesEncrypt.Decrypt(input.Password, secretKey);
+                    await _cache.DelAsync(passwordKey);
+                }
+                else
+                {
+                    return ResponseOutput.NotOk("解密失败!",1);
+                }
+            }
+            #endregion
+
+            var password = MD5Encrypt.Encrypt32(input.Password);
+            if (user.Password != password)
+            {
+                return ResponseOutput.NotOk("密码输入有误!",4);
+            }
+
+            //生成token信息
+            var claims = new[]
+            {
+                new Claim(ClaimAttributes.UserId, user.Id.ToString()),
+                new Claim(ClaimAttributes.UserName, user.Name.IsNull()?user.NickName:user.Name)
+            };
+            var token = _userToken.Build(claims);
+
+            return ResponseOutput.Ok(new 
+            { 
+                token
+            });
+        }
+
+        public async Task<IResponseOutput> GetUserInfoAsync()
+        {
+            if (!(_user?.Id > 0))
+            {
+                return ResponseOutput.NotOk("未登录!");
+            }
+
+            var user = await _userRepository.Select.WhereDynamic(_user.Id)
+                .ToOneAsync(m=>new { 
+                    m.NickName,
+                    m.Name,
+                    m.Avatar
+                });
+
+            //获取菜单
+            var menus = await _rolePermissionRepository.Select
+                .InnerJoin<UserRoleEntity>((a, b) => a.RoleId == b.RoleId && b.UserId == _user.Id)
+                .Include(a => a.Permission.View)
+                .Where(a => new[] { PermissionType.Group,PermissionType.Menu }.Contains(a.Permission.Type))
+                .OrderBy(a => a.Permission.ParentId)
+                .OrderBy(a => a.Permission.Sort)
+                .Distinct()
+                .ToListAsync(a => new
+                {
+                    a.Permission.Id,
+                    a.Permission.ParentId,
+                    a.Permission.Path,
+                    ViewPath = a.Permission.View.Path,
+                    a.Permission.Label,
+
+                    a.Permission.Icon,
+                    a.Permission.Opened,
+                    a.Permission.Closable,
+                    a.Permission.Hidden,
+                    a.Permission.NewWindow,
+                    a.Permission.External
+                });
+
+            return ResponseOutput.Ok(new { user, menus });
+        }
+
+        public async Task<IResponseOutput> GetVerifyCodeAsync(string lastKey)
+        {
+            var img = VerifyCodeHelper.GetBase64String(out string code);
+
+            //删除上次缓存的验证码
+            if (lastKey.NotNull())
+            {
+                await _cache.DelAsync(lastKey);
+            }
+
+            //写入Redis
+            var guid = Guid.NewGuid().ToString("N");
+            var key = string.Format(CacheKey.VerifyCodeKey, guid);
+            await _cache.SetAsync(key, code, TimeSpan.FromMinutes(5));
+
+            var data = new { key = guid, img };
+
+            return ResponseOutput.Ok(data);
+        }
+
+        public async Task<IResponseOutput> GetPassWordKeyAsync()
+        {
+            //写入Redis
+            var guid = Guid.NewGuid().ToString("N");
+            var key = string.Format(CacheKey.PassWordKey, guid);
+            var secretKey = StringHelper.GenerateRandom(8);
+            await _cache.SetAsync(key, secretKey, TimeSpan.FromMinutes(5));
+            var data = new { key = guid, secretKey };
+
+            return ResponseOutput.Ok(data);
+        }
+    }
+}

+ 21 - 0
Admin.Core.Services/Admin/Auth/IAuthService.cs

@@ -0,0 +1,21 @@
+
+using System.Threading.Tasks;
+using Admin.Core.Model.Output;
+using Admin.Core.Service.Admin.Auth.Input;
+
+namespace Admin.Core.Service.Admin.Auth
+{
+    /// <summary>
+    /// ȨÏÞ·þÎñ
+    /// </summary>	
+    public interface IAuthService
+	{
+        Task<IResponseOutput> LoginAsync(AuthLoginInput input);
+
+        Task<IResponseOutput> GetUserInfoAsync();
+
+        Task<IResponseOutput> GetVerifyCodeAsync(string lastKey);
+
+        Task<IResponseOutput> GetPassWordKeyAsync();
+    }
+}

+ 33 - 0
Admin.Core.Services/Admin/Auth/Input/AuthLoginInput.cs

@@ -0,0 +1,33 @@
+namespace Admin.Core.Service.Admin.Auth.Input
+{
+    /// <summary>
+    /// 登录信息
+    /// </summary>
+    public class AuthLoginInput
+    {
+        /// <summary>
+        /// 账号
+        /// </summary>
+        public string UserName { get; set; }
+
+        /// <summary>
+        /// 密码
+        /// </summary>
+        public string Password { get; set; }
+
+        /// <summary>
+        /// 密码键
+        /// </summary>
+        public string PasswordKey { get; set; }
+
+        /// <summary>
+        /// 验证码
+        /// </summary>
+        public string VerifyCode { get; set; }
+
+        /// <summary>
+        /// 验证码键
+        /// </summary>
+        public string VerifyCodeKey { get; set; }
+    }
+}

+ 17 - 0
Admin.Core.Services/Admin/Auth/_MapConfig.cs

@@ -0,0 +1,17 @@
+using AutoMapper;
+using Admin.Core.Model.Admin;
+using Admin.Core.Service.Admin.Permission.Input;
+
+namespace Admin.Core.Service.Admin.Auth
+{
+    /// <summary>
+    /// 映射配置
+    /// </summary>
+    public class MapConfig : Profile
+    {
+        public MapConfig()
+        {
+            
+        }
+    }
+}

+ 92 - 0
Admin.Core.Services/Admin/Dictionary/DictionaryService.cs

@@ -0,0 +1,92 @@
+using System.Threading.Tasks;
+using AutoMapper;
+using Admin.Core.Model.Output;
+using Admin.Core.Model.Input;
+using Admin.Core.Model.Admin;
+using Admin.Core.Repository.Admin;
+using Admin.Core.Service.Admin.Dictionary.Input;
+using Admin.Core.Service.Admin.Dictionary.Output;
+
+namespace Admin.Core.Service.Admin.Dictionary
+{
+    public class DictionaryService : IDictionaryService
+    {
+        private readonly IMapper _mapper;
+        private readonly IDictionaryRepository _dictionaryRepository;
+
+        public DictionaryService(IMapper mapper, IDictionaryRepository dictionaryRepository)
+        {
+            _mapper = mapper;
+            _dictionaryRepository = dictionaryRepository;
+        }
+
+        public async Task<IResponseOutput> GetAsync(long id)
+        {
+            var result = await _dictionaryRepository.GetAsync<DictionaryGetOutput>(id);
+            return ResponseOutput.Ok(result);
+        }
+
+        public async Task<IResponseOutput> PageAsync(PageInput<DictionaryEntity> input)
+        {
+            var key = input.Filter?.Name;
+
+            var list = await _dictionaryRepository.Select
+            .WhereIf(key.NotNull(), a => a.Name.Contains(key) || a.Code.Contains(key))
+            .Count(out var total)
+            .OrderByDescending(true, c => c.Id)
+            .Page(input.CurrentPage, input.PageSize)
+            .ToListAsync<DictionaryListOutput>();
+
+            var data = new PageOutput<DictionaryListOutput>()
+            {
+                List = list,
+                Total = total
+            };
+
+            return ResponseOutput.Ok(data);
+        }
+
+        public async Task<IResponseOutput> AddAsync(DictionaryAddInput input)
+        {
+            var dictionary = _mapper.Map<DictionaryEntity>(input);
+            var id = (await _dictionaryRepository.InsertAsync(dictionary)).Id;
+            return ResponseOutput.Result(id > 0);
+        }
+
+        public async Task<IResponseOutput> UpdateAsync(DictionaryUpdateInput input)
+        {
+            if (!(input?.Id > 0))
+            {
+                return ResponseOutput.NotOk();
+            }
+
+            var entity = await _dictionaryRepository.GetAsync(input.Id);
+            if (!(entity?.Id > 0))
+            {
+                return ResponseOutput.NotOk("Êý¾Ý×ֵ䲻´æÔÚ£¡");
+            }
+
+            _mapper.Map(input, entity);
+            await _dictionaryRepository.UpdateAsync(entity);
+            return ResponseOutput.Ok();
+        }
+
+        public async Task<IResponseOutput> DeleteAsync(long id)
+        {
+            var result = false;
+            if (id > 0)
+            {
+                result = (await _dictionaryRepository.DeleteAsync(m => m.Id == id)) > 0;
+            }
+
+            return ResponseOutput.Result(result);
+        }
+
+        public async Task<IResponseOutput> SoftDeleteAsync(long id)
+        {
+            var result = await _dictionaryRepository.SoftDeleteAsync(id);
+
+            return ResponseOutput.Result(result);
+        }
+    }
+}

+ 25 - 0
Admin.Core.Services/Admin/Dictionary/IDictionaryService.cs

@@ -0,0 +1,25 @@
+using Admin.Core.Model;
+using System.Threading.Tasks;
+using Admin.Core.Model.Input;
+using Admin.Core.Model.Output;
+using Admin.Core.Model.Admin;
+using Admin.Core.Service.Admin.Dictionary.Input;
+
+
+namespace Admin.Core.Service.Admin.Dictionary
+{
+    public partial interface IDictionaryService
+    {
+        Task<IResponseOutput> GetAsync(long id);
+
+        Task<IResponseOutput> PageAsync(PageInput<DictionaryEntity> model);
+
+        Task<IResponseOutput> AddAsync(DictionaryAddInput input);
+
+        Task<IResponseOutput> UpdateAsync(DictionaryUpdateInput input);
+
+        Task<IResponseOutput> DeleteAsync(long id);
+
+        Task<IResponseOutput> SoftDeleteAsync(long id);
+    }
+}

+ 38 - 0
Admin.Core.Services/Admin/Dictionary/Input/DictionaryAddInput.cs

@@ -0,0 +1,38 @@
+namespace Admin.Core.Service.Admin.Dictionary.Input
+{
+    /// <summary>
+    /// 添加
+    /// </summary>
+    public class DictionaryAddInput
+    {
+        /// <summary>
+        /// 字典父级
+        /// </summary>
+		public long ParentId { get; set; }
+
+        /// <summary>
+        /// 字典名称
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 字典编码
+        /// </summary>
+        public string Code { get; set; }
+
+        /// <summary>
+        /// 字典值
+        /// </summary>
+        public string Value { get; set; }
+
+        /// <summary>
+        /// 描述
+        /// </summary>
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+		public bool Enabled { get; set; }
+    }
+}

+ 18 - 0
Admin.Core.Services/Admin/Dictionary/Input/DictionaryUpdateInput.cs

@@ -0,0 +1,18 @@
+namespace Admin.Core.Service.Admin.Dictionary.Input
+{
+    /// <summary>
+    /// 修改
+    /// </summary>
+    public class DictionaryUpdateInput : DictionaryAddInput
+    {
+        /// <summary>
+        /// 主键Id
+        /// </summary>
+        public long Id { get; set; }
+
+        /// <summary>
+        /// 版本
+        /// </summary>
+        public long Version { get; set; }
+    }
+}

+ 8 - 0
Admin.Core.Services/Admin/Dictionary/Output/DictionaryGetOutput.cs

@@ -0,0 +1,8 @@
+using Admin.Core.Service.Admin.Dictionary.Input;
+
+namespace Admin.Core.Service.Admin.Dictionary.Output
+{
+    public class DictionaryGetOutput : DictionaryUpdateInput
+    {
+    }
+}

+ 47 - 0
Admin.Core.Services/Admin/Dictionary/Output/DictionaryListOutput.cs

@@ -0,0 +1,47 @@
+using System;
+
+namespace Admin.Core.Service.Admin.Dictionary.Output
+{
+    public class DictionaryListOutput
+    {
+        /// <summary>
+        /// 主键Id
+        /// </summary>
+        public int Id { get; set; }
+
+        /// <summary>
+        /// 字典父级
+        /// </summary>
+		public long ParentId { get; set; }
+
+        /// <summary>
+        /// 字典名称
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 字典编码
+        /// </summary>
+        public string Code { get; set; }
+
+        /// <summary>
+        /// 字典值
+        /// </summary>
+        public string Value { get; set; }
+
+        /// <summary>
+        /// 描述
+        /// </summary>
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 启用
+        /// </summary>
+		public bool Enabled { get; set; }
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        public DateTime? CreatedTime { get; set; }
+    }
+}

+ 18 - 0
Admin.Core.Services/Admin/Dictionary/_MapConfig.cs

@@ -0,0 +1,18 @@
+using AutoMapper;
+using Admin.Core.Model.Admin;
+using Admin.Core.Service.Admin.Dictionary.Input;
+
+namespace Admin.Core.Service.Admin.Dictionary
+{
+    /// <summary>
+    /// 映射配置
+    /// </summary>
+    public class MapConfig : Profile
+    {
+        public MapConfig()
+        {
+            CreateMap<DictionaryAddInput, DictionaryEntity>();
+            CreateMap<DictionaryUpdateInput, DictionaryEntity>();
+        }
+    }
+}

+ 43 - 0
Admin.Core.Services/Admin/Permission/IPermissionService.cs

@@ -0,0 +1,43 @@
+
+using System;
+using System.Threading.Tasks;
+using Admin.Core.Model.Output;
+using Admin.Core.Service.Admin.Permission.Input;
+
+namespace Admin.Core.Service.Admin.Permission
+{
+    public partial interface IPermissionService
+    {
+        Task<IResponseOutput> GetAsync(long id);
+
+        Task<IResponseOutput> GetGroupAsync(long id);
+
+        Task<IResponseOutput> GetMenuAsync(long id);
+
+        Task<IResponseOutput> GetApiAsync(long id);
+
+        Task<IResponseOutput> GetPermissionList();
+
+        Task<IResponseOutput> GetRolePermissionList(long roleId = 0);
+
+        Task<IResponseOutput> ListAsync(string key, DateTime? start, DateTime? end);
+
+        Task<IResponseOutput> AddGroupAsync(PermissionAddGroupInput input);
+
+        Task<IResponseOutput> AddMenuAsync(PermissionAddMenuInput input);
+
+        Task<IResponseOutput> AddApiAsync(PermissionAddApiInput input);
+
+        Task<IResponseOutput> UpdateGroupAsync(PermissionUpdateGroupInput input);
+
+        Task<IResponseOutput> UpdateMenuAsync(PermissionUpdateMenuInput input);
+
+        Task<IResponseOutput> UpdateApiAsync(PermissionUpdateApiInput input);
+
+        Task<IResponseOutput> DeleteAsync(long id);
+
+        Task<IResponseOutput> SoftDeleteAsync(long id);
+
+        Task<IResponseOutput> AssignAsync(PermissionAssignInput input);
+    }
+}

+ 47 - 0
Admin.Core.Services/Admin/Permission/Input/PermissionAddApiInput.cs

@@ -0,0 +1,47 @@
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Service.Admin.Permission.Input
+{
+    public class PermissionAddApiInput
+    {
+        /// <summary>
+        /// 权限类型
+        /// </summary>
+        public PermissionType Type { get; set; }
+
+        /// <summary>
+        /// 父级节点
+        /// </summary>
+        public int ParentId { get; set; }
+
+        /// <summary>
+        /// 接口
+        /// </summary>
+        public int? ApiId { get; set; }
+
+        /// <summary>
+        /// 权限名称
+        /// </summary>
+        public string Label { get; set; }
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 隐藏
+        /// </summary>
+		public bool Hidden { get; set; }
+
+        ///// <summary>
+        ///// 启用
+        ///// </summary>
+        //public bool Enabled { get; set; }
+
+        /// <summary>
+        /// 图标
+        /// </summary>
+        public string Icon { get; set; }
+    }
+}

+ 47 - 0
Admin.Core.Services/Admin/Permission/Input/PermissionAddGroupInput.cs

@@ -0,0 +1,47 @@
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Service.Admin.Permission.Input
+{
+    public class PermissionAddGroupInput
+    {
+        /// <summary>
+        /// 权限类型
+        /// </summary>
+        public PermissionType Type { get; set; }
+
+        /// <summary>
+        /// 父级节点
+        /// </summary>
+        public int ParentId { get; set; }
+
+        /// <summary>
+        /// 权限名称
+        /// </summary>
+        public string Label { get; set; }
+
+        ///// <summary>
+        ///// 说明
+        ///// </summary>
+        //public string Description { get; set; }
+
+        /// <summary>
+        /// 隐藏
+        /// </summary>
+		public bool Hidden { get; set; }
+
+        ///// <summary>
+        ///// 启用
+        ///// </summary>
+        //public bool Enabled { get; set; }
+
+        /// <summary>
+        /// 图标
+        /// </summary>
+        public string Icon { get; set; }
+
+        /// <summary>
+        /// 打开
+        /// </summary>
+        public bool? Opened { get; set; }
+    }
+}

+ 67 - 0
Admin.Core.Services/Admin/Permission/Input/PermissionAddMenuInput.cs

@@ -0,0 +1,67 @@
+using Admin.Core.Model.Admin;
+
+namespace Admin.Core.Service.Admin.Permission.Input
+{
+    public class PermissionAddMenuInput
+    {
+        /// <summary>
+        /// 权限类型
+        /// </summary>
+        public PermissionType Type { get; set; }
+
+        /// <summary>
+        /// 父级节点
+        /// </summary>
+        public int ParentId { get; set; }
+
+        /// <summary>
+        /// 视图
+        /// </summary>
+        public long? ViewId { get; set; }
+
+        /// <summary>
+        /// 访问地址
+        /// </summary>
+        public string Path { get; set; }
+
+        /// <summary>
+        /// 权限名称
+        /// </summary>
+        public string Label { get; set; }
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 隐藏
+        /// </summary>
+		public bool Hidden { get; set; }
+
+        ///// <summary>
+        ///// 启用
+        ///// </summary>
+        //public bool Enabled { get; set; }
+
+        /// <summary>
+        /// 图标
+        /// </summary>
+        public string Icon { get; set; }
+
+        /// <summary>
+        /// 可关闭
+        /// </summary>
+        public bool? Closable { get; set; }
+
+        /// <summary>
+        /// 打开新窗口
+        /// </summary>
+        public bool? NewWindow { get; set; }
+
+        /// <summary>
+        /// 链接外显
+        /// </summary>
+        public bool? External { get; set; }
+    }
+}

+ 10 - 0
Admin.Core.Services/Admin/Permission/Input/PermissionAssignInput.cs

@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+
+namespace Admin.Core.Service.Admin.Permission.Input
+{
+    public class PermissionAssignInput
+    {
+        public List<int> PermissionIds { get; set; }
+        public int RoleId { get; set; }
+    }
+}

+ 15 - 0
Admin.Core.Services/Admin/Permission/Input/PermissionUpdateApiInput.cs

@@ -0,0 +1,15 @@
+namespace Admin.Core.Service.Admin.Permission.Input
+{
+    public class PermissionUpdateApiInput : PermissionAddApiInput
+    {
+        /// <summary>
+        /// ȨÏÞId
+        /// </summary>
+        public long Id { get; set; }
+
+        /// <summary>
+        /// °æ±¾
+        /// </summary>
+        public long Version { get; set; }
+    }
+}

+ 16 - 0
Admin.Core.Services/Admin/Permission/Input/PermissionUpdateGroupInput.cs

@@ -0,0 +1,16 @@
+
+namespace Admin.Core.Service.Admin.Permission.Input
+{
+    public class PermissionUpdateGroupInput : PermissionAddGroupInput
+    {
+        /// <summary>
+        /// ȨÏÞId
+        /// </summary>
+        public long Id { get; set; }
+
+        /// <summary>
+        /// °æ±¾
+        /// </summary>
+        public long Version { get; set; }
+    }
+}

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä