├── .gitignore
├── Czar.Gateway.sln
├── Czar.Rpc.Client
├── Czar.Rpc.Client.csproj
├── CzarConfig.json
└── Program.cs
├── Czar.Rpc.Server
├── Czar.Rpc.Server.csproj
├── CzarConfig.json
├── HelloRpcServer.cs
└── Program.cs
├── LICENSE
├── README.md
├── doc
├── czar.gateway.20190109.sqlserver2008r2.bak
└── czar.gateway.sqlserver2008r2.bak
├── sample
├── Czar.Rpc.Common
│ ├── Czar.Rpc.Common.csproj
│ ├── DemoModel.cs
│ └── IHelloRpc.cs
├── Czar.Sample.SqlServer
│ ├── Czar.Sample.SqlServer.csproj
│ ├── CzarConfig.json
│ ├── Program.cs
│ ├── Startup.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── Czar.Sample.TestApi
│ ├── Controllers
│ │ └── ValuesController.cs
│ ├── Czar.Sample.TestApi.csproj
│ ├── Program.cs
│ ├── Startup.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
└── Czar.Sample.TestIds4
│ ├── Czar.Sample.TestIds4.csproj
│ ├── Program.cs
│ ├── Startup.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── tempkey.rsa
│ └── wwwroot
│ ├── css
│ ├── site.css
│ └── site.min.css
│ ├── favicon.ico
│ ├── images
│ ├── banner1.svg
│ ├── banner2.svg
│ └── banner3.svg
│ ├── js
│ ├── site.js
│ └── site.min.js
│ └── lib
│ ├── bootstrap
│ ├── .bower.json
│ ├── LICENSE
│ └── dist
│ │ ├── css
│ │ ├── bootstrap-theme.css
│ │ ├── bootstrap-theme.css.map
│ │ ├── bootstrap-theme.min.css
│ │ ├── bootstrap-theme.min.css.map
│ │ ├── bootstrap.css
│ │ ├── bootstrap.css.map
│ │ ├── bootstrap.min.css
│ │ └── bootstrap.min.css.map
│ │ ├── fonts
│ │ ├── glyphicons-halflings-regular.eot
│ │ ├── glyphicons-halflings-regular.svg
│ │ ├── glyphicons-halflings-regular.ttf
│ │ ├── glyphicons-halflings-regular.woff
│ │ └── glyphicons-halflings-regular.woff2
│ │ └── js
│ │ ├── bootstrap.js
│ │ ├── bootstrap.min.js
│ │ └── npm.js
│ ├── jquery-validation-unobtrusive
│ ├── .bower.json
│ ├── LICENSE.txt
│ ├── jquery.validate.unobtrusive.js
│ └── jquery.validate.unobtrusive.min.js
│ ├── jquery-validation
│ ├── .bower.json
│ ├── LICENSE.md
│ └── dist
│ │ ├── additional-methods.js
│ │ ├── additional-methods.min.js
│ │ ├── jquery.validate.js
│ │ └── jquery.validate.min.js
│ └── jquery
│ ├── .bower.json
│ ├── LICENSE.txt
│ └── dist
│ ├── jquery.js
│ ├── jquery.min.js
│ └── jquery.min.map
└── src
└── Czar.Gateway
├── Authentication
├── CzarAuthenticationProcessor.cs
├── IClientAuthenticationRepository.cs
├── ICzarAuthenticationProcessor.cs
└── Middleware
│ ├── CzarAuthenticationMiddleware.cs
│ └── CzarAuthenticationMiddlewareExtensions.cs
├── Cache
├── CzarCacheController.cs
├── CzarMemoryCache.cs
└── RedisInternalConfigurationRepository.cs
├── Configuration
├── CzarCacheRegion.cs
├── CzarOcelotConfiguration.cs
├── DbConfigurationPoller.cs
├── ErrorResult.cs
├── Model
│ ├── BaseResult.cs
│ └── ClientRoleModel.cs
└── RedisStoreMode.cs
├── Czar.Gateway.csproj
├── Errors
├── IdentityServer4Error.cs
├── InternalServerError.cs
└── RateLimitOptionsError.cs
├── Extensions
└── Ext.cs
├── Helper
└── CzarOcelotHelper.cs
├── Middleware
├── CzarOcelotMiddlewareExtensions.cs
├── OcelotPipelineExtensions.cs
└── ServiceCollectionExtensions.cs
├── Model
├── CzarAuthGroup.cs
├── CzarClientGroup.cs
├── CzarClientLimitGroup.cs
├── CzarClientReRouteWhiteList.cs
├── CzarClients.cs
├── CzarConfigReRoutes.cs
├── CzarGlobalConfiguration.cs
├── CzarLimitGroup.cs
├── CzarLimitGroupRule.cs
├── CzarLimitRule.cs
├── CzarReRoute.cs
├── CzarReRouteGroupAuth.cs
├── CzarReRouteLimitRule.cs
├── CzarReRouteRpcConfig.cs
└── CzarReRoutesItem.cs
├── RateLimit
├── CzarClientRateLimitCounter.cs
├── CzarClientRateLimitOptions.cs
├── CzarClientRateLimitProcessor.cs
├── IClientRateLimitProcessor.cs
├── IClientRateLimitRepository.cs
├── Middleware
│ ├── CzarClientRateLimitMiddleware.cs
│ └── CzarClientRateLimitMiddlewareExtensions.cs
└── RateLimitRuleModel.cs
├── Requester
└── Middleware
│ ├── CzarHttpRequesterMiddleware.cs
│ └── CzarHttpRequesterMiddlewareExtensions.cs
├── Responder
├── CzarErrorsToHttpStatusCodeMapper.cs
├── CzarHttpContextResponder.cs
└── Middleware
│ ├── CzarResponderMiddleware.cs
│ └── CzarResponderMiddlewareExtensions.cs
├── Rpc
├── CzarRpcProcessor.cs
├── ICzarRpcProcessor.cs
├── IRpcRepository.cs
├── Middleware
│ ├── CzarRpcMiddleware.cs
│ └── CzarRpcMiddlewareExtensions.cs
└── RpcHttpContent.cs
└── Stores
├── MySql
├── MySqlClientRateLimitRepository.cs
├── MySqlFileConfigurationRepository.cs
├── MySqlRpcRepository.cs
└── MysqlClientAuthenticationRepository.cs
└── SqlServer
├── SqlServerClientAuthenticationRepository.cs
├── SqlServerClientRateLimitRepository.cs
├── SqlServerFileConfigurationRepository.cs
└── SqlServerRpcRepository.cs
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
--------------------------------------------------------------------------------
/Czar.Gateway.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2026
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{BF264141-E863-40AE-A5A4-9EFE4FDC2C3E}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Czar.Gateway", "src\Czar.Gateway\Czar.Gateway.csproj", "{4C6BA65B-B5BA-42F5-B36B-31AF140DA62B}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{4B9D0EA8-0F29-4AC0-9531-76140EC49E38}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Czar.Sample.SqlServer", "sample\Czar.Sample.SqlServer\Czar.Sample.SqlServer.csproj", "{FC873F3E-4AE0-430B-B421-21EC1F330DB0}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Czar.Sample.TestIds4", "sample\Czar.Sample.TestIds4\Czar.Sample.TestIds4.csproj", "{4C0ED39A-DB9A-4604-9DA0-944AC3EB02A3}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Czar.Sample.TestApi", "sample\Czar.Sample.TestApi\Czar.Sample.TestApi.csproj", "{45DDBE95-E1BE-4AD3-B2BE-C95EF181F0B8}"
17 | EndProject
18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{824C8BC2-AA86-4876-94F7-D8DDA3842EF2}"
19 | EndProject
20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Czar.Rpc.Common", "sample\Czar.Rpc.Common\Czar.Rpc.Common.csproj", "{26A5CECA-B06D-4B9E-B202-08E7152AE966}"
21 | EndProject
22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Czar.Rpc.Server", "Czar.Rpc.Server\Czar.Rpc.Server.csproj", "{269A2DF7-83EC-451F-AD42-6C7C9D862438}"
23 | EndProject
24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Czar.Rpc.Client", "Czar.Rpc.Client\Czar.Rpc.Client.csproj", "{ACAFEF06-B0D1-45E3-8CCA-F4F214E5F591}"
25 | EndProject
26 | Global
27 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
28 | Debug|Any CPU = Debug|Any CPU
29 | Release|Any CPU = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
32 | {4C6BA65B-B5BA-42F5-B36B-31AF140DA62B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {4C6BA65B-B5BA-42F5-B36B-31AF140DA62B}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {4C6BA65B-B5BA-42F5-B36B-31AF140DA62B}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {4C6BA65B-B5BA-42F5-B36B-31AF140DA62B}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {FC873F3E-4AE0-430B-B421-21EC1F330DB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {FC873F3E-4AE0-430B-B421-21EC1F330DB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {FC873F3E-4AE0-430B-B421-21EC1F330DB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {FC873F3E-4AE0-430B-B421-21EC1F330DB0}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {4C0ED39A-DB9A-4604-9DA0-944AC3EB02A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {4C0ED39A-DB9A-4604-9DA0-944AC3EB02A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {4C0ED39A-DB9A-4604-9DA0-944AC3EB02A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {4C0ED39A-DB9A-4604-9DA0-944AC3EB02A3}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {45DDBE95-E1BE-4AD3-B2BE-C95EF181F0B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {45DDBE95-E1BE-4AD3-B2BE-C95EF181F0B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {45DDBE95-E1BE-4AD3-B2BE-C95EF181F0B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {45DDBE95-E1BE-4AD3-B2BE-C95EF181F0B8}.Release|Any CPU.Build.0 = Release|Any CPU
48 | {26A5CECA-B06D-4B9E-B202-08E7152AE966}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49 | {26A5CECA-B06D-4B9E-B202-08E7152AE966}.Debug|Any CPU.Build.0 = Debug|Any CPU
50 | {26A5CECA-B06D-4B9E-B202-08E7152AE966}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 | {26A5CECA-B06D-4B9E-B202-08E7152AE966}.Release|Any CPU.Build.0 = Release|Any CPU
52 | {269A2DF7-83EC-451F-AD42-6C7C9D862438}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
53 | {269A2DF7-83EC-451F-AD42-6C7C9D862438}.Debug|Any CPU.Build.0 = Debug|Any CPU
54 | {269A2DF7-83EC-451F-AD42-6C7C9D862438}.Release|Any CPU.ActiveCfg = Release|Any CPU
55 | {269A2DF7-83EC-451F-AD42-6C7C9D862438}.Release|Any CPU.Build.0 = Release|Any CPU
56 | {ACAFEF06-B0D1-45E3-8CCA-F4F214E5F591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
57 | {ACAFEF06-B0D1-45E3-8CCA-F4F214E5F591}.Debug|Any CPU.Build.0 = Debug|Any CPU
58 | {ACAFEF06-B0D1-45E3-8CCA-F4F214E5F591}.Release|Any CPU.ActiveCfg = Release|Any CPU
59 | {ACAFEF06-B0D1-45E3-8CCA-F4F214E5F591}.Release|Any CPU.Build.0 = Release|Any CPU
60 | EndGlobalSection
61 | GlobalSection(SolutionProperties) = preSolution
62 | HideSolutionNode = FALSE
63 | EndGlobalSection
64 | GlobalSection(NestedProjects) = preSolution
65 | {4C6BA65B-B5BA-42F5-B36B-31AF140DA62B} = {BF264141-E863-40AE-A5A4-9EFE4FDC2C3E}
66 | {FC873F3E-4AE0-430B-B421-21EC1F330DB0} = {4B9D0EA8-0F29-4AC0-9531-76140EC49E38}
67 | {4C0ED39A-DB9A-4604-9DA0-944AC3EB02A3} = {4B9D0EA8-0F29-4AC0-9531-76140EC49E38}
68 | {45DDBE95-E1BE-4AD3-B2BE-C95EF181F0B8} = {4B9D0EA8-0F29-4AC0-9531-76140EC49E38}
69 | {26A5CECA-B06D-4B9E-B202-08E7152AE966} = {4B9D0EA8-0F29-4AC0-9531-76140EC49E38}
70 | {269A2DF7-83EC-451F-AD42-6C7C9D862438} = {4B9D0EA8-0F29-4AC0-9531-76140EC49E38}
71 | {ACAFEF06-B0D1-45E3-8CCA-F4F214E5F591} = {4B9D0EA8-0F29-4AC0-9531-76140EC49E38}
72 | EndGlobalSection
73 | GlobalSection(ExtensibilityGlobals) = postSolution
74 | SolutionGuid = {04B8C314-25DD-44F9-BDBF-B22B921C26E9}
75 | EndGlobalSection
76 | EndGlobal
77 |
--------------------------------------------------------------------------------
/Czar.Rpc.Client/Czar.Rpc.Client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.2
6 |
7 |
8 |
9 | 7.1
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Always
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Czar.Rpc.Client/CzarConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "CzarHost": {
3 | "ProxyEndPoint": true,
4 | "IsSsl": "false",
5 | "PfxPath": "cert/datasync.pfx",
6 | "PfxPassword": "123456",
7 | "ClientConfig": {
8 | "Demo.Rpc.Hello": {
9 | "Host": "127.0.0.1",
10 | "Port": 7711,
11 | "Timeout": 10
12 | }
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Czar.Rpc.Client/Program.cs:
--------------------------------------------------------------------------------
1 | using AspectCore.Extensions.DependencyInjection;
2 | using Czar.Rpc.Codec;
3 | using Czar.Rpc.Common;
4 | using Czar.Rpc.Diagnostics;
5 | using Czar.Rpc.DotNetty.Extensions;
6 | using Czar.Rpc.Exceptions;
7 | using Czar.Rpc.Extensions;
8 | using Czar.Rpc.Message;
9 | using DotNetty.Common.Internal.Logging;
10 | using Microsoft.Extensions.Configuration;
11 | using Microsoft.Extensions.DependencyInjection;
12 | using Microsoft.Extensions.Logging;
13 | using Microsoft.Extensions.Logging.Console;
14 | using System;
15 | using System.Collections.Generic;
16 | using System.Data.SqlClient;
17 | using System.Diagnostics;
18 | using System.Net;
19 | using System.Threading;
20 | using System.Threading.Tasks;
21 |
22 | namespace Czar.Rpc.Client
23 | {
24 | class Program
25 | {
26 | public static IServiceProvider service;
27 | public static IConfiguration config;
28 | static async Task Main(string[] args)
29 | {
30 | List list_error = new List();
31 | try
32 | {
33 | var builder = new ConfigurationBuilder();
34 | config = builder.AddJsonFile("CzarConfig.json").Build();
35 |
36 | service = new ServiceCollection()
37 | .AddSingleton(config)
38 | .AddLogging(j => j.AddConsole())
39 | .AddLibuvTcpClient(config)
40 | .AddProxy()
41 | .BuildDynamicProxyServiceProvider();
42 |
43 | var rpc = service.GetRequiredService();
44 | rpc.CzarEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7711);
45 | var result = string.Empty;
46 |
47 | string t = "基本调用";
48 | result = rpc.Hello(18, t);
49 | Console.WriteLine(result);
50 |
51 | result = "无返回结果";
52 | rpc.HelloHolder(1, out result);
53 | Console.WriteLine(result);
54 | result = await rpc.HelloTask(2, "异步任务");
55 | Console.WriteLine(result);
56 | result = "单向";
57 | await rpc.HelloOneway(3, "单向调用");
58 | Console.WriteLine(result);
59 | result = await rpc.HelloValueTask(4, "ValueTask任务");
60 | Console.WriteLine(result);
61 |
62 | var modelResult = rpc.HelloModel(5, "返回实体", DateTime.Now);
63 | Console.WriteLine($"{modelResult.T1} {modelResult.T2} {modelResult.T3.ToLongDateString()}");
64 |
65 |
66 | var modelResult1 = await rpc.HelloModelAsync(6, "返回Task实体", DateTime.Now);
67 | Console.WriteLine($"{modelResult1.T1} {modelResult1.T2} {modelResult1.T3.ToLongDateString()}");
68 |
69 | var mm = new DemoModel()
70 | {
71 | T1 = 7,
72 | T2 = "传实体返回实体",
73 | T3 = DateTime.Now,
74 | Child = new ChildModel()
75 | {
76 | C1 = "子类1"
77 | }
78 | };
79 | var model2 = rpc.HelloSendModel(mm);
80 | Console.WriteLine($"{model2.T1} {model2.T2} {model2.T3.ToLongDateString()} {model2.Child.C1}");
81 |
82 | var list = new List();
83 | var mm1 = new DemoModel()
84 | {
85 | T1 = 8,
86 | T2 = "传List返回List",
87 | T3 = DateTime.Now,
88 | Child = new ChildModel()
89 | {
90 | C1 = "子类2"
91 | }
92 | };
93 | var mm3 = new DemoModel()
94 | {
95 | T1 = 9,
96 | T2 = "传List返回List",
97 | T3 = DateTime.Now,
98 | Child = new ChildModel()
99 | {
100 | C1 = "子类3"
101 | }
102 | };
103 | list.Add(mm1);
104 | list.Add(mm3);
105 | var list3 = rpc.HelloSendModelList(list);
106 | Console.WriteLine($"{list3[0].T1} {list3[0].T2} {list3[0].T3.ToLongDateString()} {list3[0].Child?.C1}");
107 |
108 |
109 | var mm4 = new DemoModel()
110 | {
111 | T1 = 9,
112 | T2 = "HelloSendModelParm",
113 | T3 = DateTime.Now,
114 | Child = new ChildModel()
115 | {
116 | C1 = "子类4"
117 | }
118 | };
119 | var dd = rpc.HelloSendModelParm("HelloSendModelParm", mm4);
120 | Console.WriteLine($"{dd.T1} {dd.T2} {dd.T3.ToLongDateString()} {dd.Child.C1}");
121 |
122 | //异常调用
123 | await rpc.TestBusinessExceptionInterceptor();
124 | }
125 | catch (BusinessException e)
126 | {
127 | Console.WriteLine($"CzarCode:{e.CzarCode} CzarMessage:{e.CzarMessage}");
128 | }
129 | catch (Exception ex)
130 | {
131 | Console.WriteLine(ex);
132 | }
133 | Console.ReadLine();
134 |
135 | }
136 |
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/Czar.Rpc.Server/Czar.Rpc.Server.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | Always
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Czar.Rpc.Server/CzarConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "Environment": "Development",
3 | "CzarHost": {
4 | "Port": 7711,
5 | "QuietPeriodSeconds": 2,
6 | "ShutdownTimeoutSeconds": 2,
7 | "IsSsl": "false",
8 | "PfxPath": "cert/datasync.pfx",
9 | "PfxPassword": "123456"
10 | }
11 | }
--------------------------------------------------------------------------------
/Czar.Rpc.Server/HelloRpcServer.cs:
--------------------------------------------------------------------------------
1 | using Czar.Rpc.Exceptions;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using System.Linq;
6 | using System.Net;
7 | using Czar.Rpc.Common;
8 |
9 | namespace Demo.Rpc.Server
10 | {
11 | public class HelloRpcServer: IHelloRpc
12 | {
13 | public EndPoint CzarEndPoint { get; set; }
14 |
15 | public string Hello(int no, string name)
16 | {
17 | string result = $"{no}: Hi, {name}";
18 | Console.WriteLine(result);
19 | return result + " callback";
20 | }
21 |
22 | public void HelloHolder(int no, out string name)
23 | {
24 | name = no.ToString() + " out";
25 | }
26 |
27 | public async Task HelloOneway(int no, string name)
28 | {
29 | await Task.Delay(10000);
30 | Console.WriteLine($"From oneway - {no}: Hi, {name}");
31 | }
32 |
33 | public Task HelloTask(int no, string name)
34 | {
35 | return Task.FromResult(Hello(no, name));
36 | }
37 |
38 | public ValueTask HelloValueTask(int no, string name)
39 | {
40 | return new ValueTask(Hello(no, name));
41 | }
42 |
43 | public Task TestBusinessExceptionInterceptor()
44 | {
45 | throw new BusinessException()
46 | {
47 | CzarCode = "1",
48 | CzarMessage = "test"
49 | };
50 | }
51 |
52 | public DemoModel HelloModel(int D1, string D2, DateTime D3)
53 | {
54 | return new DemoModel()
55 | {
56 | T1 = D1 + 1,
57 | T2 = D2 + "2",
58 | T3 = D3.AddDays(1)
59 | };
60 | }
61 |
62 | public async Task HelloModelAsync(int D1, string D2, DateTime D3)
63 | {
64 | return await Task.FromResult(
65 | new DemoModel()
66 | {
67 | T1 = D1 + 1,
68 | T2 = D2 + "77777",
69 | T3 = D3.AddDays(1)
70 | }
71 | );
72 | }
73 |
74 | public DemoModel HelloSendModel(DemoModel model)
75 | {
76 | model.T1 = model.T1 + 10;
77 | model.T2 = model.T2 + "11";
78 | model.T3 = model.T3.AddDays(12);
79 | return model;
80 | }
81 |
82 | public DemoModel HelloSendModelParm(string name, DemoModel model)
83 | {
84 | model.T1 = model.T1 + 10;
85 | model.T2 = model.T2 + "11";
86 | model.T3 = model.T3.AddDays(12);
87 | if (model.Child != null)
88 | {
89 | model.Child.C1 = name+"说:"+ model.Child.C1;
90 | }
91 | return model;
92 | }
93 |
94 | public List HelloSendModelList(List model)
95 | {
96 | return model.Select(t => new DemoModel() { T1=t.T1+10,T2=t.T2+"13",T3=t.T3.AddYears(1),Child=t.Child }).ToList();
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/Czar.Rpc.Server/Program.cs:
--------------------------------------------------------------------------------
1 | using Czar.Rpc.Codec;
2 | using Microsoft.Extensions.Hosting;
3 | using Microsoft.Extensions.Logging;
4 | using Microsoft.Extensions.Configuration;
5 | using Czar.Rpc.Extensions;
6 | using Czar.Rpc.DotNetty.Extensions;
7 | namespace Czar.Rpc.Server
8 | {
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 | var host = new HostBuilder()
14 | .ConfigureHostConfiguration(i => i.AddJsonFile("CzarConfig.json"))
15 | .ConfigureLogging((hostContext, configLogging) =>
16 | {
17 | configLogging.AddConsole();
18 | })
19 | .UseCodec()
20 | .UseLibuvTcpHost()
21 | .UseProxy()
22 | .UseConsoleLifetime()
23 | .Build();
24 |
25 | host.RunAsync().Wait();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 jinyancao
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Czar.gateway
2 |
3 | #### 项目介绍
4 | Czar网关项目,负责网关相关功能扩展及应用,目前支持mysql、sqlserver两种存储方式,已经实现动态路由、认证、授权、限流、缓存等特性,下一步将会增加日志和监控等功能。
5 |
6 | #### 博客同步更新地址
7 |
8 |
9 |
10 | #### 使用方式
11 |
12 | ```c#
13 | public void ConfigureServices(IServiceCollection services)
14 | {
15 | var authenticationProviderKey = "TestKey";
16 | Action gatewayoptions = o =>
17 | {
18 | o.Authority = "http://localhost:7777";
19 | o.ApiName = "gateway";
20 | o.RequireHttpsMetadata = false;
21 | };
22 |
23 | services.AddAuthentication()
24 | .AddIdentityServerAuthentication(authenticationProviderKey, gatewayoptions);
25 |
26 | Action options = o =>
27 | {
28 | o.Authority = "http://localhost:7777"; //IdentityServer地址
29 | o.RequireHttpsMetadata = false;
30 | o.ApiName = "gateway_admin"; //网关管理的名称,对应的为客户端授权的scope
31 | };
32 | services.AddOcelot().AddCzarOcelot(option =>
33 | {
34 | option.DbConnectionStrings = Configuration["CzarConfig:DbConnectionStrings"];
35 | option.RedisConnectionStrings = new List() { Configuration["CzarConfig:RedisConnectionStrings"]
36 | };
37 | //option.EnableTimer = true;//启用定时任务
38 | //option.TimerDelay = 10 * 000;//周期10秒
39 | option.ClientAuthorization = true;
40 | option.ClientRateLimit = true;
41 | })
42 | //.UseMySql() //使用mysql
43 | .AddAdministration("/CzarOcelot", options);
44 | }
45 |
46 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
47 | {
48 | if (env.IsDevelopment())
49 | {
50 | app.UseDeveloperExceptionPage();
51 | }
52 | else
53 | {
54 | app.UseExceptionHandler("/Error");
55 | }
56 | app.UseCzarOcelot().Wait();
57 | }
58 | ```
59 |
60 |
61 |
62 | #### 版本更新记录
63 |
64 | **0.2.0版本更新记录**
65 | 初始化项目内容,并统一风格。
66 |
67 | **0.2.1版本更新记录**
68 |
69 | 修复缓存信息失效后,未从数据库提出最新的配置信息bug。
70 |
71 | **0.3.0版本更新记录**
72 |
73 | 增加异常信息统一json格式输出
74 |
75 | ```json
76 | {"errcode":500,"errmsg":"请求服务不可用"}
77 | ```
78 |
79 | **0.3.1版本更新记录**
80 |
81 | 兼容Ids4自定义的错误输出,并保持风格统一
--------------------------------------------------------------------------------
/doc/czar.gateway.20190109.sqlserver2008r2.bak:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jinyancao/czar.gateway/aca749cf57a701b5124949a40bc74b73f6484486/doc/czar.gateway.20190109.sqlserver2008r2.bak
--------------------------------------------------------------------------------
/doc/czar.gateway.sqlserver2008r2.bak:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jinyancao/czar.gateway/aca749cf57a701b5124949a40bc74b73f6484486/doc/czar.gateway.sqlserver2008r2.bak
--------------------------------------------------------------------------------
/sample/Czar.Rpc.Common/Czar.Rpc.Common.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.2
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/sample/Czar.Rpc.Common/DemoModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Czar.Rpc.Common
6 | {
7 | public class DemoModel
8 | {
9 | ///
10 | /// 测试1
11 | ///
12 | public int T1 { get; set; }
13 |
14 | ///
15 | /// 测试2
16 | ///
17 | public string T2 { get; set; }
18 |
19 | ///
20 | /// 测试3
21 | ///
22 | public DateTime T3 { get; set; }
23 |
24 | public ChildModel Child { get; set; }
25 | }
26 |
27 | public class ChildModel
28 | {
29 | public string C1 { get; set; }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/sample/Czar.Rpc.Common/IHelloRpc.cs:
--------------------------------------------------------------------------------
1 | using Czar.Rpc.Attributes;
2 | using Czar.Rpc.Exceptions;
3 | using Czar.Rpc.Metadata;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 |
8 | namespace Czar.Rpc.Common
9 | {
10 | ///
11 | /// 测试Rpc实体
12 | ///
13 | [BusinessExceptionInterceptor]
14 | [CzarRpc("Demo.Rpc.Hello")]
15 | public interface IHelloRpc: IRpcBaseService
16 | {
17 | string Hello(int no, string name);
18 |
19 | void HelloHolder(int no, out string name);
20 |
21 | Task HelloTask(int no, string name);
22 |
23 | ValueTask HelloValueTask(int no, string name);
24 |
25 | [CzarOneway]
26 | Task HelloOneway(int no, string name);
27 |
28 | Task TestBusinessExceptionInterceptor();
29 |
30 | DemoModel HelloModel(int D1, string D2, DateTime D3);
31 |
32 | Task HelloModelAsync(int D1, string D2, DateTime D3);
33 |
34 | DemoModel HelloSendModel(DemoModel model);
35 |
36 | DemoModel HelloSendModelParm(string name,DemoModel model);
37 |
38 | List HelloSendModelList(List model);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.SqlServer/Czar.Sample.SqlServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.2
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Always
24 |
25 |
26 | Always
27 |
28 |
29 | Always
30 |
31 |
32 |
33 |
34 |
35 | Always
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.SqlServer/CzarConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "Environment": "Development",
3 | "CzarHost": {
4 | "ProxyEndPoint": true,
5 | "IsSsl": "false",
6 | "PfxPath": "cert/datasync.pfx",
7 | "PfxPassword": "bl123456",
8 | "ClientConfig": {
9 | "Demo.Rpc.Hello": {
10 | "Host": "127.0.0.1",
11 | "Port": 1111,
12 | "Timeout": 20
13 | }
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/sample/Czar.Sample.SqlServer/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.DependencyInjection;
10 | using Microsoft.Extensions.Logging;
11 |
12 | namespace Czar.Sample.SqlServer
13 | {
14 | public class Program
15 | {
16 | public static void Main(string[] args)
17 | {
18 | CreateWebHostBuilder(args).Build().Run();
19 | }
20 |
21 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
22 | WebHost.CreateDefaultBuilder(args)
23 | .ConfigureAppConfiguration(option=>option.AddJsonFile("CzarConfig.json"))
24 | .UseStartup()
25 | ;
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.SqlServer/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using AspectCore.Extensions.Reflection;
6 | using Czar.Gateway.Middleware;
7 | using Czar.Rpc.Clients;
8 | using Czar.Rpc.Codec;
9 | using Czar.Rpc.Configurations;
10 | using Czar.Rpc.DotNetty.Extensions;
11 | using Czar.Rpc.DotNetty.Tcp;
12 | using Czar.Rpc.Extensions;
13 | using DotNetty.Buffers;
14 | using IdentityServer4.AccessTokenValidation;
15 | using Microsoft.AspNetCore.Builder;
16 | using Microsoft.AspNetCore.Hosting;
17 | using Microsoft.AspNetCore.Mvc;
18 | using Microsoft.Extensions.Configuration;
19 | using Microsoft.Extensions.DependencyInjection;
20 | using Microsoft.Extensions.DependencyInjection.Extensions;
21 | using Microsoft.Extensions.Logging;
22 | using Microsoft.Extensions.Options;
23 | using Ocelot.Administration;
24 | using Ocelot.DependencyInjection;
25 |
26 | namespace Czar.Sample.SqlServer
27 | {
28 | public class Startup
29 | {
30 | public Startup(IConfiguration configuration)
31 | {
32 | Configuration = configuration;
33 | }
34 |
35 | public IConfiguration Configuration { get; }
36 |
37 | // This method gets called by the runtime. Use this method to add services to the container.
38 | public void ConfigureServices(IServiceCollection services)
39 | {
40 | var authenticationProviderKey = "TestKey";
41 | Action gatewayoptions = o =>
42 | {
43 | o.Authority = "http://localhost:6611";
44 | o.ApiName = "gateway";
45 | o.RequireHttpsMetadata = false;
46 | };
47 |
48 | services.AddAuthentication()
49 | .AddIdentityServerAuthentication(authenticationProviderKey, gatewayoptions);
50 |
51 | Action options = o =>
52 | {
53 | o.Authority = "http://localhost:6611"; //IdentityServer地址
54 | o.RequireHttpsMetadata = false;
55 | o.ApiName = "gateway_admin"; //网关管理的名称,对应的为客户端授权的scope
56 | };
57 | services.AddCzarOcelot(option =>
58 | {
59 | option.RedisOcelotKeyPrefix = "CzarGateway1";
60 | option.DbConnectionStrings = "Server=.;Database=Ctr_AuthPlatform;User ID=sa;Password=bl123456;";
61 | option.RedisConnectionString = "192.168.1.111:6379,password=bl123456,defaultDatabase=0,poolsize=50,ssl=false,writeBuffer=10240,connectTimeout=1000,connectRetry=1;"
62 | ;
63 | option.ClientAuthorization = true;
64 | option.ClientRateLimit = true;
65 | })
66 | //.UseMySql()
67 | .AddAdministration("/CzarOcelot", options);
68 | #region 注入Rpc相关的服务
69 | services.AddLibuvTcpClient(Configuration);
70 | #endregion
71 | }
72 |
73 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
74 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
75 | {
76 | if (env.IsDevelopment())
77 | {
78 | app.UseDeveloperExceptionPage();
79 | }
80 | app.UseCzarOcelot().Wait();
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.SqlServer/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.SqlServer/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Warning"
5 | }
6 | },
7 | "AllowedHosts": "*"
8 | }
9 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestApi/Controllers/ValuesController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using CSRedis;
6 | using Microsoft.AspNetCore.Mvc;
7 |
8 | namespace Czar.Sample.TestApi.Controllers
9 | {
10 | public struct CzarClientRateLimitCounter
11 | {
12 | public CzarClientRateLimitCounter(DateTime timestamp, long totalRequests)
13 | {
14 | Timestamp = timestamp;
15 | TotalRequests = totalRequests;
16 | }
17 |
18 | ///
19 | /// 最后请求时间
20 | ///
21 | public DateTime Timestamp { get; private set; }
22 |
23 | ///
24 | /// 请求总数
25 | ///
26 | public long TotalRequests { get; private set; }
27 | }
28 |
29 | [Route("api/[controller]")]
30 | [ApiController]
31 | public class ValuesController : ControllerBase
32 | {
33 | public ValuesController()
34 | {
35 | }
36 | // GET api/values
37 | [HttpGet]
38 | public ActionResult> Get()
39 | {
40 | return new string[] { "value11", "value2" };
41 | }
42 |
43 | // GET api/values/5
44 | [HttpGet("{id}")]
45 | public ActionResult Get(int id)
46 | {
47 | // throw new Exception("测试异常");
48 | //RedisHelper.Set("2132", id);
49 | //RedisHelper.Publish("CzarGateway1-eff-dsf", $"測試{id}");
50 | return $"return {id}";
51 | }
52 |
53 | // POST api/values
54 | [HttpPost]
55 | public void Post([FromBody] string value)
56 | {
57 | }
58 |
59 | // PUT api/values/5
60 | [HttpPut("{id}")]
61 | public void Put(int id, [FromBody] string value)
62 | {
63 | }
64 |
65 | // DELETE api/values/5
66 | [HttpDelete("{id}")]
67 | public void Delete(int id)
68 | {
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestApi/Czar.Sample.TestApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestApi/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace Czar.Sample.TestApi
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | CreateWebHostBuilder(args).Build().Run();
18 | }
19 |
20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseStartup();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestApi/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.AspNetCore.Mvc;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.DependencyInjection;
10 | using Microsoft.Extensions.Logging;
11 | using Microsoft.Extensions.Options;
12 |
13 | namespace Czar.Sample.TestApi
14 | {
15 | public class Startup
16 | {
17 | public Startup(IConfiguration configuration)
18 | {
19 | Configuration = configuration;
20 | }
21 |
22 | public IConfiguration Configuration { get; }
23 |
24 | // This method gets called by the runtime. Use this method to add services to the container.
25 | public void ConfigureServices(IServiceCollection services)
26 | {
27 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
28 | var csredis = new CSRedis.CSRedisClient("192.168.1.111:6379,password=bl123456,defaultDatabase=0,poolsize=500,ssl=false");
29 |
30 | RedisHelper.Initialization(csredis);
31 | }
32 |
33 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
34 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
35 | {
36 | //Console.WriteLine(env.EnvironmentName);
37 | if (env.IsDevelopment())
38 | {
39 | app.UseDeveloperExceptionPage();
40 | }
41 |
42 | app.UseMvc();
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestApi/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Warning",
5 | "System": "Warning",
6 | "Microsoft": "Warning"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Warning"
5 | }
6 | },
7 | "AllowedHosts": "*"
8 | }
9 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/Czar.Sample.TestIds4.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace Czar.Sample.TestIds4
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | CreateWebHostBuilder(args).Build().Run();
18 | }
19 |
20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseStartup();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using IdentityServer4.Models;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.AspNetCore.Http;
9 | using Microsoft.AspNetCore.Mvc;
10 | using Microsoft.Extensions.Configuration;
11 | using Microsoft.Extensions.DependencyInjection;
12 |
13 | namespace Czar.Sample.TestIds4
14 | {
15 | public class Startup
16 | {
17 | public Startup(IConfiguration configuration)
18 | {
19 | Configuration = configuration;
20 | }
21 |
22 | public IConfiguration Configuration { get; }
23 |
24 | // This method gets called by the runtime. Use this method to add services to the container.
25 | public void ConfigureServices(IServiceCollection services)
26 | {
27 | services.Configure(options =>
28 | {
29 | // This lambda determines whether user consent for non-essential cookies is needed for a given request.
30 | options.CheckConsentNeeded = context => true;
31 | options.MinimumSameSitePolicy = SameSiteMode.None;
32 | });
33 | services.AddIdentityServer()
34 | .AddDeveloperSigningCredential()
35 | .AddInMemoryApiResources(Config.GetApiResources())
36 | .AddInMemoryClients(Config.GetClients());
37 |
38 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
39 | }
40 |
41 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
42 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
43 | {
44 | if (env.IsDevelopment())
45 | {
46 | app.UseDeveloperExceptionPage();
47 | }
48 | else
49 | {
50 | app.UseExceptionHandler("/Error");
51 | }
52 |
53 | app.UseStaticFiles();
54 | app.UseCookiePolicy();
55 | app.UseIdentityServer();
56 | app.UseMvc();
57 | }
58 | }
59 |
60 | public class Config
61 | {
62 | // scopes define the API resources in your system
63 | public static IEnumerable GetApiResources()
64 | {
65 | return new List
66 | {
67 | new ApiResource("gateway", "My Test API"),
68 | new ApiResource("gateway_admin", "My admin API")
69 | };
70 | }
71 |
72 | // clients want to access resources (aka scopes)
73 | public static IEnumerable GetClients()
74 | {
75 | // client credentials client
76 | return new List
77 | {
78 | new Client
79 | {
80 | ClientId = "client1",
81 | AllowedGrantTypes = GrantTypes.ClientCredentials,
82 |
83 | ClientSecrets =
84 | {
85 | new Secret("secret1".Sha256())
86 | },
87 | AllowedScopes = { "gateway" }
88 | },
89 | new Client
90 | {
91 | ClientId = "client2",
92 | AllowedGrantTypes = GrantTypes.ClientCredentials,
93 |
94 | ClientSecrets =
95 | {
96 | new Secret("secret2".Sha256())
97 | },
98 | AllowedScopes = { "gateway","gateway_admin" }
99 | }
100 | };
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Warning"
5 | }
6 | },
7 | "AllowedHosts": "*"
8 | }
9 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/tempkey.rsa:
--------------------------------------------------------------------------------
1 | {"KeyId":"502e5e5c2621a429aa0d890088578461","Parameters":{"D":"V1PPOVf20fjW9hcfCiGky09k+pnwxLUnochYyVxv5FSLb+NjwP1SeNdbhKannl3RbzIHStC+CA92XzTxm2sT7dxz+KowyvB9CMhEC2ivPaqDRN1rWr3lf6Nxz4kAvKRwM20ZUg1pORzhqMTa0q39wAwIm6Gl5b3BqaGGhszGEhLgmeUJKmgzM6RcbFDxv2RggDHnfDwDluimX94Uuj89N2dw1304Wk1Jdh7/xqIoJwddhq+W/CjvdpHfYECIDT1ESOW+7jdFSO2ReuWyS9L4HibmjayCwkej4LLx9MjgdRnS34/v3oHxNqgCFsf2zecggxfBTln+2SCsNEpE95v/NQ==","DP":"Zo+coaNw7yZyxp/QOtI8oMM+arl8LbH4IL53BywoD5rxbOdt8v4PsGkqaoWwAjQskOFM1RP0CY5byRngphWnVbDmFdzr0NHVaE+M86SvHybncI7Uq7BoZTPG39eCwEt6dyIdcFtn86P0XFw900EWPDBvoQBAVre3fuI9Be3Pmhs=","DQ":"EYiJjZzGKxY1ghYXEhfFBIH7GZIhAx6HQHFWqDNP3tRXsEZgnBOsMjsbDQNJTpb3hOv/go/Ch3NLn6gK8ZF5g2lUCxob9HAd9UvjVE+oyo1fPM2aPQwld64x9GhmmU9bk2UNGqnJN41FBklX2/LyHriICm+H9iG9wAxzZEPpX1k=","Exponent":"AQAB","InverseQ":"Rc8V+D/BA5x52H9YT8wliWFAMdxkYIQFV8u4iEqu7ADdqa8UMJfk6IgXaEympcjuzL1dZUVZwcmuN2W9UUdpIzJ7lUJlbFSe3dIQNfG6Np1g1MNSCjYAUL1MKv+35OIAGbFVaF5sTkDv52GVplwaSVc/m9XDAyKJd0PI3qKZPiM=","Modulus":"t17UoLlwAEJ6hCe1RYDOq98HhXuHWbUM/eiDcldMaP4BREYkgMiwGnWCGIJ7v1AC3NlYy884VNLI3KJxmpwM5tBmqxmYQEAbxExi0WBS/jwIGUS+p3NiATSMFfjmKxJF9sZiqns1QuxDd/6mx8v38hqICh+oIfRU3yjn5XOquFn7ZkLqOqL/9jzmzSUD1JHy7B4SJFAK+Cbf9eZYzG9wo7TcZ5OyqNxcb3mMN2DmxQxQYO0qyHfRJlpGttbpEPCrXKN+nGrMNe5U12dCAOlxbfM0JfjwoGz6ZpRBqQixnDXyiYUoZP4CeSCdb2Ol0bs1pvNCl/StteCaix9D2/M+7Q==","P":"wPyikO6EoZyQ5Rwmcjm5cgmQXW9a0gLKsbtrxfT0UZv4rZapyuq9qv5ww7FA/zrFPjBkPqiqcoxiSGlioct03uOaw5TYslPw39XRs9lqxm0UzfCWm/5puOzD3YBCCGGDZ2oH4gR03HJH5uVqa3dxvS1MRNOMav1oLcKnki3zMgM=","Q":"8z5hArowjESHtg+reKzuPYHSPPpJjRbjjEd720GvC7eFIKB0UbxiTEN7x40F9E870jyAP0GFs5SmosXUu/VUJyv5Tbf7lgFuMYXHN97lBi/JDzgXHujxQCTwUTKrVmDxMT1fJQG6RiZmEo2qA57I0KwLbr5zMUxLiAf9cAes8E8="}}
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | for details on configuring this project to bundle and minify static web assets. */
3 | body {
4 | padding-top: 50px;
5 | padding-bottom: 20px;
6 | }
7 |
8 | /* Wrapping element */
9 | /* Set some basic padding to keep content from hitting the edges */
10 | .body-content {
11 | padding-left: 15px;
12 | padding-right: 15px;
13 | }
14 |
15 | /* Carousel */
16 | .carousel-caption p {
17 | font-size: 20px;
18 | line-height: 1.4;
19 | }
20 |
21 | /* Make .svg files in the carousel display properly in older browsers */
22 | .carousel-inner .item img[src$=".svg"] {
23 | width: 100%;
24 | }
25 |
26 | /* QR code generator */
27 | #qrCode {
28 | margin: 15px;
29 | }
30 |
31 | /* Hide/rearrange for smaller screens */
32 | @media screen and (max-width: 767px) {
33 | /* Hide captions */
34 | .carousel-caption {
35 | display: none;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/css/site.min.css:
--------------------------------------------------------------------------------
1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}#qrCode{margin:15px}@media screen and (max-width:767px){.carousel-caption{display:none}}
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jinyancao/czar.gateway/aca749cf57a701b5124949a40bc74b73f6484486/sample/Czar.Sample.TestIds4/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/images/banner2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | // for details on configuring this project to bundle and minify static web assets.
3 |
4 | // Write your Javascript code.
5 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/js/site.min.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jinyancao/czar.gateway/aca749cf57a701b5124949a40bc74b73f6484486/sample/Czar.Sample.TestIds4/wwwroot/js/site.min.js
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/bootstrap/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap",
3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
4 | "keywords": [
5 | "css",
6 | "js",
7 | "less",
8 | "mobile-first",
9 | "responsive",
10 | "front-end",
11 | "framework",
12 | "web"
13 | ],
14 | "homepage": "http://getbootstrap.com",
15 | "license": "MIT",
16 | "moduleType": "globals",
17 | "main": [
18 | "less/bootstrap.less",
19 | "dist/js/bootstrap.js"
20 | ],
21 | "ignore": [
22 | "/.*",
23 | "_config.yml",
24 | "CNAME",
25 | "composer.json",
26 | "CONTRIBUTING.md",
27 | "docs",
28 | "js/tests",
29 | "test-infra"
30 | ],
31 | "dependencies": {
32 | "jquery": "1.9.1 - 3"
33 | },
34 | "version": "3.3.7",
35 | "_release": "3.3.7",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.3.7",
39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86"
40 | },
41 | "_source": "https://github.com/twbs/bootstrap.git",
42 | "_target": "v3.3.7",
43 | "_originalSource": "bootstrap",
44 | "_direct": true
45 | }
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2016 Twitter, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jinyancao/czar.gateway/aca749cf57a701b5124949a40bc74b73f6484486/sample/Czar.Sample.TestIds4/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jinyancao/czar.gateway/aca749cf57a701b5124949a40bc74b73f6484486/sample/Czar.Sample.TestIds4/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jinyancao/czar.gateway/aca749cf57a701b5124949a40bc74b73f6484486/sample/Czar.Sample.TestIds4/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jinyancao/czar.gateway/aca749cf57a701b5124949a40bc74b73f6484486/sample/Czar.Sample.TestIds4/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/bootstrap/dist/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition.js')
3 | require('../../js/alert.js')
4 | require('../../js/button.js')
5 | require('../../js/carousel.js')
6 | require('../../js/collapse.js')
7 | require('../../js/dropdown.js')
8 | require('../../js/modal.js')
9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/jquery-validation-unobtrusive/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation-unobtrusive",
3 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive",
4 | "version": "3.2.9",
5 | "_release": "3.2.9",
6 | "_resolution": {
7 | "type": "version",
8 | "tag": "v3.2.9",
9 | "commit": "a91f5401898e125f10771c5f5f0909d8c4c82396"
10 | },
11 | "_source": "https://github.com/aspnet/jquery-validation-unobtrusive.git",
12 | "_target": "^3.2.9",
13 | "_originalSource": "jquery-validation-unobtrusive",
14 | "_direct": true
15 | }
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) .NET Foundation. All rights reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4 | these files except in compliance with the License. You may obtain a copy of the
5 | License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software distributed
10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the
12 | specific language governing permissions and limitations under the License.
13 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | // Unobtrusive validation support library for jQuery and jQuery Validate
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // @version v3.2.9
4 | !function(a){"function"==typeof define&&define.amd?define("jquery.validate.unobtrusive",["jquery.validation"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery-validation")):jQuery.validator.unobtrusive=a(jQuery)}(function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function u(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=f.unobtrusive.options||{},u=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),u("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),u("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),u("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var m,f=a.validator,v="unobtrusiveValidation";return f.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=u(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){f.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=u(this);a&&a.attachValidation()})}},m=f.unobtrusive.adapters,m.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},m.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},m.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},m.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},f.addMethod("__dummy__",function(a,e,n){return!0}),f.addMethod("regex",function(a,e,n){var t;return!!this.optional(e)||(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),f.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),f.methods.extension?(m.addSingleVal("accept","mimtype"),m.addSingleVal("extension","extension")):m.addSingleVal("extension","extension","accept"),m.addSingleVal("regex","pattern"),m.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),m.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),m.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),m.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),m.add("required",function(a){"INPUT"===a.element.tagName.toUpperCase()&&"CHECKBOX"===a.element.type.toUpperCase()||e(a,"required",!0)}),m.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),m.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),m.add("fileextensions",["extensions"],function(a){e(a,"extension",a.params.extensions)}),a(function(){f.unobtrusive.parse(document)}),f.unobtrusive});
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/jquery-validation/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation",
3 | "homepage": "https://jqueryvalidation.org/",
4 | "repository": {
5 | "type": "git",
6 | "url": "git://github.com/jquery-validation/jquery-validation.git"
7 | },
8 | "authors": [
9 | "Jörn Zaefferer "
10 | ],
11 | "description": "Form validation made easy",
12 | "main": "dist/jquery.validate.js",
13 | "keywords": [
14 | "forms",
15 | "validation",
16 | "validate"
17 | ],
18 | "license": "MIT",
19 | "ignore": [
20 | "**/.*",
21 | "node_modules",
22 | "bower_components",
23 | "test",
24 | "demo",
25 | "lib"
26 | ],
27 | "dependencies": {
28 | "jquery": ">= 1.7.2"
29 | },
30 | "version": "1.17.0",
31 | "_release": "1.17.0",
32 | "_resolution": {
33 | "type": "version",
34 | "tag": "1.17.0",
35 | "commit": "fc9b12d3bfaa2d0c04605855b896edb2934c0772"
36 | },
37 | "_source": "https://github.com/jzaefferer/jquery-validation.git",
38 | "_target": "^1.17.0",
39 | "_originalSource": "jquery-validation",
40 | "_direct": true
41 | }
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/jquery/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery",
3 | "main": "dist/jquery.js",
4 | "license": "MIT",
5 | "ignore": [
6 | "package.json"
7 | ],
8 | "keywords": [
9 | "jquery",
10 | "javascript",
11 | "browser",
12 | "library"
13 | ],
14 | "homepage": "https://github.com/jquery/jquery-dist",
15 | "version": "3.3.1",
16 | "_release": "3.3.1",
17 | "_resolution": {
18 | "type": "version",
19 | "tag": "3.3.1",
20 | "commit": "9e8ec3d10fad04748176144f108d7355662ae75e"
21 | },
22 | "_source": "https://github.com/jquery/jquery-dist.git",
23 | "_target": "^3.3.1",
24 | "_originalSource": "jquery",
25 | "_direct": true
26 | }
--------------------------------------------------------------------------------
/sample/Czar.Sample.TestIds4/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright JS Foundation and other contributors, https://js.foundation/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Authentication/CzarAuthenticationProcessor.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Configuration;
2 | using Ocelot.Cache;
3 | using System;
4 | using System.Threading.Tasks;
5 |
6 | namespace Czar.Gateway.Authentication
7 | {
8 | ///
9 | /// 金焰的世界
10 | /// 2018-11-15
11 | /// 实现自定义授权处理器逻辑
12 | ///
13 | public class CzarAuthenticationProcessor : ICzarAuthenticationProcessor
14 | {
15 | private readonly IClientAuthenticationRepository _clientAuthenticationRepository;
16 | private readonly CzarOcelotConfiguration _options;
17 | private readonly IOcelotCache _ocelotCache;
18 | public CzarAuthenticationProcessor(IClientAuthenticationRepository clientAuthenticationRepository, CzarOcelotConfiguration options, IOcelotCache ocelotCache)
19 | {
20 | _clientAuthenticationRepository = clientAuthenticationRepository;
21 | _options = options;
22 | _ocelotCache = ocelotCache;
23 | }
24 | ///
25 | /// 校验当前的请求地址客户端是否有权限访问
26 | ///
27 | /// 客户端ID
28 | /// 请求地址
29 | ///
30 | public async Task CheckClientAuthenticationAsync(string clientid, string path)
31 | {
32 | var enablePrefix = CzarCacheRegion.AuthenticationRegion;
33 | var key = CzarOcelotHelper.ComputeCounterKey(enablePrefix, clientid, "", path);
34 | var cacheResult = _ocelotCache.Get(key, enablePrefix);
35 | if (cacheResult!=null)
36 | {//提取缓存数据
37 | return cacheResult.Role;
38 | }
39 | else
40 | {//重新获取认证信息
41 | var result = await _clientAuthenticationRepository.ClientAuthenticationAsync(clientid, path);
42 | //添加到缓存里
43 | _ocelotCache.Add(key, new ClientRoleModel() { CacheTime = DateTime.Now,Role=result }, TimeSpan.FromMinutes(_options.CzarCacheTime), enablePrefix);
44 | return result;
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Authentication/IClientAuthenticationRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading.Tasks;
5 |
6 | namespace Czar.Gateway.Authentication
7 | {
8 | ///
9 | /// 金焰的世界
10 | /// 2018-11-15
11 | /// 客户端授权仓储接口
12 | ///
13 | public interface IClientAuthenticationRepository
14 | {
15 | ///
16 | /// 校验当前的请求地址是否有权限访问
17 | ///
18 | /// 客户端ID
19 | /// 请求地址
20 | ///
21 | Task ClientAuthenticationAsync(string clientid, string path);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Authentication/ICzarAuthenticationProcessor.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace Czar.Gateway.Authentication
4 | {
5 | ///
6 | /// 金焰的世界
7 | /// 2018-11-15
8 | /// 自定义授权处理器
9 | ///
10 | public interface ICzarAuthenticationProcessor
11 | {
12 | ///
13 | /// 校验当前的请求地址客户端是否有权限访问
14 | ///
15 | /// 客户端ID
16 | /// 请求地址
17 | ///
18 | Task CheckClientAuthenticationAsync(string clientid, string path);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Authentication/Middleware/CzarAuthenticationMiddleware.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Configuration;
2 | using Ocelot.Configuration;
3 | using Ocelot.Logging;
4 | using Ocelot.Middleware;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace Czar.Gateway.Authentication.Middleware
9 | {
10 | ///
11 | /// 金焰的世界
12 | /// 2018-11-15
13 | /// 自定义授权中间件
14 | ///
15 | public class CzarAuthenticationMiddleware : OcelotMiddleware
16 | {
17 | private readonly OcelotRequestDelegate _next;
18 | private readonly CzarOcelotConfiguration _options;
19 | private readonly ICzarAuthenticationProcessor _ahphAuthenticationProcessor;
20 | public CzarAuthenticationMiddleware(OcelotRequestDelegate next,
21 | IOcelotLoggerFactory loggerFactory,
22 | ICzarAuthenticationProcessor ahphAuthenticationProcessor,
23 | CzarOcelotConfiguration options)
24 | : base(loggerFactory.CreateLogger())
25 | {
26 | _next = next;
27 | _ahphAuthenticationProcessor = ahphAuthenticationProcessor;
28 | _options = options;
29 | }
30 |
31 | public async Task Invoke(DownstreamContext context)
32 | {
33 | if (!context.IsError && context.HttpContext.Request.Method.ToUpper() != "OPTIONS" && IsAuthenticatedRoute(context.DownstreamReRoute))
34 | {
35 | if (!_options.ClientAuthorization)
36 | {
37 | Logger.LogInformation($"未启用客户端认证中间件");
38 | await _next.Invoke(context);
39 | }
40 | else
41 | {
42 | Logger.LogInformation($"{context.HttpContext.Request.Path} 是认证路由. {MiddlewareName} 开始校验授权信息");
43 | #region 提取客户端ID
44 | var clientId = "client_cjy";
45 | var path = context.DownstreamReRoute.UpstreamPathTemplate.OriginalValue; //路由地址
46 | var clientClaim = context.HttpContext.User.Claims.FirstOrDefault(p => p.Type == _options.ClientKey);
47 | if (!string.IsNullOrEmpty(clientClaim?.Value))
48 | {//从Claims中提取客户端id
49 | clientId = clientClaim?.Value;
50 | }
51 | #endregion
52 | if (await _ahphAuthenticationProcessor.CheckClientAuthenticationAsync(clientId, path))
53 | {
54 | await _next.Invoke(context);
55 | }
56 | else
57 | {//未授权直接返回错误
58 | var error = new UnauthenticatedError($"请求认证路由 {context.HttpContext.Request.Path}客户端未授权");
59 | Logger.LogWarning($"路由地址 {context.HttpContext.Request.Path} 自定义认证管道校验失败. {error}");
60 | SetPipelineError(context, error);
61 | }
62 | }
63 | }
64 | else
65 | {
66 | await _next.Invoke(context);
67 | }
68 |
69 | }
70 | private static bool IsAuthenticatedRoute(DownstreamReRoute reRoute)
71 | {
72 | return reRoute.IsAuthenticated;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Authentication/Middleware/CzarAuthenticationMiddlewareExtensions.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Middleware.Pipeline;
2 |
3 | namespace Czar.Gateway.Authentication.Middleware
4 | {
5 | ///
6 | /// 金焰的世界
7 | /// 2018-11-15
8 | /// 使用自定义授权中间件
9 | ///
10 | public static class CzarAuthenticationMiddlewareExtensions
11 | {
12 | public static IOcelotPipelineBuilder UseAhphAuthenticationMiddleware(this IOcelotPipelineBuilder builder)
13 | {
14 | return builder.UseMiddleware();
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Cache/CzarCacheController.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Authentication;
2 | using Czar.Gateway.Configuration;
3 | using Czar.Gateway.RateLimit;
4 | using Czar.Gateway.Rpc;
5 | using Microsoft.AspNetCore.Authorization;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.Extensions.Caching.Memory;
8 | using Ocelot.Configuration;
9 | using Ocelot.Configuration.Creator;
10 | using Ocelot.Configuration.Repository;
11 | using System;
12 | using System.Threading.Tasks;
13 |
14 | namespace Czar.Gateway.Cache
15 | {
16 | ///
17 | /// 提供外部缓存处理接口
18 | ///
19 | [Authorize]
20 | [Route("CzarCache")]
21 | public class CzarCacheController : Controller
22 | {
23 | private readonly CzarOcelotConfiguration _options;
24 | private readonly IClientAuthenticationRepository _clientAuthenticationRepository;
25 | private IFileConfigurationRepository _fileConfigurationRepository;
26 | private IInternalConfigurationCreator _internalConfigurationCreator;
27 | private readonly IClientRateLimitRepository _clientRateLimitRepository;
28 | private readonly IRpcRepository _rpcRepository;
29 | private readonly IMemoryCache _cache;
30 | public CzarCacheController(IClientAuthenticationRepository clientAuthenticationRepository, CzarOcelotConfiguration options,
31 | IFileConfigurationRepository fileConfigurationRepository,
32 | IInternalConfigurationCreator internalConfigurationCreator,
33 | IClientRateLimitRepository clientRateLimitRepository,
34 | IRpcRepository rpcRepository,
35 | IMemoryCache cache)
36 | {
37 | _clientAuthenticationRepository = clientAuthenticationRepository;
38 | _options = options;
39 | _fileConfigurationRepository = fileConfigurationRepository;
40 | _internalConfigurationCreator = internalConfigurationCreator;
41 | _clientRateLimitRepository = clientRateLimitRepository;
42 | _rpcRepository = rpcRepository;
43 | _cache = cache;
44 | }
45 |
46 | ///
47 | /// 更新客户端地址访问授权接口
48 | ///
49 | /// 客户端ID
50 | /// 请求模板
51 | ///
52 | [HttpPost]
53 | [Route("ClientRule")]
54 | public async Task UpdateClientRuleCache(string clientid,string path)
55 | {
56 | var region = CzarCacheRegion.AuthenticationRegion;
57 | var key = CzarOcelotHelper.ComputeCounterKey(region, clientid, "", path);
58 | key = CzarOcelotHelper.GetKey(_options.RedisOcelotKeyPrefix, region, key);
59 | var result = await _clientAuthenticationRepository.ClientAuthenticationAsync(clientid, path);
60 | var data = new ClientRoleModel() { CacheTime = DateTime.Now, Role = result };
61 | if (_options.ClusterEnvironment)
62 | {
63 | RedisHelper.Set(key, data); //加入redis缓存
64 | RedisHelper.Publish(key, data.ToJson()); //发布事件
65 | }
66 | else
67 | {
68 | _cache.Remove(key);
69 | }
70 | }
71 |
72 | ///
73 | /// 更新网关配置路由信息
74 | ///
75 | ///
76 | [HttpPost]
77 | [Route("InternalConfiguration")]
78 | public async Task UpdateInternalConfigurationCache()
79 | {
80 | var key = CzarCacheRegion.InternalConfigurationRegion;
81 | key = CzarOcelotHelper.GetKey(_options.RedisOcelotKeyPrefix, "", key);
82 | var fileconfig = await _fileConfigurationRepository.Get();
83 | var internalConfig = await _internalConfigurationCreator.Create(fileconfig.Data);
84 | var config = (InternalConfiguration)internalConfig.Data;
85 | if (_options.ClusterEnvironment)
86 | {
87 | RedisHelper.Set(key, config); //加入redis缓存
88 | RedisHelper.Publish(key, config.ToJson()); //发布事件
89 | }
90 | else
91 | {
92 | _cache.Remove(key);
93 | }
94 | }
95 |
96 | ///
97 | /// 删除路由配合的缓存信息
98 | ///
99 | /// 区域
100 | /// 下端路由
101 | ///
102 | [HttpPost]
103 | [Route("Response")]
104 | public async Task DeleteResponseCache(string region,string downurl)
105 | {
106 | var key = CzarOcelotHelper.GetKey(_options.RedisOcelotKeyPrefix, region, downurl);
107 | if (_options.ClusterEnvironment)
108 | {
109 | await RedisHelper.DelAsync(key);
110 | RedisHelper.Publish(key, "");//发布时间
111 | }
112 | else
113 | {
114 | _cache.Remove(key);
115 | }
116 | }
117 |
118 | ///
119 | /// 更新客户端限流规则缓存
120 | ///
121 | /// 客户端ID
122 | /// 路由模板
123 | ///
124 | [HttpPost]
125 | [Route("RateLimitRule")]
126 | public async Task UpdateRateLimitRuleCache(string clientid, string path)
127 | {
128 | var region = CzarCacheRegion.RateLimitRuleModelRegion;
129 | var key = clientid + path;
130 | key = CzarOcelotHelper.GetKey(_options.RedisOcelotKeyPrefix, region, key);
131 | var result = await _clientRateLimitRepository.CheckClientRateLimitAsync(clientid, path);
132 | var data = new RateLimitRuleModel() { RateLimit = result.RateLimit, rateLimitOptions = result.rateLimitOptions };
133 | if (_options.ClusterEnvironment)
134 | {
135 | RedisHelper.Set(key, data); //加入redis缓存
136 | RedisHelper.Publish(key, data.ToJson()); //发布事件
137 | }
138 | else
139 | {
140 | _cache.Remove(key);
141 | }
142 | }
143 |
144 | ///
145 | /// 更新客户端是否开启限流缓存
146 | ///
147 | ///
148 | ///
149 | [HttpPost]
150 | [Route("ClientRole")]
151 | public async Task UpdateClientRoleCache(string path)
152 | {
153 | var region = CzarCacheRegion.ClientRoleModelRegion;
154 | var key = path;
155 | key = CzarOcelotHelper.GetKey(_options.RedisOcelotKeyPrefix, region, key);
156 | var result = await _clientRateLimitRepository.CheckReRouteRuleAsync(path);
157 | var data = new ClientRoleModel() { CacheTime = DateTime.Now, Role = result };
158 | if (_options.ClusterEnvironment)
159 | {
160 | RedisHelper.Set(key, data); //加入redis缓存
161 | RedisHelper.Publish(key, data.ToJson()); //发布事件
162 | }
163 | else
164 | {
165 | _cache.Remove(key);
166 | }
167 | }
168 |
169 | ///
170 | /// 更新呢客户端路由白名单缓存
171 | ///
172 | ///
173 | ///
174 | ///
175 | [HttpPost]
176 | [Route("ClientReRouteWhiteList")]
177 | public async Task UpdateClientReRouteWhiteListCache(string clientid, string path)
178 | {
179 | var region = CzarCacheRegion.ClientReRouteWhiteListRegion;
180 | var key = clientid + path;
181 | key = CzarOcelotHelper.GetKey(_options.RedisOcelotKeyPrefix, region, key);
182 | var result = await _clientRateLimitRepository.CheckClientReRouteWhiteListAsync(clientid, path);
183 | var data = new ClientRoleModel() { CacheTime = DateTime.Now, Role = result };
184 | if (_options.ClusterEnvironment)
185 | {
186 | RedisHelper.Set(key, data); //加入redis缓存
187 | RedisHelper.Publish(key, data.ToJson()); //发布事件
188 | }
189 | else
190 | {
191 | _cache.Remove(key);
192 | }
193 | }
194 |
195 | [HttpPost]
196 | [Route("Rpc")]
197 | public async Task UpdateRpcCache(string UpUrl)
198 | {
199 | var region = CzarCacheRegion.RemoteInvokeMessageRegion;
200 | var key = UpUrl;
201 | key = CzarOcelotHelper.GetKey(_options.RedisOcelotKeyPrefix, region, key);
202 | var result = await _rpcRepository.GetRemoteMethodAsync(UpUrl);
203 | if (_options.ClusterEnvironment)
204 | {
205 | RedisHelper.Set(key, result); //加入redis缓存
206 | RedisHelper.Publish(key, result.ToJson()); //发布事件
207 | }
208 | else
209 | {
210 | _cache.Remove(key);
211 | }
212 | }
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Cache/CzarMemoryCache.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Configuration;
2 | using Czar.Gateway.RateLimit;
3 | using Microsoft.Extensions.Caching.Memory;
4 | using Ocelot.Cache;
5 | using System;
6 |
7 | namespace Czar.Gateway.Cache
8 | {
9 | ///
10 | /// 金焰的世界
11 | /// 2019-03-03
12 | /// 使用二级缓存解决集群环境问题
13 | ///
14 | public class CzarMemoryCache : IOcelotCache
15 | {
16 | private readonly CzarOcelotConfiguration _options;
17 | private readonly IMemoryCache _cache;
18 | public CzarMemoryCache(CzarOcelotConfiguration options,IMemoryCache cache)
19 | {
20 | _options = options;
21 | _cache = cache;
22 | }
23 | public void Add(string key, T value, TimeSpan ttl, string region)
24 | {
25 | key = CzarOcelotHelper.GetKey(_options.RedisOcelotKeyPrefix,region, key);
26 | if (_options.ClusterEnvironment)
27 | {
28 | var msg = value.ToJson();
29 | if (typeof(T) == typeof(CachedResponse))
30 | {//带过期时间的缓存
31 | _cache.Set(key, value, ttl); //添加本地缓存
32 | RedisHelper.Set(key, msg,(int)ttl.TotalSeconds); //加入redis缓存
33 | RedisHelper.Publish(key, msg); //发布
34 | }
35 | else if (typeof(T) == typeof(CzarClientRateLimitCounter?))
36 | {//限流缓存,直接使用redis
37 | RedisHelper.Set(key, value, (int)ttl.TotalSeconds);
38 | }
39 | else
40 | {//正常缓存,发布
41 | _cache.Set(key, value, ttl); //添加本地缓存
42 | RedisHelper.Set(key, msg); //加入redis缓存
43 | RedisHelper.Publish(key, msg); //发布
44 | }
45 | }
46 | else
47 | {
48 | _cache.Set(key, value, ttl); //添加本地缓存
49 | }
50 | }
51 |
52 | public void AddAndDelete(string key, T value, TimeSpan ttl, string region)
53 | {
54 | Add(key, value, ttl, region);
55 | }
56 |
57 | public void ClearRegion(string region)
58 | {
59 | if (_options.ClusterEnvironment)
60 | {
61 | var keys = RedisHelper.Keys(region + "*");
62 | RedisHelper.Del(keys);
63 | foreach (var key in keys)
64 | {
65 | RedisHelper.Publish(key, ""); //发布key值为空,处理时删除即可。
66 | }
67 | }
68 | else
69 | {
70 | _cache.Remove(region);
71 | }
72 | }
73 |
74 | public T Get(string key, string region)
75 | {
76 | key = CzarOcelotHelper.GetKey(_options.RedisOcelotKeyPrefix, region, key);
77 | if(region== CzarCacheRegion.CzarClientRateLimitCounterRegion&& _options.ClusterEnvironment)
78 | {//限流且开启了集群支持,默认从redis取
79 | return RedisHelper.Get(key);
80 | }
81 | var result = _cache.Get(key);
82 | if (result == null&& _options.ClusterEnvironment)
83 | {
84 | result= RedisHelper.Get(key);
85 | if (result != null)
86 | {
87 | if (typeof(T) == typeof(CachedResponse))
88 | {//查看redis过期时间
89 | var second = RedisHelper.Ttl(key);
90 | if (second > 0)
91 | {
92 | _cache.Set(key, result, TimeSpan.FromSeconds(second));
93 | }
94 | }
95 | else
96 | {
97 | _cache.Set(key, result, TimeSpan.FromSeconds(_options.CzarCacheTime));
98 | }
99 | }
100 | }
101 | return result;
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Cache/RedisInternalConfigurationRepository.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Configuration;
2 | using Ocelot.Cache;
3 | using Ocelot.Configuration;
4 | using Ocelot.Configuration.Creator;
5 | using Ocelot.Configuration.Repository;
6 | using Ocelot.Responses;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Text;
10 |
11 | namespace Czar.Gateway.Cache
12 | {
13 | ///
14 | /// 金焰的世界
15 | /// 2018-11-14
16 | /// 使用redis存储内部配置信息
17 | ///
18 | public class RedisInternalConfigurationRepository : IInternalConfigurationRepository
19 | {
20 | private readonly CzarOcelotConfiguration _options;
21 | private IFileConfigurationRepository _fileConfigurationRepository;
22 | private IInternalConfigurationCreator _internalConfigurationCreator;
23 | private readonly IOcelotCache _ocelotCache;
24 | public RedisInternalConfigurationRepository(CzarOcelotConfiguration options,IFileConfigurationRepository fileConfigurationRepository, IInternalConfigurationCreator internalConfigurationCreator, IOcelotCache ocelotCache)
25 | {
26 | _fileConfigurationRepository = fileConfigurationRepository;
27 | _internalConfigurationCreator = internalConfigurationCreator;
28 | _options = options;
29 | _ocelotCache = ocelotCache;
30 | }
31 |
32 | ///
33 | /// 设置配置信息
34 | ///
35 | /// 配置信息
36 | ///
37 | public Response AddOrReplace(IInternalConfiguration internalConfiguration)
38 | {
39 | var key = CzarCacheRegion.InternalConfigurationRegion;
40 | _ocelotCache.Add(key, (InternalConfiguration)internalConfiguration, TimeSpan.FromSeconds(_options.CzarCacheTime), "");
41 | return new OkResponse();
42 | }
43 |
44 | ///
45 | /// 从缓存中获取配置信息
46 | ///
47 | ///
48 | public Response Get()
49 | {
50 | var key = CzarCacheRegion.InternalConfigurationRegion;
51 | var result = _ocelotCache.Get(key, "");
52 | if (result!=null)
53 | {
54 | return new OkResponse(result);
55 | }
56 | var fileconfig= _fileConfigurationRepository.Get().Result;
57 | var internalConfig= _internalConfigurationCreator.Create(fileconfig.Data).Result;
58 | AddOrReplace(internalConfig.Data);
59 | return new OkResponse(internalConfig.Data);
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Configuration/CzarCacheRegion.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Configuration
2 | {
3 | ///
4 | /// 缓存所属区域
5 | ///
6 | public class CzarCacheRegion
7 | {
8 | ///
9 | /// 授权
10 | ///
11 | public const string AuthenticationRegion = "CacheClientAuthentication";
12 |
13 | ///
14 | /// 路由配置
15 | ///
16 | public const string FileConfigurationRegion = "CacheFileConfiguration";
17 |
18 | ///
19 | /// 内部配置
20 | ///
21 | public const string InternalConfigurationRegion = "CacheInternalConfiguration";
22 |
23 | ///
24 | /// 客户端权限
25 | ///
26 | public const string ClientRoleModelRegion = "CacheClientRoleModel";
27 |
28 | ///
29 | /// 客户端路由白名单
30 | ///
31 | public const string ClientReRouteWhiteListRegion = "CacheClientReRouteWhiteList";
32 |
33 | ///
34 | /// 限流规则
35 | ///
36 | public const string RateLimitRuleModelRegion = "CacheRateLimitRuleModel";
37 |
38 | ///
39 | /// Rpc远程调用
40 | ///
41 | public const string RemoteInvokeMessageRegion = "CacheRemoteInvokeMessage";
42 |
43 | ///
44 | /// 客户端限流
45 | ///
46 | public const string CzarClientRateLimitCounterRegion = "CacheCzarClientRateLimitCounter";
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Configuration/CzarOcelotConfiguration.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Configuration
2 | {
3 | ///
4 | /// 金焰的世界
5 | /// 2018-11-11
6 | /// 自定义配置信息
7 | ///
8 | public class CzarOcelotConfiguration
9 | {
10 | ///
11 | /// 数据库连接字符串,使用不同数据库时自行修改,默认实现了SQLSERVER
12 | ///
13 | public string DbConnectionStrings { get; set; }
14 |
15 | ///
16 | /// 金焰的世界
17 | /// 2018-11-12
18 | /// 是否启用定时器,默认不启动
19 | ///
20 | public bool EnableTimer { get; set; } = false;
21 |
22 | ///
23 | /// 金焰的世界
24 | /// 2018-11.12
25 | /// 定时器周期,单位(毫秒),默认30分总自动更新一次
26 | ///
27 | public int TimerDelay { get; set; } = 30 * 60 * 1000;
28 |
29 | ///
30 | /// 金焰的世界
31 | /// 2018-11-14
32 | /// Redis连接字符串
33 | ///
34 | public string RedisConnectionString { get; set; }
35 |
36 | ///
37 | /// 金焰的世界
38 | /// 2019-03-03
39 | /// 配置哨兵或分区时使用
40 | ///
41 | public string[] RedisSentinelOrPartitionConStr { get; set; }
42 |
43 | ///
44 | /// 金焰的世界
45 | /// 2019-03-03
46 | /// Redis部署方式,默认使用普通方式
47 | ///
48 | public RedisStoreMode RedisStoreMode { get; set; } = RedisStoreMode.Normal;
49 |
50 | ///
51 | /// 金焰的计界
52 | /// 2019-03-03
53 | /// 做集群缓存同步时使用,会订阅所有正则匹配的事件
54 | ///
55 | public string RedisOcelotKeyPrefix { get; set; } = "CzarOcelot";
56 |
57 | ///
58 | /// 金焰的世界
59 | /// 2019-03-03
60 | /// 是否启用集群环境,如果非集群环境直接本地缓存+数据库即可
61 | ///
62 | public bool ClusterEnvironment { get; set; } = false;
63 |
64 | ///
65 | /// 金焰的世界
66 | /// 2018-11-15
67 | /// 是否启用客户端授权,默认不开启
68 | ///
69 | public bool ClientAuthorization { get; set; } = false;
70 |
71 | ///
72 | /// 金焰的世界
73 | /// 2018-11-15
74 | /// 服务器缓存时间,默认30分钟
75 | ///
76 | public int CzarCacheTime { get; set; } = 1800;
77 | ///
78 | /// 金焰的世界
79 | /// 2018-11-15
80 | /// 客户端标识,默认 client_id
81 | ///
82 | public string ClientKey { get; set; } = "client_id";
83 |
84 | ///
85 | /// 金焰的世界
86 | /// 2018-11-18
87 | /// 是否开启自定义限流,默认不开启
88 | ///
89 | public bool ClientRateLimit { get; set; } = false;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Configuration/DbConfigurationPoller.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Hosting;
2 | using Ocelot.Configuration.Creator;
3 | using Ocelot.Configuration.Repository;
4 | using Ocelot.Logging;
5 | using System;
6 | using System.Linq;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace Czar.Gateway.Configuration
11 | {
12 | ///
13 | /// 金焰的世界
14 | /// 2018-11-12
15 | /// 数据库配置信息更新策略
16 | ///
17 | public class DbConfigurationPoller : IHostedService, IDisposable
18 | {
19 | private readonly IOcelotLogger _logger;
20 | private readonly IFileConfigurationRepository _repo;
21 | private readonly CzarOcelotConfiguration _option;
22 | private Timer _timer;
23 | private bool _polling;
24 | private readonly IInternalConfigurationRepository _internalConfigRepo;
25 | private readonly IInternalConfigurationCreator _internalConfigCreator;
26 | public DbConfigurationPoller(IOcelotLoggerFactory factory,
27 | IFileConfigurationRepository repo,
28 | IInternalConfigurationRepository internalConfigRepo,
29 | IInternalConfigurationCreator internalConfigCreator,
30 | CzarOcelotConfiguration option)
31 | {
32 | _internalConfigRepo = internalConfigRepo;
33 | _internalConfigCreator = internalConfigCreator;
34 | _logger = factory.CreateLogger();
35 | _repo = repo;
36 | _option = option;
37 | }
38 |
39 | public void Dispose()
40 | {
41 | _timer?.Dispose();
42 | }
43 |
44 | public Task StartAsync(CancellationToken cancellationToken)
45 | {
46 | if (_option.EnableTimer)
47 | {//判断是否启用自动更新
48 | _logger.LogInformation($"{nameof(DbConfigurationPoller)} is starting.");
49 | _timer = new Timer(async x =>
50 | {
51 | if (_polling)
52 | {
53 | return;
54 | }
55 | _polling = true;
56 | await Poll();
57 | _polling = false;
58 | }, null, _option.TimerDelay, _option.TimerDelay);
59 | }
60 | return Task.CompletedTask;
61 | }
62 |
63 | public Task StopAsync(CancellationToken cancellationToken)
64 | {
65 | if (_option.EnableTimer)
66 | {//判断是否启用自动更新
67 | _logger.LogInformation($"{nameof(DbConfigurationPoller)} is stopping.");
68 | _timer?.Change(Timeout.Infinite, 0);
69 | }
70 | return Task.CompletedTask;
71 | }
72 |
73 | private async Task Poll()
74 | {
75 | _logger.LogInformation("Started polling");
76 |
77 | var fileConfig = await _repo.Get();
78 |
79 | if (fileConfig.IsError)
80 | {
81 | _logger.LogWarning($"error geting file config, errors are {string.Join(",", fileConfig.Errors.Select(x => x.Message))}");
82 | return;
83 | }
84 | else
85 | {
86 | var config = await _internalConfigCreator.Create(fileConfig.Data);
87 | if (!config.IsError)
88 | {
89 | _internalConfigRepo.AddOrReplace(config.Data);
90 | }
91 | }
92 | _logger.LogInformation("Finished polling");
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Configuration/ErrorResult.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Configuration
2 | {
3 | ///
4 | /// 金焰的世界
5 | /// 2018-11-15
6 | /// 统一的异常显示结构
7 | ///
8 | public class ErrorResult
9 | {
10 | ///
11 | /// 错误代码
12 | ///
13 | public int errcode { get; set; }
14 |
15 | ///
16 | /// 错误描述
17 | ///
18 | public string errmsg { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Configuration/Model/BaseResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Czar.Gateway.Configuration
6 | {
7 | ///
8 | /// 金焰的世界
9 | /// 2018-12-10
10 | /// 信息输出基类
11 | ///
12 | public class BaseResult
13 | {
14 | public BaseResult(int _errcode,string _errmsg)
15 | {
16 | errcode = _errcode;
17 | errmsg = _errmsg;
18 | }
19 | public BaseResult()
20 | {
21 |
22 | }
23 | ///
24 | /// 错误类型标识
25 | ///
26 | public int errcode { get; set; }
27 |
28 | ///
29 | /// 错误类型说明
30 | ///
31 | public string errmsg { get; set; }
32 | }
33 |
34 | ///
35 | /// 金焰的世界
36 | /// 2018-12-10
37 | /// 默认成功结果
38 | ///
39 | public class SuccessResult : BaseResult
40 | {
41 | public SuccessResult() : base(0, "成功")
42 | {
43 |
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Configuration/Model/ClientRoleModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Czar.Gateway.Configuration
4 | {
5 | ///
6 | /// 金焰的世界
7 | /// 2018-11-15
8 | /// 是否存在的实体,缓存使用
9 | ///
10 | public class ClientRoleModel
11 | {
12 | ///
13 | /// 缓存时间
14 | ///
15 | public DateTime CacheTime { get; set; }
16 | ///
17 | /// 是否有访问权限
18 | ///
19 | public bool Role { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Configuration/RedisStoreMode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Czar.Gateway.Configuration
6 | {
7 | ///
8 | /// 金焰的世界
9 | /// 2019-03-03
10 | /// Redis部署方式
11 | ///
12 | public enum RedisStoreMode
13 | {
14 | ///
15 | /// 普通方式
16 | ///
17 | Normal = 1,
18 | ///
19 | /// 官方集群方式
20 | ///
21 | Cluster=2,
22 | ///
23 | /// 哨兵方式
24 | ///
25 | Sentinel=3,
26 | ///
27 | /// 分区方式
28 | ///
29 | Partition=4
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Czar.Gateway.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.2
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Errors/IdentityServer4Error.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Errors;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Czar.Gateway.Errors
7 | {
8 | public class IdentityServer4Error:Error
9 | {
10 | public IdentityServer4Error(string message) : base(message, OcelotErrorCode.UnableToCreateAuthenticationHandlerError)
11 | {
12 |
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Errors/InternalServerError.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Errors;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Czar.Gateway.Errors
7 | {
8 | ///
9 | /// 金焰的世界
10 | /// 2018-12-10
11 | /// 服务不可用错误
12 | ///
13 | public class InternalServerError:Error
14 | {
15 | public InternalServerError(string message) : base(message, OcelotErrorCode.UnableToCompleteRequestError)
16 | {
17 |
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Errors/RateLimitOptionsError.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Errors;
2 |
3 | namespace Czar.Gateway.Errors
4 | {
5 | ///
6 | /// 金焰的世界
7 | /// 2018-11-18
8 | /// 限流错误信息
9 | ///
10 | public class RateLimitOptionsError:Error
11 | {
12 | public RateLimitOptionsError(string message) : base(message, OcelotErrorCode.RateLimitOptionsError)
13 | {
14 |
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Extensions/Ext.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Converters;
3 | using Newtonsoft.Json.Linq;
4 | using System.Collections.Generic;
5 | using System.Data;
6 |
7 | namespace Czar.Gateway
8 | {
9 | ///
10 | /// 自定义扩展实现序列化
11 | ///
12 | public static partial class Ext
13 | {
14 | public static object ToJson(this string Json)
15 | {
16 | return Json == null ? null : JsonConvert.DeserializeObject(Json);
17 | }
18 | public static string ToJson(this object obj)
19 | {
20 | var timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
21 | //var timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd" };
22 | return JsonConvert.SerializeObject(obj, timeConverter);
23 | }
24 | public static string ToJson(this object obj, string datetimeformats)
25 | {
26 | var timeConverter = new IsoDateTimeConverter { DateTimeFormat = datetimeformats };
27 | return JsonConvert.SerializeObject(obj, timeConverter);
28 | }
29 | public static T ToObject(this string Json)
30 | {
31 | return Json == null ? default(T) : JsonConvert.DeserializeObject(Json);
32 | }
33 | public static List ToList(this string Json)
34 | {
35 | return Json == null ? null : JsonConvert.DeserializeObject>(Json);
36 | }
37 | public static DataTable ToTable(this string Json)
38 | {
39 | return Json == null ? null : JsonConvert.DeserializeObject(Json);
40 | }
41 | public static JObject ToJObject(this string Json)
42 | {
43 | return Json == null ? JObject.Parse("{}") : JObject.Parse(Json.Replace(" ", ""));
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Helper/CzarOcelotHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Security.Cryptography;
4 | using System.Text;
5 |
6 | namespace Czar.Gateway
7 | {
8 | public static class CzarOcelotHelper
9 | {
10 | ///
11 | /// 获取加密后缓存的KEY
12 | ///
13 | /// 缓存前缀,防止重复
14 | /// 客户端ID
15 | /// 限流策略,如 1s 2m 3h 4d
16 | /// 限流地址,可使用通配符
17 | ///
18 | public static string ComputeCounterKey(string CounterPrefix, string ClientId, string Period, string Path)
19 | {
20 | var key = $"{CounterPrefix}_{ClientId}_{Period}_{Path}";
21 | var idBytes = Encoding.UTF8.GetBytes(key);
22 | byte[] hashBytes;
23 | using (var algorithm = SHA1.Create())
24 | {
25 | hashBytes = algorithm.ComputeHash(idBytes);
26 | }
27 | return BitConverter.ToString(hashBytes).Replace("-", string.Empty);
28 | }
29 |
30 | ///
31 | /// 金焰的世界
32 | /// 2018-11-19
33 | /// 根据限流标识,获取周期秒数
34 | ///
35 | /// 标识
36 | ///
37 | public static int ConvertToSecond(string timeSpan)
38 | {
39 | var l = timeSpan.Length - 1;
40 | var value = timeSpan.Substring(0, l);
41 | var type = timeSpan.Substring(l, 1);
42 |
43 | switch (type)
44 | {
45 | case "d":
46 | return Convert.ToInt32(double.Parse(value) * 24 * 3600);
47 | case "h":
48 | return Convert.ToInt32(double.Parse(value) * 3600);
49 | case "m":
50 | return Convert.ToInt32(double.Parse(value) * 60);
51 | case "s":
52 | return Convert.ToInt32(value);
53 | default:
54 | throw new FormatException($"{timeSpan} can't be converted to TimeSpan, unknown type {type}");
55 | }
56 | }
57 |
58 | ///
59 | /// 获取格式化后的key
60 | ///
61 | /// 系统标识
62 | /// 分类标识
63 | /// key
64 | ///
65 | public static string GetKey(string prefix,string region, string key)
66 | {
67 | return prefix + "-" + region + "-" + key;
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Middleware/CzarOcelotMiddlewareExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Ocelot.Configuration;
3 | using Ocelot.Logging;
4 | using Ocelot.Middleware;
5 | using Ocelot.Middleware.Pipeline;
6 | using System;
7 | using System.Threading.Tasks;
8 | using System.Linq;
9 | using Ocelot.Configuration.Creator;
10 | using Microsoft.Extensions.DependencyInjection;
11 | using Ocelot.Configuration.Repository;
12 | using Ocelot.Responses;
13 | using Microsoft.AspNetCore.Hosting;
14 | using System.Diagnostics;
15 | using Czar.Gateway.Configuration;
16 | using Microsoft.Extensions.Caching.Memory;
17 |
18 | namespace Czar.Gateway.Middleware
19 | {
20 | ///
21 | /// 金焰的世界
22 | /// 2018-11-10
23 | /// 基于Ocelot扩展网关中间件,主要是重写了CreateConfiguration方法,其他内容保持与原有的中间件内容不变。
24 | ///
25 | public static class CzarOcelotMiddlewareExtensions
26 | {
27 |
28 | public static async Task UseCzarOcelot(this IApplicationBuilder builder)
29 | {
30 | await builder.UseCzarOcelot(new OcelotPipelineConfiguration());
31 | return builder;
32 | }
33 |
34 | public static async Task UseCzarOcelot(this IApplicationBuilder builder, Action pipelineConfiguration)
35 | {
36 | var config = new OcelotPipelineConfiguration();
37 | pipelineConfiguration?.Invoke(config);
38 | return await builder.UseCzarOcelot(config);
39 | }
40 |
41 | public static async Task UseCzarOcelot(this IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
42 | {
43 | //重写创建配置方法
44 | var configuration = await CreateConfiguration(builder);
45 |
46 | ConfigureDiagnosticListener(builder);
47 | CacheChangeListener(builder);
48 | return CreateOcelotPipeline(builder, pipelineConfiguration);
49 | }
50 |
51 | ///
52 | /// 金焰的世界
53 | /// 2019-03-03
54 | /// 添加缓存数据变更订阅
55 | ///
56 | ///
57 | ///
58 | private static void CacheChangeListener(IApplicationBuilder builder)
59 | {
60 | var config= builder.ApplicationServices.GetService();
61 | var _cache= builder.ApplicationServices.GetService();
62 | if (config.ClusterEnvironment)
63 | {
64 | //订阅满足条件的所有事件
65 | RedisHelper.PSubscribe(new[] { config.RedisOcelotKeyPrefix + "*" }, message =>
66 | {
67 | var key = message.Channel;
68 | _cache.Remove(key); //直接移除,如果有请求从redis里取
69 | });
70 | }
71 | }
72 |
73 | private static IApplicationBuilder CreateOcelotPipeline(IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
74 | {
75 | var pipelineBuilder = new OcelotPipelineBuilder(builder.ApplicationServices);
76 |
77 | //pipelineBuilder.BuildOcelotPipeline(pipelineConfiguration);
78 | //使用自定义管道扩展 2018-11-15 金焰的世界
79 | pipelineBuilder.BuildCzarOcelotPipeline(pipelineConfiguration);
80 |
81 | var firstDelegate = pipelineBuilder.Build();
82 |
83 | /*
84 | inject first delegate into first piece of asp.net middleware..maybe not like this
85 | then because we are updating the http context in ocelot it comes out correct for
86 | rest of asp.net..
87 | */
88 |
89 | builder.Properties["analysis.NextMiddlewareName"] = "TransitionToOcelotMiddleware";
90 |
91 | builder.Use(async (context, task) =>
92 | {
93 | var downstreamContext = new DownstreamContext(context);
94 | await firstDelegate.Invoke(downstreamContext);
95 | });
96 |
97 | return builder;
98 | }
99 |
100 | private static async Task CreateConfiguration(IApplicationBuilder builder)
101 | {
102 | //提取文件配置信息
103 | var fileConfig = await builder.ApplicationServices.GetService().Get();
104 | var internalConfigCreator = builder.ApplicationServices.GetService();
105 | var internalConfig = await internalConfigCreator.Create(fileConfig.Data);
106 | //如果配置文件错误直接抛出异常
107 | if (internalConfig.IsError)
108 | {
109 | ThrowToStopOcelotStarting(internalConfig);
110 | }
111 | //配置信息缓存,这块需要注意实现方式,因为后期我们需要改造下满足分布式架构,这篇不做讲解
112 | var internalConfigRepo = builder.ApplicationServices.GetService();
113 | internalConfigRepo.AddOrReplace(internalConfig.Data);
114 | //获取中间件配置委托
115 | var configurations = builder.ApplicationServices.GetServices();
116 | foreach (var configuration in configurations)
117 | {
118 | await configuration(builder);
119 | }
120 | return GetOcelotConfigAndReturn(internalConfigRepo);
121 | }
122 |
123 | private static bool IsError(Response response)
124 | {
125 | return response == null || response.IsError;
126 | }
127 |
128 | private static IInternalConfiguration GetOcelotConfigAndReturn(IInternalConfigurationRepository provider)
129 | {
130 | var ocelotConfiguration = provider.Get();
131 |
132 | if (ocelotConfiguration?.Data == null || ocelotConfiguration.IsError)
133 | {
134 | ThrowToStopOcelotStarting(ocelotConfiguration);
135 | }
136 |
137 | return ocelotConfiguration.Data;
138 | }
139 |
140 | private static void ThrowToStopOcelotStarting(Response config)
141 | {
142 | throw new Exception($"Unable to start Ocelot, errors are: {string.Join(",", config.Errors.Select(x => x.ToString()))}");
143 | }
144 |
145 | private static void ConfigureDiagnosticListener(IApplicationBuilder builder)
146 | {
147 | var env = builder.ApplicationServices.GetService();
148 | var listener = builder.ApplicationServices.GetService();
149 | var diagnosticListener = builder.ApplicationServices.GetService();
150 | diagnosticListener.SubscribeWithAdapter(listener);
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Middleware/OcelotPipelineExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Czar.Gateway.Authentication.Middleware;
4 | using Czar.Gateway.RateLimit.Middleware;
5 | using Czar.Gateway.Requester.Middleware;
6 | using Czar.Gateway.Responder.Middleware;
7 | using Czar.Gateway.Rpc.Middleware;
8 | using Ocelot.Authentication.Middleware;
9 | using Ocelot.Authorisation.Middleware;
10 | using Ocelot.Cache.Middleware;
11 | using Ocelot.DownstreamRouteFinder.Middleware;
12 | using Ocelot.DownstreamUrlCreator.Middleware;
13 | using Ocelot.Errors.Middleware;
14 | using Ocelot.Headers.Middleware;
15 | using Ocelot.LoadBalancer.Middleware;
16 | using Ocelot.Middleware;
17 | using Ocelot.Middleware.Pipeline;
18 | using Ocelot.RateLimit.Middleware;
19 | using Ocelot.Request.Middleware;
20 | using Ocelot.Requester.Middleware;
21 | using Ocelot.RequestId.Middleware;
22 | using Ocelot.Responder.Middleware;
23 | using Ocelot.WebSockets.Middleware;
24 |
25 | namespace Czar.Gateway.Middleware
26 | {
27 | ///
28 | /// 金焰的世界
29 | /// 2018-11-15
30 | /// 网关管道扩展
31 | ///
32 | public static class OcelotPipelineExtensions
33 | {
34 | public static OcelotRequestDelegate BuildCzarOcelotPipeline(this IOcelotPipelineBuilder builder,
35 | OcelotPipelineConfiguration pipelineConfiguration)
36 | {
37 |
38 | // 注册一个全局异常
39 | builder.UseExceptionHandlerMiddleware();
40 |
41 | // 如果请求是websocket使用单独的管道
42 | builder.MapWhen(context => context.HttpContext.WebSockets.IsWebSocketRequest,
43 | app =>
44 | {
45 | app.UseDownstreamRouteFinderMiddleware();
46 | app.UseDownstreamRequestInitialiser();
47 | app.UseLoadBalancingMiddleware();
48 | app.UseDownstreamUrlCreatorMiddleware();
49 | app.UseWebSocketsProxyMiddleware();
50 | });
51 |
52 | // 添加自定义的错误管道
53 | builder.UseIfNotNull(pipelineConfiguration.PreErrorResponderMiddleware);
54 |
55 | //使用自定义的输出管道
56 | builder.UseCzarResponderMiddleware();
57 |
58 | // 下游路由匹配管道
59 | builder.UseDownstreamRouteFinderMiddleware();
60 |
61 | //增加自定义扩展管道
62 | if (pipelineConfiguration.MapWhenOcelotPipeline != null)
63 | {
64 | foreach (var pipeline in pipelineConfiguration.MapWhenOcelotPipeline)
65 | {
66 | builder.MapWhen(pipeline);
67 | }
68 | }
69 |
70 | // 使用Http头部转换管道
71 | builder.UseHttpHeadersTransformationMiddleware();
72 |
73 | // 初始化下游请求管道
74 | builder.UseDownstreamRequestInitialiser();
75 |
76 | // 使用自定义限流管道
77 | builder.UseRateLimiting();
78 |
79 | //使用请求ID生成管道
80 | builder.UseRequestIdMiddleware();
81 |
82 | //使用自定义授权前管道
83 | builder.UseIfNotNull(pipelineConfiguration.PreAuthenticationMiddleware);
84 |
85 | //根据请求判断是否启用授权来使用管道
86 | if (pipelineConfiguration.AuthenticationMiddleware == null)
87 | {
88 | builder.UseAuthenticationMiddleware();
89 | }
90 | else
91 | {
92 | builder.Use(pipelineConfiguration.AuthenticationMiddleware);
93 | }
94 |
95 | //添加自定义限流中间件 2018-11-18 金焰的世界
96 | builder.UseCzarClientRateLimitMiddleware();
97 |
98 | //添加自定义授权中间件 2018-11-15 金焰的世界
99 | builder.UseAhphAuthenticationMiddleware();
100 |
101 | //启用自定义的认证之前中间件
102 | builder.UseIfNotNull(pipelineConfiguration.PreAuthorisationMiddleware);
103 |
104 | //是否使用自定义的认证中间件
105 | if (pipelineConfiguration.AuthorisationMiddleware == null)
106 | {
107 | builder.UseAuthorisationMiddleware();
108 | }
109 | else
110 | {
111 | builder.Use(pipelineConfiguration.AuthorisationMiddleware);
112 | }
113 |
114 | // 使用自定义的参数构建中间件
115 | builder.UseIfNotNull(pipelineConfiguration.PreQueryStringBuilderMiddleware);
116 |
117 | // 使用负载均衡中间件
118 | builder.UseLoadBalancingMiddleware();
119 |
120 | // 使用下游地址创建中间件
121 | builder.UseDownstreamUrlCreatorMiddleware();
122 |
123 | // 使用缓存中间件
124 | builder.UseOutputCacheMiddleware();
125 |
126 | //判断下游的是否启用rpc通信,切换到RPC处理
127 | builder.MapWhen(context => context.DownstreamReRoute.DownstreamScheme.Equals("rpc", StringComparison.OrdinalIgnoreCase), app =>
128 | {
129 | app.UseCzarRpcMiddleware();
130 | });
131 |
132 | //使用下游请求中间件
133 | builder.UseCzaHttpRequesterMiddleware();
134 |
135 | return builder.Build();
136 | }
137 |
138 | private static void UseIfNotNull(this IOcelotPipelineBuilder builder,
139 | Func, Task> middleware)
140 | {
141 | if (middleware != null)
142 | {
143 | builder.Use(middleware);
144 | }
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Middleware/ServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Authentication;
2 | using Czar.Gateway.Cache;
3 | using Czar.Gateway.Configuration;
4 | using Czar.Gateway.Stores.MySql;
5 | using Czar.Gateway.Stores.SqlServer;
6 | using Czar.Gateway.RateLimit;
7 | using Czar.Gateway.Responder;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using Ocelot.Cache;
10 | using Ocelot.Configuration.File;
11 | using Ocelot.Configuration.Repository;
12 | using Ocelot.DependencyInjection;
13 | using Ocelot.Responder;
14 | using System;
15 | using Czar.Gateway.Rpc;
16 | using Czar.Rpc.Message;
17 | using Ocelot.Configuration;
18 | using Czar.Rpc.DotNetty.Extensions;
19 | using Microsoft.Extensions.Configuration;
20 | using System.Linq;
21 |
22 | namespace Czar.Gateway.Middleware
23 | {
24 | ///
25 | /// 金焰的世界
26 | /// 2018-11-12
27 | /// 扩展Ocelot实现的自定义的注入
28 | ///
29 | public static class ServiceCollectionExtensions
30 | {
31 | ///
32 | /// 添加默认的注入方式,所有需要传入的参数都是用默认值
33 | ///
34 | ///
35 | ///
36 | public static IOcelotBuilder AddCzarOcelot(this IServiceCollection builder, Action option)
37 | {
38 | var options = new CzarOcelotConfiguration();
39 | builder.AddSingleton(options);
40 | option?.Invoke(options);
41 |
42 | //配置文件仓储注入
43 | builder.AddSingleton();
44 | builder.AddSingleton();
45 | builder.AddSingleton();
46 |
47 | //注册后端服务
48 | builder.AddHostedService();
49 | builder.AddMemoryCache(); //添加本地缓存
50 | #region 启动Redis缓存,并支持普通模式 官方集群模式 哨兵模式 分区模式
51 | if (options.ClusterEnvironment)
52 | {
53 | //默认使用普通模式
54 | var csredis = new CSRedis.CSRedisClient(options.RedisConnectionString);
55 | switch (options.RedisStoreMode)
56 | {
57 | case RedisStoreMode.Partition:
58 | var NodesIndex = options.RedisSentinelOrPartitionConStr;
59 | Func nodeRule = null;
60 | csredis = new CSRedis.CSRedisClient(nodeRule, options.RedisSentinelOrPartitionConStr);
61 | break;
62 | case RedisStoreMode.Sentinel:
63 | csredis = new CSRedis.CSRedisClient(options.RedisConnectionString, options.RedisSentinelOrPartitionConStr);
64 | break;
65 | }
66 | //初始化 RedisHelper
67 | RedisHelper.Initialization(csredis);
68 | }
69 | #endregion
70 | builder.AddSingleton, CzarMemoryCache>();
71 | builder.AddSingleton, CzarMemoryCache>();
72 | builder.AddSingleton, CzarMemoryCache>();
73 | builder.AddSingleton();
74 | builder.AddSingleton, CzarMemoryCache>();
75 | builder.AddSingleton, CzarMemoryCache>();
76 | builder.AddSingleton, CzarMemoryCache>();
77 | builder.AddSingleton, CzarMemoryCache>();
78 | //注入授权
79 | builder.AddSingleton();
80 | //注入限流实现
81 | builder.AddSingleton();
82 |
83 | //重写错误状态码
84 | builder.AddSingleton();
85 |
86 | //http输出转换类
87 | builder.AddSingleton();
88 |
89 | var service = builder.First(x => x.ServiceType == typeof(IConfiguration));
90 | var configuration = (IConfiguration)service.ImplementationInstance;
91 | //Rpc应用
92 | builder.AddSingleton();
93 | builder.AddSingleton();
94 | builder.AddLibuvTcpClient(configuration);
95 |
96 | return new OcelotBuilder(builder, configuration);
97 | }
98 |
99 | ///
100 | /// 扩展使用Mysql存储。
101 | ///
102 | ///
103 | ///
104 | public static IOcelotBuilder UseMySql(this IOcelotBuilder builder)
105 | {
106 | builder.Services.AddSingleton();
107 | builder.Services.AddSingleton();
108 | builder.Services.AddSingleton();
109 | builder.Services.AddSingleton();
110 | return builder;
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarAuthGroup.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.ComponentModel.DataAnnotations.Schema;
7 |
8 | public partial class CzarAuthGroup
9 | {
10 | [Key]
11 | public int GroupId { get; set; }
12 |
13 | [Required]
14 | [StringLength(100)]
15 | public string GroupName { get; set; }
16 |
17 | [StringLength(500)]
18 | public string GroupDetail { get; set; }
19 |
20 | public int InfoStatus { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarClientGroup.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.ComponentModel.DataAnnotations.Schema;
7 |
8 | public partial class CzarClientGroup
9 | {
10 | [Key]
11 | public int ClientGroupId { get; set; }
12 |
13 | public int? Id { get; set; }
14 |
15 | public int? GroupId { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarClientLimitGroup.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.ComponentModel.DataAnnotations.Schema;
7 |
8 | public partial class CzarClientLimitGroup
9 | {
10 | [Key]
11 | public int ClientLimitGroupId { get; set; }
12 |
13 | public int? Id { get; set; }
14 |
15 | public int? LimitGroupId { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarClientReRouteWhiteList.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.ComponentModel.DataAnnotations.Schema;
7 | public partial class CzarClientReRouteWhiteList
8 | {
9 | [Key]
10 | public int WhiteListId { get; set; }
11 |
12 | public int? ReRouteId { get; set; }
13 |
14 | public int? Id { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarClients.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.ComponentModel.DataAnnotations.Schema;
7 |
8 | public partial class CzarClients
9 | {
10 | [Key]
11 | public int Id { get; set; }
12 |
13 | public int AbsoluteRefreshTokenLifetime { get; set; }
14 |
15 | public int AccessTokenLifetime { get; set; }
16 |
17 | public int AccessTokenType { get; set; }
18 |
19 | public bool AllowAccessTokensViaBrowser { get; set; }
20 |
21 | public bool AllowOfflineAccess { get; set; }
22 |
23 | public bool AllowPlainTextPkce { get; set; }
24 |
25 | public bool AllowRememberConsent { get; set; }
26 |
27 | public bool AlwaysIncludeUserClaimsInIdToken { get; set; }
28 |
29 | public bool AlwaysSendClientClaims { get; set; }
30 |
31 | public int AuthorizationCodeLifetime { get; set; }
32 |
33 | public bool? BackChannelLogoutSessionRequired { get; set; }
34 |
35 | [StringLength(500)]
36 | public string BackChannelLogoutUri { get; set; }
37 |
38 | [Required]
39 | [StringLength(50)]
40 | public string ClientClaimsPrefix { get; set; }
41 |
42 | [Required]
43 | [StringLength(50)]
44 | public string ClientId { get; set; }
45 |
46 | [Required]
47 | [StringLength(200)]
48 | public string ClientName { get; set; }
49 |
50 | [StringLength(100)]
51 | public string ClientUri { get; set; }
52 |
53 | public int? ConsentLifetime { get; set; }
54 |
55 | [StringLength(500)]
56 | public string Description { get; set; }
57 |
58 | public bool EnableLocalLogin { get; set; }
59 |
60 | public bool Enabled { get; set; }
61 |
62 | public bool FrontChannelLogoutSessionRequired { get; set; }
63 |
64 | [StringLength(100)]
65 | public string FrontChannelLogoutUri { get; set; }
66 |
67 | public int IdentityTokenLifetime { get; set; }
68 |
69 | public bool IncludeJwtId { get; set; }
70 |
71 | [StringLength(150)]
72 | public string LogoUri { get; set; }
73 |
74 | [StringLength(200)]
75 | public string PairWiseSubjectSalt { get; set; }
76 |
77 | [StringLength(50)]
78 | public string ProtocolType { get; set; }
79 |
80 | public int RefreshTokenExpiration { get; set; }
81 |
82 | public int RefreshTokenUsage { get; set; }
83 |
84 | public bool RequireClientSecret { get; set; }
85 |
86 | public bool RequireConsent { get; set; }
87 |
88 | public bool RequirePkce { get; set; }
89 |
90 | public int SlidingRefreshTokenLifetime { get; set; }
91 |
92 | public bool UpdateAccessTokenClaimsOnRefresh { get; set; }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarConfigReRoutes.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System.ComponentModel.DataAnnotations;
4 |
5 | public partial class CzarConfigReRoutes
6 | {
7 | [Key]
8 | public int CtgRouteId { get; set; }
9 |
10 | public int? AhphId { get; set; }
11 |
12 | public int? ReRouteId { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarGlobalConfiguration.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System.ComponentModel.DataAnnotations;
4 | public partial class CzarGlobalConfiguration
5 | {
6 | [Key]
7 | public int AhphId { get; set; }
8 |
9 | [Required]
10 | [StringLength(100)]
11 | public string GatewayName { get; set; }
12 |
13 | [StringLength(100)]
14 | public string RequestIdKey { get; set; }
15 |
16 | [StringLength(100)]
17 | public string BaseUrl { get; set; }
18 |
19 | [StringLength(50)]
20 | public string DownstreamScheme { get; set; }
21 |
22 | [StringLength(500)]
23 | public string ServiceDiscoveryProvider { get; set; }
24 |
25 | [StringLength(500)]
26 | public string LoadBalancerOptions { get; set; }
27 |
28 | [StringLength(500)]
29 | public string HttpHandlerOptions { get; set; }
30 |
31 | [StringLength(200)]
32 | public string QoSOptions { get; set; }
33 |
34 | public int IsDefault { get; set; }
35 |
36 | public int InfoStatus { get; set; }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarLimitGroup.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.ComponentModel.DataAnnotations.Schema;
7 | public partial class CzarLimitGroup
8 | {
9 | [Key]
10 | public int LimitGroupId { get; set; }
11 |
12 | [Required]
13 | [StringLength(100)]
14 | public string LimitGroupName { get; set; }
15 |
16 | [StringLength(500)]
17 | public string LimitGroupDetail { get; set; }
18 |
19 | public int InfoStatus { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarLimitGroupRule.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.ComponentModel.DataAnnotations.Schema;
7 | public partial class CzarLimitGroupRule
8 | {
9 | [Key]
10 | public int GroupRuleId { get; set; }
11 |
12 | public int? LimitGroupId { get; set; }
13 |
14 | public int? ReRouteLimitId { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarLimitRule.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.ComponentModel.DataAnnotations.Schema;
7 | public partial class CzarLimitRule
8 | {
9 | [Key]
10 | public int RuleId { get; set; }
11 |
12 | [Required]
13 | [StringLength(200)]
14 | public string LimitName { get; set; }
15 |
16 | [Required]
17 | [StringLength(50)]
18 | public string LimitPeriod { get; set; }
19 |
20 | public int LimitNum { get; set; }
21 |
22 | public int InfoStatus { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarReRoute.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System.ComponentModel.DataAnnotations;
4 |
5 | public partial class CzarReRoute
6 | {
7 | [Key]
8 | public int ReRouteId { get; set; }
9 |
10 | public int? ItemId { get; set; }
11 |
12 | [Required]
13 | [StringLength(150)]
14 | public string UpstreamPathTemplate { get; set; }
15 |
16 | [Required]
17 | [StringLength(50)]
18 | public string UpstreamHttpMethod { get; set; }
19 |
20 | [StringLength(100)]
21 | public string UpstreamHost { get; set; }
22 |
23 | [Required]
24 | [StringLength(50)]
25 | public string DownstreamScheme { get; set; }
26 |
27 | [Required]
28 | [StringLength(200)]
29 | public string DownstreamPathTemplate { get; set; }
30 |
31 | [StringLength(500)]
32 | public string DownstreamHostAndPorts { get; set; }
33 |
34 | [StringLength(300)]
35 | public string AuthenticationOptions { get; set; }
36 |
37 | [StringLength(100)]
38 | public string RequestIdKey { get; set; }
39 |
40 | [StringLength(200)]
41 | public string CacheOptions { get; set; }
42 |
43 | [StringLength(100)]
44 | public string ServiceName { get; set; }
45 |
46 | [StringLength(500)]
47 | public string LoadBalancerOptions { get; set; }
48 |
49 | [StringLength(200)]
50 | public string QoSOptions { get; set; }
51 |
52 | [StringLength(200)]
53 | public string DelegatingHandlers { get; set; }
54 |
55 | public int? Priority { get; set; }
56 |
57 | public int InfoStatus { get; set; }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarReRouteGroupAuth.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.ComponentModel.DataAnnotations.Schema;
7 |
8 | public partial class CzarReRouteGroupAuth
9 | {
10 | [Key]
11 | public int AuthId { get; set; }
12 |
13 | public int? GroupId { get; set; }
14 |
15 | public int? ReRouteId { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarReRouteLimitRule.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.DataAnnotations;
6 | using System.ComponentModel.DataAnnotations.Schema;
7 | public partial class CzarReRouteLimitRule
8 | {
9 | [Key]
10 | public int ReRouteLimitId { get; set; }
11 |
12 | public int? RuleId { get; set; }
13 |
14 | public int? ReRouteId { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarReRouteRpcConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Text;
5 |
6 | namespace Czar.Gateway.Model
7 | {
8 | public partial class CzarReRouteRpcConfig
9 | {
10 | [Key]
11 | public int RpcId { get; set; }
12 |
13 |
14 | public int ReRouteId { get; set; }
15 |
16 | [Required]
17 | [StringLength(100)]
18 | public string ServantName { get; set; }
19 |
20 | [Required]
21 | [StringLength(100)]
22 | public string FuncName { get; set; }
23 |
24 |
25 | public bool IsOneway { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Model/CzarReRoutesItem.cs:
--------------------------------------------------------------------------------
1 | namespace Czar.Gateway.Model
2 | {
3 | using System.ComponentModel.DataAnnotations;
4 | public partial class CzarReRoutesItem
5 | {
6 | [Key]
7 | public int ItemId { get; set; }
8 |
9 | [Required]
10 | [StringLength(100)]
11 | public string ItemName { get; set; }
12 |
13 | [StringLength(500)]
14 | public string ItemDetail { get; set; }
15 |
16 | public int? ItemParentId { get; set; }
17 |
18 | public int InfoStatus { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/RateLimit/CzarClientRateLimitCounter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace Czar.Gateway.RateLimit
5 | {
6 | ///
7 | /// 金焰的世界
8 | /// 2018-11-19
9 | /// 客户端限流计数器
10 | ///
11 | public struct CzarClientRateLimitCounter
12 | {
13 | [JsonConstructor]
14 | public CzarClientRateLimitCounter(DateTime timestamp, long totalRequests)
15 | {
16 | Timestamp = timestamp;
17 | TotalRequests = totalRequests;
18 | }
19 |
20 | ///
21 | /// 最后请求时间
22 | ///
23 | public DateTime Timestamp { get; private set; }
24 |
25 | ///
26 | /// 请求总数
27 | ///
28 | public long TotalRequests { get; private set; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/RateLimit/CzarClientRateLimitOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Czar.Gateway.RateLimit
6 | {
7 | ///
8 | /// 金焰的世界
9 | /// 2018-11.19
10 | /// 限流相关选项
11 | ///
12 | public class CzarClientRateLimitOptions
13 | {
14 | ///
15 | /// 限流请求的地址
16 | ///
17 | public string RateLimitPath { get; set; }
18 |
19 | ///
20 | /// 限制的访问次数
21 | ///
22 | public int Limit { get; set; }
23 |
24 | ///
25 | /// 限流的策略,如 1s 2m 3h 4d
26 | ///
27 | public string Period { get; set; }
28 |
29 | ///
30 | /// 客户端ID
31 | ///
32 | public string ClientId { get; set; }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/RateLimit/CzarClientRateLimitProcessor.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Cache;
2 | using Czar.Gateway.Configuration;
3 | using Ocelot.Cache;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Czar.Gateway.RateLimit
10 | {
11 | ///
12 | /// 金焰的世界
13 | /// 2018-11-19
14 | /// 实现客户端限流处理器
15 | ///
16 | public class CzarClientRateLimitProcessor : IClientRateLimitProcessor
17 | {
18 | private readonly CzarOcelotConfiguration _options;
19 | private readonly IOcelotCache _ocelotCache;
20 | private readonly IOcelotCache _rateLimitRuleCache;
21 | private readonly IOcelotCache _clientRateLimitCounter;
22 | private readonly IClientRateLimitRepository _clientRateLimitRepository;
23 | private static readonly object _processLocker = new object();
24 | public CzarClientRateLimitProcessor(CzarOcelotConfiguration options,IClientRateLimitRepository clientRateLimitRepository, IOcelotCache clientRateLimitCounter, IOcelotCache ocelotCache, IOcelotCache rateLimitRuleCache)
25 | {
26 | _options = options;
27 | _clientRateLimitRepository = clientRateLimitRepository;
28 | _clientRateLimitCounter = clientRateLimitCounter;
29 | _ocelotCache = ocelotCache;
30 | _rateLimitRuleCache = rateLimitRuleCache;
31 | }
32 |
33 | ///
34 | /// 校验客户端限流结果
35 | ///
36 | /// 客户端ID
37 | /// 请求地址
38 | ///
39 | public async Task CheckClientRateLimitResultAsync(string clientid, string path)
40 | {
41 | var result = false;
42 | var clientRule = new List();
43 | //1、校验路由是否有限流策略
44 | result = !await CheckReRouteRuleAsync(path);
45 | if (!result)
46 | {//2、校验客户端是否被限流了
47 | var limitResult = await CheckClientRateLimitAsync(clientid, path);
48 | result = !limitResult.RateLimit;
49 | clientRule = limitResult.rateLimitOptions;
50 | }
51 | if (!result)
52 | {//3、校验客户端是否启动白名单
53 | result = await CheckClientReRouteWhiteListAsync(clientid, path);
54 | }
55 | if (!result)
56 | {//4、校验是否触发限流及计数
57 | result = CheckRateLimitResult(clientRule);
58 | }
59 | return result;
60 |
61 | }
62 |
63 | ///
64 | /// 检验是否启用限流规则
65 | ///
66 | /// 请求地址
67 | ///
68 | private async Task CheckReRouteRuleAsync(string path)
69 | {
70 | var region = CzarCacheRegion.ClientRoleModelRegion;
71 | var key = path;
72 | var cacheResult = _ocelotCache.Get(key, region);
73 | if (cacheResult != null)
74 | {//提取缓存数据
75 | return cacheResult.Role;
76 | }
77 | else
78 | {//重新获取限流策略
79 | var result = await _clientRateLimitRepository.CheckReRouteRuleAsync(path);
80 | _ocelotCache.Add(key, new ClientRoleModel() { CacheTime = DateTime.Now, Role = result }, TimeSpan.FromSeconds(_options.CzarCacheTime), region);
81 | return result;
82 | }
83 |
84 | }
85 |
86 | ///
87 | /// 校验客户端限流规则
88 | ///
89 | /// 客户端ID
90 | /// 请求地址
91 | ///
92 | private async Task<(bool RateLimit, List rateLimitOptions)> CheckClientRateLimitAsync(string clientid, string path)
93 | {
94 | var region = CzarCacheRegion.RateLimitRuleModelRegion;
95 | var key = clientid + path;
96 | var cacheResult = _rateLimitRuleCache.Get(key, region);
97 | if (cacheResult != null)
98 | {//提取缓存数据
99 | return (cacheResult.RateLimit, cacheResult.rateLimitOptions);
100 | }
101 | else
102 | {//重新获取限流策略
103 | var result = await _clientRateLimitRepository.CheckClientRateLimitAsync(clientid, path);
104 | _rateLimitRuleCache.Add(key, new RateLimitRuleModel() { RateLimit=result.RateLimit, rateLimitOptions=result.rateLimitOptions }, TimeSpan.FromSeconds(_options.CzarCacheTime), region);
105 | return result;
106 | }
107 | }
108 |
109 | ///
110 | /// 校验是否设置了路由白名单
111 | ///
112 | /// 客户端ID
113 | /// 请求地址
114 | ///
115 | private async Task CheckClientReRouteWhiteListAsync(string clientid, string path)
116 | {
117 | var region = CzarCacheRegion.ClientReRouteWhiteListRegion;
118 | var key = clientid+ path;
119 | var cacheResult = _ocelotCache.Get(key, region);
120 | if (cacheResult != null)
121 | {//提取缓存数据
122 | return cacheResult.Role;
123 | }
124 | else
125 | {//重新获取限流策略
126 | var result = await _clientRateLimitRepository.CheckClientReRouteWhiteListAsync(clientid,path);
127 | _ocelotCache.Add(key, new ClientRoleModel() { CacheTime = DateTime.Now, Role = result }, TimeSpan.FromSeconds(_options.CzarCacheTime), region);
128 | return result;
129 | }
130 | }
131 |
132 | ///
133 | /// 校验完整的限流规则
134 | ///
135 | /// 限流配置
136 | ///
137 | private bool CheckRateLimitResult(List rateLimitOptions)
138 | {
139 | bool result = true;
140 | if (rateLimitOptions != null && rateLimitOptions.Count > 0)
141 | {//校验策略
142 | foreach (var op in rateLimitOptions)
143 | {
144 | CzarClientRateLimitCounter counter = new CzarClientRateLimitCounter(DateTime.UtcNow, 1);
145 | //分别对每个策略校验
146 | var enablePrefix = CzarCacheRegion.CzarClientRateLimitCounterRegion;
147 | var key = CzarOcelotHelper.ComputeCounterKey(enablePrefix, op.ClientId, op.Period, op.RateLimitPath);
148 | var periodTimestamp = CzarOcelotHelper.ConvertToSecond(op.Period);
149 | lock (_processLocker)
150 | {
151 | var rateLimitCounter = _clientRateLimitCounter.Get(key, enablePrefix);
152 | if (rateLimitCounter.HasValue)
153 | {//提取当前的计数情况
154 | // 请求次数增长
155 | var totalRequests = rateLimitCounter.Value.TotalRequests + 1;
156 | // 深拷贝
157 | counter = new CzarClientRateLimitCounter(rateLimitCounter.Value.Timestamp, totalRequests);
158 | }
159 | else
160 | {//写入限流策略
161 | _clientRateLimitCounter.Add(key, counter,TimeSpan.FromSeconds(periodTimestamp), enablePrefix);
162 | }
163 | }
164 | if (counter.TotalRequests > op.Limit)
165 | {//更新请求记录,并标记为失败
166 | result = false;
167 | }
168 | if (counter.TotalRequests > 1 && counter.TotalRequests <= op.Limit)
169 | {//更新缓存配置信息
170 | //获取限流剩余时间
171 | var cur = (int)(counter.Timestamp.AddSeconds(periodTimestamp) - DateTime.UtcNow).TotalSeconds;
172 | _clientRateLimitCounter.Add(key, counter, TimeSpan.FromSeconds(cur), enablePrefix);
173 | }
174 | }
175 | }
176 | return result;
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/RateLimit/IClientRateLimitProcessor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading.Tasks;
5 |
6 | namespace Czar.Gateway.RateLimit
7 | {
8 | ///
9 | /// 金焰的世界
10 | /// 2018-11-18
11 | /// 客户端限流处理器
12 | ///
13 | public interface IClientRateLimitProcessor
14 | {
15 | ///
16 | /// 校验客户端限流结果
17 | ///
18 | /// 客户端ID
19 | /// 应用策略地址
20 | ///
21 | Task CheckClientRateLimitResultAsync(string clientid, string path);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/RateLimit/IClientRateLimitRepository.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 |
5 | namespace Czar.Gateway.RateLimit
6 | {
7 | ///
8 | /// 金焰的世界
9 | /// 2018-11-19
10 | /// 客户端限流相关仓储接口
11 | ///
12 | public interface IClientRateLimitRepository
13 | {
14 | ///
15 | /// 校验是否启用限流规则
16 | ///
17 | /// 请求地址
18 | ///
19 | Task CheckReRouteRuleAsync(string path);
20 |
21 | ///
22 | /// 校验客户端限流规则
23 | ///
24 | /// 客户端ID
25 | /// 请求地址
26 | ///
27 | Task<(bool RateLimit, List rateLimitOptions)> CheckClientRateLimitAsync(string clientid, string path);
28 |
29 | ///
30 | /// 校验是否设置了路由白名单
31 | ///
32 | /// 客户端ID
33 | /// 请求地址
34 | ///
35 | Task CheckClientReRouteWhiteListAsync(string clientid, string path);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/RateLimit/Middleware/CzarClientRateLimitMiddleware.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Configuration;
2 | using Czar.Gateway.Errors;
3 | using Ocelot.Logging;
4 | using Ocelot.Middleware;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace Czar.Gateway.RateLimit.Middleware
9 | {
10 |
11 | ///
12 | /// 金焰的世界
13 | /// 2018-11-18
14 | /// 自定义客户端限流中间件
15 | ///
16 | public class CzarClientRateLimitMiddleware : OcelotMiddleware
17 | {
18 | private readonly IClientRateLimitProcessor _clientRateLimitProcessor;
19 | private readonly OcelotRequestDelegate _next;
20 | private readonly CzarOcelotConfiguration _options;
21 | public CzarClientRateLimitMiddleware(OcelotRequestDelegate next,
22 | IOcelotLoggerFactory loggerFactory,
23 | IClientRateLimitProcessor clientRateLimitProcessor,
24 | CzarOcelotConfiguration options)
25 | : base(loggerFactory.CreateLogger())
26 | {
27 | _next = next;
28 | _clientRateLimitProcessor = clientRateLimitProcessor;
29 | _options = options;
30 | }
31 |
32 | public async Task Invoke(DownstreamContext context)
33 | {
34 | var clientId = "client_cjy"; //使用默认的客户端
35 | if (!context.IsError)
36 | {
37 | if (!_options.ClientRateLimit)
38 | {
39 | Logger.LogInformation($"未启用客户端限流中间件");
40 | await _next.Invoke(context);
41 | }
42 | else
43 | {
44 | //非认证的渠道
45 | if (!context.DownstreamReRoute.IsAuthenticated)
46 | {
47 | if (context.HttpContext.Request.Headers.Keys.Contains(_options.ClientKey))
48 | {
49 | clientId = context.HttpContext.Request.Headers[_options.ClientKey].First();
50 | }
51 | }
52 | else
53 | {//认证过的渠道,从Claim中提取
54 | var clientClaim = context.HttpContext.User.Claims.FirstOrDefault(p => p.Type == _options.ClientKey);
55 | if (!string.IsNullOrEmpty(clientClaim?.Value))
56 | {
57 | clientId = clientClaim?.Value;
58 | }
59 | }
60 | //路由地址
61 | var path = context.DownstreamReRoute.UpstreamPathTemplate.OriginalValue;
62 | //1、校验路由是否有限流策略
63 | //2、校验客户端是否被限流了
64 | //3、校验客户端是否启动白名单
65 | //4、校验是否触发限流及计数
66 | if (await _clientRateLimitProcessor.CheckClientRateLimitResultAsync(clientId, path))
67 | {
68 | await _next.Invoke(context);
69 | }
70 | else
71 | {
72 | var error = new RateLimitOptionsError($"请求路由 {context.HttpContext.Request.Path}触发限流策略");
73 | Logger.LogWarning($"路由地址 {context.HttpContext.Request.Path} 触发限流策略. {error}");
74 | SetPipelineError(context, error);
75 | }
76 | }
77 | }
78 | else
79 | {
80 | await _next.Invoke(context);
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/RateLimit/Middleware/CzarClientRateLimitMiddlewareExtensions.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Middleware.Pipeline;
2 |
3 | namespace Czar.Gateway.RateLimit.Middleware
4 | {
5 | ///
6 | /// 金焰的世界
7 | /// 2018-11-18
8 | /// 限流中间件扩展
9 | ///
10 | public static class CzarClientRateLimitMiddlewareExtensions
11 | {
12 | public static IOcelotPipelineBuilder UseCzarClientRateLimitMiddleware(this IOcelotPipelineBuilder builder)
13 | {
14 | return builder.UseMiddleware();
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/RateLimit/RateLimitRuleModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Czar.Gateway.RateLimit
4 | {
5 | public class RateLimitRuleModel
6 | {
7 | ///
8 | /// 是否启用限流
9 | ///
10 | public bool RateLimit { get; set; }
11 |
12 | ///
13 | /// 限流配置信息
14 | ///
15 | public List rateLimitOptions { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Requester/Middleware/CzarHttpRequesterMiddleware.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Errors;
2 | using Newtonsoft.Json.Linq;
3 | using Ocelot.Logging;
4 | using Ocelot.Middleware;
5 | using Ocelot.Requester;
6 | using System.Threading.Tasks;
7 |
8 | namespace Czar.Gateway.Requester.Middleware
9 | {
10 | ///
11 | /// 金焰的世界
12 | /// 2018-12-10
13 | /// 自定义请求中间件
14 | ///
15 | public class CzarHttpRequesterMiddleware : OcelotMiddleware
16 | {
17 | private readonly OcelotRequestDelegate _next;
18 | private readonly IHttpRequester _requester;
19 |
20 | public CzarHttpRequesterMiddleware(OcelotRequestDelegate next,
21 | IOcelotLoggerFactory loggerFactory,
22 | IHttpRequester requester)
23 | : base(loggerFactory.CreateLogger())
24 | {
25 | _next = next;
26 | _requester = requester;
27 | }
28 |
29 | public async Task Invoke(DownstreamContext context)
30 | {
31 | var response = await _requester.GetResponse(context);
32 |
33 | if (response.IsError)
34 | {
35 | Logger.LogDebug("IHttpRequester returned an error, setting pipeline error");
36 |
37 | SetPipelineError(context, response.Errors);
38 | return;
39 | }
40 | else if(response.Data.StatusCode != System.Net.HttpStatusCode.OK)
41 | {//如果后端未处理异常,设置异常信息,统一输出,防止暴露敏感信息
42 | if (response.Data.StatusCode == System.Net.HttpStatusCode.BadRequest)
43 | {//提取Ids4相关的异常(400)
44 | var result = await response.Data.Content.ReadAsStringAsync();
45 | JObject jobj = JObject.Parse(result);
46 | var errorMsg = jobj["error"]?.ToString();
47 | var error = new IdentityServer4Error(errorMsg??"未知异常");
48 | SetPipelineError(context, error);
49 | return;
50 | }
51 | else
52 | {
53 | var error = new InternalServerError($"请求服务异常");
54 | Logger.LogWarning($"路由地址 {context.HttpContext.Request.Path} 请求服务异常. {error}");
55 | SetPipelineError(context, error);
56 | return;
57 | }
58 | }
59 | Logger.LogDebug("setting http response message");
60 |
61 | context.DownstreamResponse = new DownstreamResponse(response.Data);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Requester/Middleware/CzarHttpRequesterMiddlewareExtensions.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Middleware.Pipeline;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Czar.Gateway.Requester.Middleware
7 | {
8 | public static class CzarHttpRequesterMiddlewareExtensions
9 | {
10 | public static IOcelotPipelineBuilder UseCzaHttpRequesterMiddleware(this IOcelotPipelineBuilder builder)
11 | {
12 | return builder.UseMiddleware();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Responder/CzarErrorsToHttpStatusCodeMapper.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Errors;
2 | using Ocelot.Responder;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 |
8 | namespace Czar.Gateway.Responder
9 | {
10 | ///
11 | /// 金焰的世界
12 | /// 2018-11-19
13 | /// 错误信息转换成输出状态码
14 | ///
15 | public class CzarErrorsToHttpStatusCodeMapper : IErrorsToHttpStatusCodeMapper
16 | {
17 | public int Map(List errors)
18 | {
19 | if (errors.Any(e => e.Code == OcelotErrorCode.UnauthenticatedError))
20 | {
21 | return 401;
22 | }
23 |
24 | if (errors.Any(e => e.Code == OcelotErrorCode.UnauthorizedError
25 | || e.Code == OcelotErrorCode.ClaimValueNotAuthorisedError
26 | || e.Code == OcelotErrorCode.ScopeNotAuthorisedError
27 | || e.Code == OcelotErrorCode.UserDoesNotHaveClaimError
28 | || e.Code == OcelotErrorCode.CannotFindClaimError))
29 | {
30 | return 403;
31 | }
32 |
33 | if (errors.Any(e => e.Code == OcelotErrorCode.RequestTimedOutError))
34 | {
35 | return 503;
36 | }
37 |
38 | if (errors.Any(e => e.Code == OcelotErrorCode.UnableToFindDownstreamRouteError))
39 | {
40 | return 404;
41 | }
42 |
43 | if (errors.Any(e => e.Code == OcelotErrorCode.UnableToCompleteRequestError))
44 | {
45 | return 500;
46 | }
47 |
48 | if (errors.Any(e => e.Code == OcelotErrorCode.RateLimitOptionsError))
49 | {
50 | return 429;
51 | }
52 |
53 | if (errors.Any(e => e.Code == OcelotErrorCode.UnableToCreateAuthenticationHandlerError))
54 | {
55 | return 400;
56 | }
57 |
58 | return 404;
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Responder/CzarHttpContextResponder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 | using Microsoft.AspNetCore.Http.Features;
3 | using Microsoft.Extensions.Primitives;
4 | using Ocelot.Headers;
5 | using Ocelot.Middleware;
6 | using Ocelot.Responder;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Net;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace Czar.Gateway.Responder
15 | {
16 | public class CzarHttpContextResponder : IHttpResponder
17 | {
18 | private readonly IRemoveOutputHeaders _removeOutputHeaders;
19 |
20 | public CzarHttpContextResponder(IRemoveOutputHeaders removeOutputHeaders)
21 | {
22 | _removeOutputHeaders = removeOutputHeaders;
23 | }
24 |
25 | public async Task SetResponseOnHttpContext(HttpContext context, DownstreamResponse response)
26 | {
27 | _removeOutputHeaders.Remove(response.Headers);
28 |
29 | foreach (var httpResponseHeader in response.Headers)
30 | {
31 | AddHeaderIfDoesntExist(context, httpResponseHeader);
32 | }
33 |
34 | foreach (var httpResponseHeader in response.Content.Headers)
35 | {
36 | AddHeaderIfDoesntExist(context, new Header(httpResponseHeader.Key, httpResponseHeader.Value));
37 | }
38 |
39 | var content = await response.Content.ReadAsStreamAsync();
40 |
41 | if (response.Content.Headers.ContentLength != null)
42 | {
43 | AddHeaderIfDoesntExist(context, new Header("Content-Length", new[] { content.Length.ToString() }));
44 | }
45 |
46 | SetStatusCode(context, (int)response.StatusCode);
47 |
48 | context.Response.HttpContext.Features.Get().ReasonPhrase = response.ReasonPhrase;
49 |
50 | using (content)
51 | {
52 | if (response.StatusCode != HttpStatusCode.NotModified && context.Response.ContentLength != 0)
53 | {
54 | await content.CopyToAsync(context.Response.Body);
55 | }
56 | }
57 | }
58 |
59 | public void SetErrorResponseOnContext(HttpContext context, int statusCode)
60 | {
61 | SetStatusCode(context, statusCode);
62 | }
63 |
64 | private void SetStatusCode(HttpContext context, int statusCode)
65 | {
66 | if (!context.Response.HasStarted)
67 | {
68 | context.Response.StatusCode = statusCode;
69 | }
70 | }
71 |
72 | private static void AddHeaderIfDoesntExist(HttpContext context, Header httpResponseHeader)
73 | {
74 | if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key))
75 | {
76 | context.Response.Headers.Add(httpResponseHeader.Key, new StringValues(httpResponseHeader.Values.ToArray()));
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Responder/Middleware/CzarResponderMiddleware.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Configuration;
2 | using Microsoft.AspNetCore.Http;
3 | using Ocelot.Errors;
4 | using Ocelot.Logging;
5 | using Ocelot.Middleware;
6 | using Ocelot.Responder;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Net;
10 | using System.Threading.Tasks;
11 |
12 | namespace Czar.Gateway.Responder.Middleware
13 | {
14 | ///
15 | /// 金焰的世界
16 | /// 2018-12-10
17 | /// 统一输出中间件
18 | ///
19 | public class CzarResponderMiddleware: OcelotMiddleware
20 | {
21 | private readonly OcelotRequestDelegate _next;
22 | private readonly IHttpResponder _responder;
23 | private readonly IErrorsToHttpStatusCodeMapper _codeMapper;
24 |
25 | public CzarResponderMiddleware(OcelotRequestDelegate next,
26 | IHttpResponder responder,
27 | IOcelotLoggerFactory loggerFactory,
28 | IErrorsToHttpStatusCodeMapper codeMapper
29 | )
30 | : base(loggerFactory.CreateLogger())
31 | {
32 | _next = next;
33 | _responder = responder;
34 | _codeMapper = codeMapper;
35 | }
36 |
37 | public async Task Invoke(DownstreamContext context)
38 | {
39 | await _next.Invoke(context);
40 |
41 | if (context.IsError)
42 | {//自定义输出结果
43 | var errmsg = context.Errors[0].Message;
44 | int httpstatus = _codeMapper.Map(context.Errors);
45 | var errResult = new BaseResult() { errcode = httpstatus, errmsg = errmsg };
46 | var message = errResult.ToJson();
47 | context.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
48 | await context.HttpContext.Response.WriteAsync(message);
49 | return;
50 | }
51 | else if (context.HttpContext.Response.StatusCode != (int)HttpStatusCode.OK)
52 | {//标记失败,不做任何处理,自定义扩展时预留
53 |
54 | }
55 | else if (context.DownstreamResponse == null)
56 | {//添加如果管道强制终止,不做任何处理,修复未将对象实例化错误
57 |
58 | }
59 | else
60 | {//继续请求下游地址返回
61 | Logger.LogDebug("no pipeline errors, setting and returning completed response");
62 | await _responder.SetResponseOnHttpContext(context.HttpContext, context.DownstreamResponse);
63 | }
64 | }
65 |
66 | private void SetErrorResponse(HttpContext context, List errors)
67 | {
68 | var statusCode = _codeMapper.Map(errors);
69 | _responder.SetErrorResponseOnContext(context, statusCode);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Responder/Middleware/CzarResponderMiddlewareExtensions.cs:
--------------------------------------------------------------------------------
1 | using Ocelot.Middleware.Pipeline;
2 |
3 | namespace Czar.Gateway.Responder.Middleware
4 | {
5 | ///
6 | /// 金焰的世界
7 | /// 2018-12-10
8 | /// 应用输出中间件扩展
9 | ///
10 | public static class CzarResponderMiddlewareExtensions
11 | {
12 | public static IOcelotPipelineBuilder UseCzarResponderMiddleware(this IOcelotPipelineBuilder builder)
13 | {
14 | return builder.UseMiddleware();
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Rpc/CzarRpcProcessor.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Configuration;
2 | using Czar.Rpc.Message;
3 | using Ocelot.Cache;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Czar.Gateway.Rpc
10 | {
11 | public class CzarRpcProcessor: ICzarRpcProcessor
12 | {
13 | private readonly IRpcRepository _rpcRepository;
14 | private readonly CzarOcelotConfiguration _options;
15 | private readonly IOcelotCache _ocelotCache;
16 | public CzarRpcProcessor(IRpcRepository rpcRepository, CzarOcelotConfiguration options, IOcelotCache ocelotCache)
17 | {
18 | _rpcRepository = rpcRepository;
19 | _options = options;
20 | _ocelotCache = ocelotCache;
21 | }
22 |
23 | ///
24 | /// 根据模板地址获取RPC请求方法
25 | ///
26 | /// 上游模板
27 | ///
28 | public async Task GetRemoteMethodAsync(string UpUrl)
29 | {
30 | var region = CzarCacheRegion.RemoteInvokeMessageRegion;
31 | var key = UpUrl;
32 | var cacheResult = _ocelotCache.Get(key, region);
33 | if (cacheResult != null)
34 | {//提取缓存数据
35 | return cacheResult;
36 | }
37 | else
38 | {
39 | cacheResult = await _rpcRepository.GetRemoteMethodAsync(UpUrl);
40 | _ocelotCache.Add(key, cacheResult, TimeSpan.FromSeconds(_options.CzarCacheTime), region);
41 | return cacheResult;
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Rpc/ICzarRpcProcessor.cs:
--------------------------------------------------------------------------------
1 | using Czar.Rpc.Message;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Czar.Gateway.Rpc
8 | {
9 | public interface ICzarRpcProcessor
10 | {
11 | ///
12 | /// 根据模板地址获取RPC请求方法
13 | ///
14 | /// 上游模板
15 | ///
16 | Task GetRemoteMethodAsync(string UpUrl);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Rpc/IRpcRepository.cs:
--------------------------------------------------------------------------------
1 | using Czar.Rpc.Message;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Czar.Gateway.Rpc
8 | {
9 | public interface IRpcRepository
10 | {
11 | ///
12 | /// 根据模板地址获取RPC请求方法
13 | ///
14 | /// 上游模板
15 | ///
16 | Task GetRemoteMethodAsync(string UpUrl);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Czar.Gateway/Rpc/Middleware/CzarRpcMiddleware.cs:
--------------------------------------------------------------------------------
1 | using Czar.Gateway.Errors;
2 | using Czar.Rpc.Clients;
3 | using Ocelot.Logging;
4 | using Ocelot.Middleware;
5 | using Ocelot.Responses;
6 | using System.Collections.Generic;
7 | using System.Net;
8 | using System.Threading.Tasks;
9 |
10 | namespace Czar.Gateway.Rpc.Middleware
11 | {
12 | public class CzarRpcMiddleware : OcelotMiddleware
13 | {
14 | private readonly OcelotRequestDelegate _next;
15 | private readonly IRpcClientFactory _clientFactory;
16 | private readonly ICzarRpcProcessor _czarRpcProcessor;
17 | public CzarRpcMiddleware(OcelotRequestDelegate next, IRpcClientFactory clientFactory,
18 | IOcelotLoggerFactory loggerFactory, ICzarRpcProcessor czarRpcProcessor) : base(loggerFactory.CreateLogger())
19 | {
20 | _next = next;
21 | _clientFactory = clientFactory;
22 | _czarRpcProcessor = czarRpcProcessor;
23 | }
24 |
25 | public async Task Invoke(DownstreamContext context)
26 | {
27 | var httpStatusCode = HttpStatusCode.OK;
28 | var _param = new List