├── .gitignore
├── LICENSE
├── pom.xml
├── readme.md
├── settings.xml
└── src
└── main
├── java
└── com
│ └── muggle
│ └── poseidon
│ ├── adapter
│ ├── DisableSecurityConfigAdapter.java
│ ├── PoseidonAuthConfigAdapter.java
│ ├── PoseidonSecurityConfig.java
│ ├── SwaggerConfig.java
│ └── UserWebConfig.java
│ ├── annotation
│ └── InterfaceAction.java
│ ├── aop
│ ├── QueryAspect.java
│ └── RequestAspect.java
│ ├── auto
│ ├── ExpansibilityConfig.java
│ ├── PoseidonSecurityProperties.java
│ └── SecurityAutoConfig.java
│ ├── base
│ ├── BaseBean.java
│ ├── BaseController.java
│ ├── BaseQuery.java
│ ├── BaseService.java
│ ├── CommonQuery.java
│ ├── DistributedLocker.java
│ ├── ErrorCode.java
│ ├── ResultBean.java
│ ├── exception
│ │ ├── BasePoseidonCheckException.java
│ │ ├── BasePoseidonException.java
│ │ ├── SimplePoseidonCheckException.java
│ │ └── SimplePoseidonException.java
│ └── query
│ │ └── CommonQueryBean.java
│ ├── entity
│ ├── AuthUrlPathDO.java
│ └── RequestInfoDO.java
│ ├── filter
│ ├── SecurityLoginFilter.java
│ └── SecurityTokenFilter.java
│ ├── handler
│ ├── query
│ │ └── QuerySqlProcessor.java
│ ├── security
│ │ ├── PoseidonAccessDeniedHandler.java
│ │ ├── PoseidonAuthenticationFailureHandler.java
│ │ ├── PoseidonAuthenticationSuccessHandler.java
│ │ ├── PoseidonLoginUrlAuthenticationEntryPoint.java
│ │ ├── PoseidonLogoutSuccessHandler.java
│ │ └── RequestLogProcessor.java
│ └── web
│ │ ├── RoolMessageHandler.java
│ │ ├── WebResultHandler.java
│ │ └── WebUrlHandler.java
│ ├── listener
│ ├── ExceptionEvent.java
│ └── ExceptionListener.java
│ ├── manager
│ ├── PoseidonFilterInvocationSecurityMetadataSource.java
│ └── PoseidonWebExpressionVoter.java
│ ├── properties
│ └── SecurityMessageProperties.java
│ ├── service
│ └── TokenService.java
│ ├── store
│ ├── SecurityStore.java
│ └── impl
│ │ └── SimpleRedisSecurityStore.java
│ └── util
│ ├── BaseDaoUtils.java
│ ├── DateUtils.java
│ ├── ICollectionUtils.java
│ ├── INumberUtils.java
│ ├── IStringUtils.java
│ ├── JSONUtils.java
│ ├── JwtTokenUtils.java
│ ├── LocalDateUtils.java
│ ├── NamedThreadFactory.java
│ ├── PoseidonIdGenerator.java
│ ├── RSACoder.java
│ ├── RequestUtils.java
│ ├── SHA256Utils.java
│ ├── SimpleLocker.java
│ ├── ThreadPoolUtils.java
│ ├── UserInfoUtils.java
│ └── ZipUtils.java
└── resources
├── META-INF
└── spring.factories
├── banner.txt
└── poseidon-logback.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 | /mvnw.cmd
33 | /mvnw
34 | /.mvn/
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.muggle
7 | poseidon-boot-starter
8 | 1.0.0.Beta
9 | poseidon-boot-starter
10 | poseidon 项目starter 包
11 |
12 |
13 | 5.3
14 | 0.7.0
15 | 2.8.0
16 | UTF-8
17 | UTF-8
18 |
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-configuration-processor
24 | true
25 |
26 |
27 |
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-autoconfigure
32 |
33 |
34 | org.springframework
35 | spring-webmvc
36 |
37 |
38 | jakarta.servlet
39 | jakarta.servlet-api
40 | 6.0.0
41 |
42 |
43 | org.aspectj
44 | aspectjrt
45 |
46 |
47 |
48 | net.logstash.logback
49 | logstash-logback-encoder
50 | ${logstash.version}
51 |
52 |
53 |
54 | org.aspectj
55 | aspectjweaver
56 |
57 |
58 | commons-codec
59 | commons-codec
60 | 1.11
61 |
62 |
63 | io.jsonwebtoken
64 | jjwt
65 | ${jjwt.version}
66 |
67 |
68 | io.springfox
69 | springfox-swagger2
70 | ${swagger2.version}
71 |
72 |
73 | com.github.pagehelper
74 | pagehelper
75 | 5.1.2
76 |
77 |
78 | org.springframework.security
79 | spring-security-web
80 |
81 |
82 | org.springframework.security
83 | spring-security-config
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | org.springframework.boot
92 | spring-boot-dependencies
93 | 3.1.3
94 | pom
95 | import
96 |
97 |
98 |
99 |
100 |
101 |
102 | muggle0-poseidon-real
103 | real
104 | https://muggle0-maven.pkg.coding.net/repository/poseidon/real/
105 |
106 | true
107 |
108 |
109 | true
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | org.apache.maven.plugins
119 | maven-compiler-plugin
120 | 3.11.0
121 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 |
4 | # poseidon-boot-starter 使用说明
5 | 很nice 的 springboot 项目的脚手架,请路过的朋友点一个star。
6 |
7 | 对 springboot 项目感兴趣的小伙伴可以关注 [poseidon](https://github.com/muggle0/poseidon)
8 |
9 | 对 springCloud 感兴趣的小伙伴可以关注 [poseidon-cloud](https://github.com/muggle0/poseidon-cloud)
10 |
11 | 本人的书:[muggle的书](https://muggle-book.gitee.io/)
12 |
13 | 博客:muggle.javaboy.org
14 |
15 | 框架集成功能:
16 |
17 | - 异常报警
18 | - 权限动态配置
19 | - 幂等锁
20 | - 日志分组
21 | - 用户操作日志记录
22 | - 查询接口通用化。
23 |
24 | ## 开发日志
25 |
26 | - 2020.3.9 1.0.0.Beta 发布。多方测试bug
27 |
28 | - 2020.4.5 项目从cloud-starter 分裂出来,补充部分不成熟地方。
29 |
30 | - 2020.4.16 发布 `0.0.1.Beta` 版
31 |
32 | - 2020.4.17 开始开发webflux版,提供对webflux的支持(webflux 分支 版本号0.0.1-webflux.Alpha)。
33 |
34 | - 2020.6.1 `0.0.1.Beta` 添加查询组件功能,并计划发布`0.0.1.release`。
35 |
36 | ## 快速开始
37 |
38 | 具体使用案例可参考 [sofia](https://github.com/fighting-v/sofia) 小伙伴喜欢的可以关注下这个项目嗷。
39 |
40 | 第一步拉取项目 并且使用 maven 安装到本地。
41 | 拉取项目:
42 | ```
43 | git clone https://github.com/muggle0/poseidon-boot-starter.git
44 | ```
45 | 安装到本地仓库:
46 | ```
47 | cd poseidon-boot-starter
48 |
49 | mvn install
50 |
51 | ```
52 |
53 | 第二步
54 | 创建 spring boot工程 并引入依赖:
55 |
56 | ```xml
57 |
58 |
59 | com.muggle
60 | poseidon-boot-starter
61 | 0.0.1.Beta
62 |
63 | ```
64 | 第三步开启自动化配置并注册 `tokenService` 和 `securityStore`
65 |
66 | appplication.properties:
67 |
68 | ```properties
69 | spring.profiles.active=dev
70 | # 使用内置logback配置代替spring logback配置
71 | logging.config=classpath:poseidon-logback.xml
72 | # 配置内置logback参数 log文件位置
73 | log.dir=logs
74 | #是否开启自动化配置,开启自动化配置后会注入权限管理,幂等锁,统一异常处理功能
75 | poseidon.auto=true
76 | # 权限管理配置忽略的 url 使用ant匹配符。
77 | poseidon.ignore-path=/**
78 | ```
79 |
80 | 接下来往spring容器注册
81 |
82 | ```java
83 |
84 | /**
85 | * muggle
86 | */
87 | @Service
88 | public class SofiaSecurityStore implements SecurityStore {
89 | private static String publicKey="test";
90 | @Override
91 | public UserDetails getUserdetail(String token) throws BasePoseidonCheckException {
92 | String role = JwtTokenUtils.getBody(token, publicKey, "role");
93 | String username = JwtTokenUtils.getBody(token, publicKey, "username");
94 | SofiaUserDO sofiaUserDO = new SofiaUserDO();
95 | sofiaUserDO.setAccountNonExpired(true);
96 | sofiaUserDO.setAccountNonLocked(true);
97 | SimpleGrantedAuthority admin = new SimpleGrantedAuthority(role);
98 | sofiaUserDO.setAuthorities(Arrays.asList(admin));
99 | sofiaUserDO.setEnabled(true);
100 | sofiaUserDO.setUsername(username);
101 | return sofiaUserDO;
102 | }
103 |
104 | @Override
105 | public String signUserMessage(UserDetails userDetails) {
106 | Map roleMap=new HashMap<>();
107 | roleMap.put("username",userDetails.getUsername());
108 | roleMap.put("role","/admin/**");
109 | String token = JwtTokenUtils.createToken(roleMap, publicKey, 12L);
110 | return token;
111 | }
112 | @Override
113 | public Boolean cleanToken(String s) {
114 | return null;
115 | }
116 |
117 | }
118 |
119 |
120 | @Component
121 | public class SofiaTokenService implements TokenService {
122 | private AntPathMatcher antPathMatcher=new AntPathMatcher();
123 | @Override
124 | public UserDetails getUserById(Long aLong) {
125 | return null;
126 | }
127 |
128 | @Override
129 | public boolean rooleMatch(Collection extends GrantedAuthority> collection, String s) {
130 | boolean match=false;
131 | for (GrantedAuthority grantedAuthority : collection) {
132 | String authority = grantedAuthority.getAuthority();
133 | match = antPathMatcher.match(authority, s);
134 | }
135 | return match;
136 | }
137 |
138 |
139 | @Override
140 | public void saveUrlInfo(List list) {
141 |
142 | }
143 |
144 | @Override
145 | public UserDetails login(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws SimplePoseidonCheckException {
146 | return loadUserByUsername("admin");
147 | }
148 |
149 | @Override
150 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
151 | SofiaUserDO sofiaUserDO = new SofiaUserDO();
152 | sofiaUserDO.setAccountNonExpired(true);
153 | sofiaUserDO.setAccountNonLocked(true);
154 | sofiaUserDO.setEnabled(true);
155 | sofiaUserDO.setUsername(username);
156 | return sofiaUserDO;
157 | }
158 | }
159 |
160 | ```
161 | 访问自定义的接口,我们就能看到权限拦截成功了。
162 |
163 | ## 接口说明:
164 |
165 | ### 权限相关配置
166 |
167 | `SecurityStore.getUserdetail` 方法 根据token获取用户信息,当请求头 `header` 里面 有 `token` 如:
168 |
169 | ```
170 | POST http://localhost:8080/test
171 |
172 | Content-Type:application/json
173 | token:eyJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiYWRtaW4iLCJ1c2VybmFtZSI6Ii9hZG1pbi8qKiJ9.8FOhRpN7DDii2YuuuXdcOU2BofwoEJ6YxCBb4k69sPCGxs9vpH9nd_cTjhvfilvS8itbiUJfgOAT3P9DtDvmiQ
174 | ```
175 | 这时框架会调用调用该方法来获取用户信息 `userDetails`, 接下来会调用 `userDetails.getAuthorities()` 获取角色集合并获取请求的 uri 一并传递给 `TokenService.rooleMatch` 让实现者自己做权限判断。
176 |
177 | 登录请求的url 为 `/sign_in` 访问该 url 的时候会调用 `TokenService.login` 方法来获取一个token返回给前端。`TokenService.loadUserByUsername` 为 security 框架默认的方法,这里不会去使用它,所以可以只实现该方法,不必去实现其逻辑
178 |
179 | 当 spring 的 `profiles` 也就是配置 `spring.profiles.active` 为 "uat","sit","online","refresh" 时 会获取 swagger 接口注解上的信息并调用: `TokenService.saveUrlInfo()` 的方法,你可以选择直接return 也可以 将这些 url 存到数据库 用于做权限控制
180 |
181 | ### 日志切面相关配置
182 |
183 | 当使用者实现接口 `DistributedLocker` 并注册到spring容器的时候会激活日志切面和幂等拦截。幂等拦截和日志切面使用示例:
184 |
185 | ```java
186 | @RestController
187 | @RequestMapping("/admin")
188 | public class TestController {
189 |
190 |
191 | @GetMapping("/test")
192 | @InterfaceAction(Idempotent = true,expertime = 4L)
193 | public ResultBean test(){
194 | return ResultBean.success();
195 | }
196 |
197 | @PostMapping("/test0")
198 | @InterfaceAction
199 | public ResultBean test0(){
200 | return ResultBean.success();
201 | }
202 |
203 | }
204 |
205 | ```
206 | `@InterfaceAction` 是切面注解,当使用该注解的时候 会拦截用户请求 和请求信息打印 info 日志:
207 |
208 | ```
209 | POSEIDON---- 2020-04-06 12:15:06 [http-nio-8080-exec-3] INFO com.muggle.poseidon.aop.RequestAspect - 请求日志 username=admin url=/admin/test0 method=POST ip=0:0:0:0:0:0:0:1 classMethod=com.fight.controller.TestController.test0 paramters=[]
210 | ```
211 |
212 | 注解默认不开启幂等拦截,如果想开启幂等拦截需要将 `Idempotent`设置为 true,其他的幂等参数设置 `expertime` 为接口上锁时间, `message` 为幂等拦截后返回给前端的提示信息。
213 |
214 | 可能有部分开发者对用户行为日志写库的需求,我这里未做支持,如果有该需求的开发者可以自己修改 `RequestAspect` 源码。
215 |
216 | 如果你有对日志写库或者二次处理的需求,你只需要实现 `RequestLogProcessor` 接口并注册就能获取到请求与入参。
217 |
218 | ### 框架的基础设施
219 |
220 | 框架收录了平时使用的 utlis 类在 `com.muggle.poseidon.util` 包下,使用者可以按需修改调整。`com.muggle.poseidon.base` 包下提供了基类,基础异常和 `ResultBean` 使用者请根据实际情况按需调整
221 |
222 | ### 统一异常处理相关配置
223 |
224 | `com.muggle.poseidon.handler.web.WebResultHandler.WebResultHandler` 是统一异常处理类,该类定义了部分异常捕获后返回给前端的json信息,用户根据实际情况按需调整。
225 |
226 | 这里需要注意一个 异常报警功能的使用:
227 |
228 | ```java
229 |
230 | @ExceptionHandler(value = {Exception.class})
231 | public ResultBean exceptionHandler(Exception e, HttpServletRequest req) {
232 | try {
233 | UserDetails userInfo = UserInfoUtils.getUserInfo();
234 | ExceptionEvent exceptionEvent = new ExceptionEvent(String.format("系统异常: [ %s ] 时间戳: [%d] ", e.getMessage(),System.currentTimeMillis()), this);
235 | applicationContext.publishEvent(exceptionEvent);
236 | log.error("系统异常:" + req.getMethod() + req.getRequestURI()+" user: "+userInfo.toString() , e);
237 | return ResultBean.error("系统异常");
238 | }catch (Exception err){
239 | log.error("紧急!!! 严重的异常",err);
240 | return ResultBean.error("系统发生严重的错误");
241 | }
242 | }
243 |
244 | ```
245 |
246 | 当系统抛出无法处理的异常的时候,会发布一个事件 `ExceptionEvent` ,我们可以通过监听这个事件来实现系统报警:
247 |
248 | ```java
249 | @Component
250 | public class ExceptionListener implements ApplicationListener {
251 |
252 |
253 | @Override
254 | public void onApplicationEvent(ExceptionEvent event) {
255 | String message = event.getMessage();
256 | // TODO 将异常信息投递到邮箱等,通知开发人员系统异常,尽快处理。
257 | }
258 | }
259 | ```
260 |
261 |
262 | 我们还可以添加我们自定义的异常拦截,我们需要,继承 `com.muggle.poseidon.handler.web.WebResultHandler` 然后添加我们需要的处理方法, 示例:
263 | ```java
264 | @RestControllerAdvice
265 | @Configuration
266 | public class MyWebResultHandler extends WebResultHandler {
267 | private static final Logger log = LoggerFactory.getLogger(OAwebResultHandler.class);
268 | @ExceptionHandler({ConstraintViolationException.class})
269 | public ResultBean methodArgumentNotValidException(ConstraintViolationException e, HttpServletRequest req) {
270 | log.error("参数未通过校验", e);
271 | ResultBean error = ResultBean.error(e.getConstraintViolations().iterator().next().getMessage());
272 | return error;
273 | }
274 | }
275 | ```
276 | 示例中添加了一个参数校验异常处理方法。
277 |
278 | 对于其他的异常处理逻辑请阅读源码 `com.muggle.poseidon.handler.web.WebResultHandler` 类。
279 |
280 | ### 查询组件的使用。
281 |
282 | 为了减少开发者对查询接口开发的开发时间,该框架设计了一个简单的配合 `PageHelper` 使用的插件,该功能由于构思不是很成熟,
283 | 所以其部分实现需要框架的使用者自己去完成。下面介绍该功能的使用方式和原理:
284 |
285 | 第一步注册查询拦截切面:
286 | ```java
287 | @Bean
288 | QueryAspect getQueryAspect(){
289 | return new QueryAspect();
290 | }
291 | ```
292 |
293 | 第二步定义查询类:
294 |
295 | ```java
296 | public class MyQuery extends BaseQuery {
297 |
298 | @ApiModelProperty(value = "是否有效")
299 | private Boolean enable;
300 |
301 | @ApiModelProperty(value = "请求类型")
302 | private String requestType;
303 |
304 | @ApiModelProperty(value = "类名")
305 | private String className;
306 |
307 | @ApiModelProperty(value = "方法名")
308 | private String methodName;
309 |
310 | @ApiModelProperty(value = "请求路径")
311 | private String url;
312 |
313 | @ApiModelProperty(value = "描述")
314 | private String description;
315 |
316 |
317 | private String finalSql;
318 |
319 | @Override
320 | public void processSql() {
321 | Map operatorMap = this.getOperatorMap();
322 | StringBuilder builder=new StringBuilder();
323 | if (operatorMap!=null){
324 | Iterator iterator = operatorMap.keySet().iterator();
325 | while (iterator.hasNext()) {
326 | String next = iterator.next();
327 | try {
328 | Object field=getFieldValue(next);
329 | if ((field instanceof Number)){
330 | builder.append(next+operatorMap.get(next).getValue()+field);
331 | }else {
332 | builder.append(next+operatorMap.get(next).getValue()+"'"+field+"'");
333 | }
334 | } catch (NoSuchFieldException | IllegalAccessException e) {
335 | throw new OAException("查询参数异常:"+next);
336 | }
337 | }
338 | }
339 |
340 | List groupBy = this.getGroupBy();
341 | if (!CollectionUtils.isEmpty(groupBy)){
342 | builder.append(" group by");
343 | for (int i = 0; i < groupBy.size(); i++) {
344 | if (i==groupBy.size()-1){
345 | builder.append(groupBy.get(i));
346 | }else {
347 | builder.append(groupBy.get(i)+",");
348 | }
349 | }
350 | }
351 | this.finalSql=builder.toString();
352 | }
353 |
354 | private Object getFieldValue(String next) throws NoSuchFieldException, IllegalAccessException {
355 | Field field = this.getClass().getDeclaredField(next);
356 | //打开私有访问
357 | field.setAccessible(true);
358 | //获取属性值
359 | return field.get(this);
360 | }
361 |
362 | @Override
363 | public String getFinalSql() {
364 | return finalSql;
365 | }
366 |
367 | public void setFinalSql(String finalSql) {
368 | this.finalSql = finalSql;
369 | }
370 | }
371 | ```
372 |
373 | 然后在 `mybatis` 的xml中使用 `finalSql` :
374 | ```xml
375 |
382 | ```
383 | 这个功能的设计思路是 在 `BaseQuery` 的 `orderBy` 字段为排序的list,`groupBy` 是 排序的list, `operatorMap` 是字段的运算符。
384 | 在 `QueryAspect` 的切面中它做的事情很简单,调用 `processSql()` 方法和 `init()` 方法,同时会调用 `QuerySqlProcessor` 的方法进行返回值和查询参数的自定义处理。
385 | 所以这个功能只定义最基础的骨架,其内部的具体实现还是要使用者自己去完成。
386 |
387 |
388 |
389 | ### 日志配置
390 |
391 | 使用框架logback配置:`logging.config=classpath:poseidon-logback.xml` 具体配置信息信息在源码中有注释。
392 |
393 |
394 |
395 | ## 框架使用及其二次开发建议
396 |
397 | 1. 权限控制: 因为不同项目对权限的管理粒度不一样,所以框架将这一部分暴露给使用者实现;关于权限的管控思路——粗粒度权限管控的可以以url的命名来简单管控如 `/admin/**` 的url 只能 admin角色访问,以此类推。
398 |
399 | 对于粒度再细一点的,可以将需要进行权限管控的url 缓存到内存,然后通过用户角色来判断是否有权限访问该url。
400 |
401 | 对于粒度更加细一点的权限控制,可以结合上面两种方法做权限管控,从url命名上约束接口是否需要权限控制,然后再将角色的url权限保存到数据库中。
402 |
403 | 2. 自动化配置扩展: 部分使用者可能希望诸如自定义的序列化器,拦截器,过滤器,监听器等也能根据项目需要实现自动化配置,我们可以在框架中加入我们自己的bean
404 |
405 | 假如我现在想自动化配置一个监听器:
406 |
407 | ```java
408 | public class ExceptionListener implements ApplicationListener {
409 |
410 |
411 | @Override
412 | public void onApplicationEvent(ExceptionEvent event) {
413 |
414 | }
415 | }
416 | ```
417 |
418 | 我们在 `com.muggle.poseidon.auto.ExpansibilityConfig` 类中注册bean:
419 |
420 | ```java
421 | @Bean
422 | ExceptionListener listener(){
423 | return new ExceptionListener();
424 | }
425 | ```
426 |
427 | 就可以让引用该starter包的spring容器中注册该监听器,或者你也可以在 `spring.factories` 加上你的类限定名:
428 |
429 | ```properties
430 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
431 | com.muggle.poseidon.handler.web.WebResultHandler,\
432 | com.username.lestener.ExceptionListener
433 | ```
434 |
435 |
436 | ## 交流
437 | 微信号:muggle_wx
438 |
439 | 喜欢的朋友 starter 一下吧,撸码不容易
440 |
441 |
--------------------------------------------------------------------------------
/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 | muggle0-poseidon-real
10 | ${env.CODING_MAVEN_REG_USERNAME}
11 | ${env.CODING_MAVEN_REG_PASSWORD}
12 |
13 |
14 |
15 |
16 | a1
17 |
18 |
19 | central
20 | http://repo1.maven.org/maven2/
21 |
22 | true
23 |
24 |
25 | false
26 |
27 |
28 |
29 | muggle0-poseidon-real
30 | real
31 | https://muggle0-maven.pkg.coding.net/repository/poseidon/real/
32 |
33 | true
34 |
35 |
36 | true
37 |
38 |
39 |
40 |
41 |
42 | central
43 | https://maven.aliyun.com/nexus/content/groups/public
44 |
45 | true
46 |
47 |
48 | false
49 |
50 |
51 |
52 |
53 |
54 |
55 | a1
56 |
57 |
58 |
59 | aliyunmaven
60 | central
61 | aliyun maven
62 | https://maven.aliyun.com/repository/public
63 |
64 |
65 | nexus-tencentyun
66 |
67 | !muggle0-poseidon-real
68 | Nexus tencentyun
69 | http://mirrors.cloud.tencent.com/nexus/repository/maven-public/
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/adapter/DisableSecurityConfigAdapter.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.adapter;
2 |
3 | import com.muggle.poseidon.auto.PoseidonSecurityProperties;
4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
5 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
8 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
9 |
10 | /**
11 | * Description
12 | * Date 2021/3/28
13 | * Created by muggle
14 | */
15 | @Configuration
16 | @EnableConfigurationProperties(PoseidonSecurityProperties.class)
17 | @ConditionalOnProperty(prefix = "poseidon", name = "auto", havingValue = "false", matchIfMissing = false)
18 | public class DisableSecurityConfigAdapter extends WebSecurityConfigurerAdapter {
19 |
20 | @Override
21 | protected void configure(HttpSecurity http) throws Exception {
22 | http
23 | .csrf()
24 | .disable()
25 | .authorizeRequests()
26 | .anyRequest()
27 | .permitAll()
28 | .and()
29 | .logout()
30 | .permitAll();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/adapter/PoseidonAuthConfigAdapter.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.adapter;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.google.common.collect.Lists;
7 | import com.muggle.poseidon.auto.PoseidonSecurityProperties;
8 | import com.muggle.poseidon.filter.SecurityLoginFilter;
9 | import com.muggle.poseidon.filter.SecurityTokenFilter;
10 | import com.muggle.poseidon.handler.security.PoseidonAccessDeniedHandler;
11 | import com.muggle.poseidon.handler.security.PoseidonAuthenticationFailureHandler;
12 | import com.muggle.poseidon.handler.security.PoseidonAuthenticationSuccessHandler;
13 | import com.muggle.poseidon.handler.security.PoseidonLoginUrlAuthenticationEntryPoint;
14 | import com.muggle.poseidon.handler.security.PoseidonLogoutSuccessHandler;
15 | import com.muggle.poseidon.manager.PoseidonWebExpressionVoter;
16 | import com.muggle.poseidon.properties.SecurityMessageProperties;
17 | import com.muggle.poseidon.service.TokenService;
18 | import com.muggle.poseidon.store.SecurityStore;
19 | import org.apache.commons.logging.Log;
20 | import org.apache.commons.logging.LogFactory;
21 | import org.springframework.security.access.AccessDecisionManager;
22 | import org.springframework.security.access.AccessDecisionVoter;
23 | import org.springframework.security.access.vote.UnanimousBased;
24 | import org.springframework.security.config.Customizer;
25 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
26 | import org.springframework.security.config.annotation.web.builders.WebSecurity;
27 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
28 | import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
29 | import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
30 | import org.springframework.security.config.http.SessionCreationPolicy;
31 | import org.springframework.security.web.AuthenticationEntryPoint;
32 | import org.springframework.security.web.DefaultSecurityFilterChain;
33 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
34 | import org.springframework.security.web.authentication.logout.LogoutFilter;
35 | import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
36 |
37 | /**
38 | * @program: poseidon-cloud-starter
39 | * @description: 权限校验配置类
40 | * @author: muggle
41 | * @create: 2019-11-04
42 | **/
43 | @EnableWebSecurity
44 | public class PoseidonAuthConfigAdapter {
45 | private static final Log log = LogFactory.getLog(PoseidonAuthConfigAdapter.class);
46 | private TokenService tokenService;
47 | private SecurityStore securityStore;
48 | private PoseidonSecurityProperties properties;
49 |
50 | public PoseidonAuthConfigAdapter(TokenService tokenService, SecurityStore securityStore, PoseidonSecurityProperties properties) {
51 | this.tokenService = tokenService;
52 | this.securityStore = securityStore;
53 | this.properties = properties;
54 | }
55 |
56 |
57 |
58 |
59 |
60 | public void configure(WebSecurity web) throws Exception {
61 |
62 | // String [] paths={"/**/*.bmp", "/**/*.gif", "/**/*.png", "/**/*.jpg", "/**/*.ico","/**/*.html","/**/*.css","/**/*.js"};
63 | if (properties.getStaticPath() == null) {
64 | properties.setStaticPath(new ArrayList<>());
65 | }
66 | String[] paths = new String[properties.getStaticPath().size()];
67 | properties.getStaticPath().toArray(paths);
68 | web.ignoring().antMatchers(paths);
69 | SecurityStore.ACCESS_PATHS.add("/error_message");
70 | SecurityStore.ACCESS_PATHS.add("/");
71 | SecurityStore.ACCESS_PATHS.add("/public/notfound");
72 | // log.debug("》》》》 初始化security 放行静态资源:{}" + "/**/*.bmp /**/*.png /**/*.gif /**/*.jpg /**/*.ico /**/*.js");
73 | }
74 |
75 | public DefaultSecurityFilterChain configure(HttpSecurity http) throws Exception {
76 | log.info(">>>>>>>>>>>>>>>>>>>>> 启动security配置 <<<<<<<<<<<<<<<<<<<< ");
77 |
78 | List ignorePath = properties.getIgnorePath();
79 |
80 | if (ignorePath == null) {
81 | properties.setIgnorePath(new ArrayList<>());
82 | ignorePath = properties.getIgnorePath();
83 | }
84 | String[] paths = new String[ignorePath.size()];
85 | ignorePath.toArray(paths);
86 | SecurityStore.saveAccessPath(ignorePath);
87 | http.authorizeRequests().requestMatchers(paths).permitAll()
88 | .requestMatchers("/admin/oauth/**").hasRole("admin")
89 | .anyRequest().authenticated().accessDecisionManager(accessDecisionManager())
90 | .and().csrf(new Customizer>() {
91 | @Override
92 | public void customize(CsrfConfigurer httpSecurityCsrfConfigurer) {
93 |
94 | }
95 | });
96 | http.formLogin(new Customizer>() {
97 | @Override
98 | public void customize(FormLoginConfigurer httpSecurityFormLoginConfigurer) {
99 |
100 | }
101 | });
102 | http.addFilterBefore(poseidonTokenFilter(), LogoutFilter.class);
103 | http.exceptionHandling().authenticationEntryPoint(loginUrlAuthenticationEntryPoint()).accessDeniedHandler(new PoseidonAccessDeniedHandler());
104 | http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
105 | http.addFilterAt(getLoginFilter(), UsernamePasswordAuthenticationFilter.class);
106 | http.logout().logoutUrl(SecurityMessageProperties.LOGOUT).logoutSuccessHandler(getLogoutSuccessHandler()).permitAll();
107 | return http.build();
108 | }
109 |
110 |
111 | /**
112 | * @author muggle
113 | * @Description: 设置投票器
114 | * @Param:
115 | * @return:
116 | * @date 2019/11/6 8:38
117 | */
118 | private AccessDecisionManager accessDecisionManager() {
119 | List> decisionVoters = Lists.newArrayList(((AccessDecisionVoter>)
120 | new PoseidonWebExpressionVoter(tokenService, properties)));
121 | return new UnanimousBased(decisionVoters);
122 |
123 | }
124 |
125 | /**
126 | * @author muggle
127 | * @Description: token的过滤器
128 | * @Param:
129 | * @return:
130 | * @date 2019/11/6 8:38
131 | */
132 | private SecurityTokenFilter poseidonTokenFilter() {
133 | final SecurityTokenFilter poseidonTokenFilter = new SecurityTokenFilter(securityStore, properties);
134 | return poseidonTokenFilter;
135 | }
136 |
137 | /**
138 | * @author muggle
139 | * @Description: 未登陆处理器,当url为登陆权限时放行
140 | * @Param:
141 | * @return:
142 | * @date 2019/11/5 12:01
143 | */
144 | private AuthenticationEntryPoint loginUrlAuthenticationEntryPoint() {
145 | return new PoseidonLoginUrlAuthenticationEntryPoint(SecurityMessageProperties.LOGIN_URL);
146 | }
147 |
148 | private SecurityLoginFilter getLoginFilter() {
149 | SecurityLoginFilter securityLoginFilter = new SecurityLoginFilter(tokenService, securityStore);
150 | securityLoginFilter.setAuthenticationFailureHandler(new PoseidonAuthenticationFailureHandler());
151 | securityLoginFilter.setAuthenticationSuccessHandler(new PoseidonAuthenticationSuccessHandler());
152 | securityLoginFilter.setFilterProcessesUrl(SecurityMessageProperties.LOGIN_URL);
153 | return securityLoginFilter;
154 | }
155 |
156 | /**
157 | * 登出成功处理器
158 | *
159 | * @return
160 | */
161 | private LogoutSuccessHandler getLogoutSuccessHandler() {
162 | return new PoseidonLogoutSuccessHandler(this.securityStore);
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/adapter/PoseidonSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.adapter;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
7 | import org.springframework.security.config.http.SessionCreationPolicy;
8 | import org.springframework.security.web.SecurityFilterChain;
9 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
10 |
11 | /**
12 | * Description
13 | * Date 2023/10/7
14 | * Created by muggle
15 | */
16 | @EnableWebSecurity
17 | @Configuration
18 | public class PoseidonSecurityConfig {
19 |
20 | @Bean
21 | public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
22 |
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/adapter/SwaggerConfig.java:
--------------------------------------------------------------------------------
1 | //package com.muggle.poseidon.adapter;
2 | //
3 | //import org.springframework.context.annotation.Bean;
4 | //import org.springframework.context.annotation.Configuration;
5 | //import springfox.documentation.builders.ApiInfoBuilder;
6 | //import springfox.documentation.builders.PathSelectors;
7 | //import springfox.documentation.builders.RequestHandlerSelectors;
8 | //import springfox.documentation.service.Contact;
9 | //import springfox.documentation.spi.DocumentationType;
10 | //import springfox.documentation.spring.web.plugins.Docket;
11 | //import springfox.documentation.swagger2.annotations.EnableSwagger2;
12 | //
13 | ///**
14 | // * @program: poseidon-cloud-user
15 | // * @description: 接口文档配置
16 | // * @author: muggle
17 | // * @create: 2019-12-06
18 | // **/
19 | //
20 | //@Configuration
21 | //@EnableSwagger2
22 | //public class SwaggerConfig {
23 | //
24 | // @Bean
25 | // public Docket createRestApi() {
26 | // return new Docket(DocumentationType.SWAGGER_2)
27 | // .pathMapping("/")
28 | // .select()
29 | // .apis(RequestHandlerSelectors.basePackage("com.muggle.poseidon.controller"))
30 | // .paths(PathSelectors.any())
31 | // .build().apiInfo(new ApiInfoBuilder()
32 | // .title("用户中心api")
33 | // .description("用户管理界面")
34 | // .version("0.0.1.BUILD")
35 | // .contact(new Contact("啊啊啊啊","test","isocket@outlook.com"))
36 | // .license("The Apache License")
37 | // .licenseUrl("http://www.baidu.com")
38 | // .build());
39 | // }
40 | //
41 | //}
42 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/adapter/UserWebConfig.java:
--------------------------------------------------------------------------------
1 | //package com.muggle.poseidon.adapter;
2 | //
3 | //
4 | //import com.alibaba.fastjson.serializer.SerializerFeature;
5 | //import com.alibaba.fastjson.support.config.FastJsonConfig;
6 | //import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
7 | //import com.muggle.poseidon.base.config.interceptor.RequestLockInterceptor;
8 | //import com.muggle.poseidon.helper.RequestLockHelper;
9 | //import org.springframework.beans.factory.annotation.Autowired;
10 | //import org.springframework.boot.web.server.ErrorPage;
11 | //import org.springframework.boot.web.server.WebServerFactoryCustomizer;
12 | //import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
13 | //import org.springframework.context.annotation.Bean;
14 | //import org.springframework.context.annotation.Configuration;
15 | //import org.springframework.http.HttpStatus;
16 | //import org.springframework.http.MediaType;
17 | //import org.springframework.http.converter.HttpMessageConverter;
18 | //import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
19 | //import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
20 | //
21 | //import java.util.ArrayList;
22 | //import java.util.List;
23 | //
24 | //
25 | //@Configuration
26 | //public class UserWebConfig implements WebMvcConfigurer {
27 | //
28 | // @Autowired
29 | // List helpers;
30 | //
31 | //
32 | //
33 | // // 解析器
34 | // @Override
35 | // public void configureMessageConverters(List> converters) {
36 | // // 1.需要先定义一个convert 转换消息的对象
37 | // FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
38 | // // 2.添加fastJson的配置信息,比如,是否需要格式化返回的json数据
39 | // FastJsonConfig fastJsonConfig = new FastJsonConfig();
40 | // // 空值特别处理
41 | // // WriteNullListAsEmpty 将Collection类型字段的字段空值输出为[]
42 | // // WriteNullStringAsEmpty 将字符串类型字段的空值输出为空字符串 ""
43 | // // WriteNullNumberAsZero 将数值类型字段的空值输出为0
44 | // // WriteNullBooleanAsFalse 将Boolean类型字段的空值输出为false
45 | // fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat, SerializerFeature.WriteNullListAsEmpty,
46 | // SerializerFeature.WriteNullStringAsEmpty);
47 | // // 处理中文乱码问题
48 | // List fastMediaTypes = new ArrayList<>();
49 | // fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
50 | // fastConverter.setSupportedMediaTypes(fastMediaTypes);
51 | // // 3.在convert中添加配置信息
52 | // fastConverter.setFastJsonConfig(fastJsonConfig);
53 | // // 4.将convert添加到converters当中
54 | // converters.add(fastConverter);
55 | // }
56 | //
57 | // @Override
58 | // public void addInterceptors(InterceptorRegistry registry) {
59 | // registry.addInterceptor(new RequestLockInterceptor(helpers)).addPathPatterns("/**");
60 | //
61 | // }
62 | //
63 | // // 配置错误页面
64 | // @Bean
65 | // public WebServerFactoryCustomizer containerCustomizer() {
66 | // return new WebServerFactoryCustomizer() {
67 | // @Override
68 | // public void customize(ConfigurableServletWebServerFactory factory) {
69 | // factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,"/public/test"));
70 | // }
71 | // };
72 | // }
73 | //}
74 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/annotation/InterfaceAction.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.annotation;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * @description: 开启日志的注解,标注到方法上
11 | * @author: mozishu
12 | * @create: 2019-12-28 12:40
13 | */
14 | @Documented
15 | @Target(ElementType.METHOD)
16 | @Retention(RetentionPolicy.RUNTIME)
17 | public @interface InterfaceAction {
18 | String message() default "请求太频繁,请稍后再试";
19 |
20 | /**
21 | * 幂等
22 | * @return
23 | */
24 | boolean Idempotent() default false;
25 |
26 | long expertime() default 3L;
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/aop/QueryAspect.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.aop;
2 |
3 | import com.github.pagehelper.Page;
4 | import com.muggle.poseidon.base.BaseQuery;
5 | import com.muggle.poseidon.base.ResultBean;
6 | import com.muggle.poseidon.handler.query.QuerySqlProcessor;
7 | import org.apache.commons.logging.Log;
8 | import org.apache.commons.logging.LogFactory;
9 | import org.aspectj.lang.JoinPoint;
10 | import org.aspectj.lang.annotation.AfterReturning;
11 | import org.aspectj.lang.annotation.Aspect;
12 | import org.aspectj.lang.annotation.Before;
13 | import org.aspectj.lang.annotation.Pointcut;
14 | import org.springframework.beans.factory.annotation.Autowired;
15 |
16 | /**
17 | * @Description:
18 | * @Author: muggle
19 | * @Date: 2020/6/6
20 | **/
21 |
22 | @Aspect
23 | public class QueryAspect {
24 |
25 | @Autowired(required = false)
26 | QuerySqlProcessor sqlProcessor;
27 | private static final Log log = LogFactory.getLog(QueryAspect.class);
28 |
29 | public QueryAspect() {
30 | log.info(">>>>>>>>>>>>>>>>>>>>>>> 查询切面注册 <<<<<<<<<<<<<<<<<<<<<");
31 | }
32 |
33 | @Pointcut("execution(* *..*.*Controller.*(com.muggle.poseidon.base.BaseQuery+))")
34 | public void query() {
35 | }
36 |
37 | @Before("query()")
38 | public void doBefore(JoinPoint joinPoint) {
39 | Object[] args = joinPoint.getArgs();
40 | if (args.length < 1) {
41 | return;
42 | }
43 | for (Object arg : args) {
44 | if (arg instanceof BaseQuery) {
45 | BaseQuery query = (BaseQuery) arg;
46 | query.init();
47 | if (sqlProcessor != null) {
48 | sqlProcessor.beforeQuery(query);
49 | }
50 | query.processSql();
51 | }
52 | }
53 | }
54 |
55 | @AfterReturning(pointcut = "query()", returning = "result")
56 | public void doAfterReturning(JoinPoint joinPoint, Object result) {
57 | if (result == null) {
58 | return;
59 | }
60 | if (result instanceof ResultBean) {
61 | Object data = ((ResultBean) result).getData();
62 | if (sqlProcessor != null) {
63 | sqlProcessor.afterReturningQuery((ResultBean) result);
64 | }
65 | if (data instanceof Page) {
66 | ((ResultBean) result).setTotal(((Page) data).getTotal());
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/aop/RequestAspect.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.aop;
2 |
3 | import jakarta.servlet.http.HttpServletRequest;
4 |
5 | import com.muggle.poseidon.annotation.InterfaceAction;
6 | import com.muggle.poseidon.base.DistributedLocker;
7 | import com.muggle.poseidon.base.exception.BasePoseidonCheckException;
8 | import com.muggle.poseidon.base.exception.SimplePoseidonException;
9 | import com.muggle.poseidon.handler.security.RequestLogProcessor;
10 | import com.muggle.poseidon.util.RequestUtils;
11 | import com.muggle.poseidon.util.UserInfoUtils;
12 | import org.apache.commons.logging.Log;
13 | import org.apache.commons.logging.LogFactory;
14 | import org.aspectj.lang.JoinPoint;
15 | import org.aspectj.lang.annotation.AfterReturning;
16 | import org.aspectj.lang.annotation.Aspect;
17 | import org.aspectj.lang.annotation.Before;
18 | import org.aspectj.lang.annotation.Pointcut;
19 | import org.aspectj.lang.reflect.MethodSignature;
20 | import org.springframework.security.core.Authentication;
21 | import org.springframework.security.core.context.SecurityContextHolder;
22 | import org.springframework.security.core.userdetails.UserDetails;
23 | import org.springframework.web.context.request.RequestContextHolder;
24 | import org.springframework.web.context.request.ServletRequestAttributes;
25 |
26 |
27 | /**
28 | * @description: 日志aop类
29 | * @author: muggle
30 | * @create: 2019-12-26 16:40
31 | */
32 | @Aspect
33 | public class RequestAspect {
34 | private DistributedLocker locker;
35 |
36 | private RequestLogProcessor logProcessor;
37 |
38 | public RequestAspect(DistributedLocker locker, RequestLogProcessor logProcessor) {
39 | this.logProcessor = logProcessor;
40 | this.locker = locker;
41 | log.info(">>>>>>>>>>>>>>>>>>>>>>>[请求日志切面初始化]<<<<<<<<<<<<<<<<<<<<<");
42 | }
43 |
44 | private static final Log log = LogFactory.getLog(RequestAspect.class);
45 |
46 | @Pointcut("@annotation(com.muggle.poseidon.annotation.InterfaceAction)")
47 | public void request() {
48 | }
49 |
50 | @Before("request()")
51 | public void doBefore(JoinPoint joinPoint) {
52 | log.debug(">>>>>>>>>>>>>>>>>>>>>>> 请求日志切面 dobefore <<<<<<<<<<<<<<<<<<<<<");
53 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
54 | HttpServletRequest request = attributes.getRequest();
55 | this.verifyIdempotent(joinPoint);
56 | //参数
57 | Object[] args = joinPoint.getArgs();
58 | StringBuilder stringBuilder = new StringBuilder();
59 | for (Object arg : args) {
60 | stringBuilder.append(" (").append(arg.toString()).append(") ");
61 | }
62 |
63 | String userMessage = "用户名:%s";
64 | try {
65 | UserDetails userInfo = UserInfoUtils.getUserInfo();
66 | userMessage = String.format(userMessage, userInfo == null ? "用户未登录" : userInfo.getUsername());
67 | } catch (BasePoseidonCheckException e) {
68 | userMessage = String.format(userMessage, "非法的登录用户");
69 | }
70 | log.info("》》》》》》 请求日志 " + userMessage + " url=" + request.getRequestURI() + "method=" + request.getMethod() + "ip=" + request.getRemoteAddr()
71 | + "host=" + request.getRemoteHost() + "port=" + request.getRemotePort()
72 | + "classMethod=" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()
73 | + "paramters [ " + stringBuilder.toString() + " ]");
74 | if (logProcessor != null) {
75 | logProcessor.recordBefore(request, joinPoint.getArgs());
76 | }
77 | }
78 |
79 | /**
80 | * 幂等操作 @param joinPoint
81 | */
82 | private void verifyIdempotent(JoinPoint joinPoint) {
83 | InterfaceAction annotation = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(InterfaceAction.class);
84 | boolean idempotent = annotation.Idempotent();
85 | if (idempotent) {
86 | log.debug(">>>>>>>>>>>>>>>>>>>>>>> 幂等操作 <<<<<<<<<<<<<<<<<<<<<");
87 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
88 | HttpServletRequest request = attributes.getRequest();
89 | String requestURI = request.getRequestURI();
90 | String remoteAddr = RequestUtils.getIP(request);
91 | log.info(String.format("请求进入幂等方法,开始尝试上锁 uri: %s ip:%s", requestURI, remoteAddr));
92 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
93 | String username = "notSignin";
94 | if (authentication != null && authentication.getPrincipal() == null) {
95 | username = authentication.getPrincipal().toString();
96 | }
97 | String key = "lock:idempotent:" + request.getRequestURI() + ":" + username + ":" + RequestUtils.getIP(request);
98 | long expertime = annotation.expertime();
99 | log.info("冪等上锁 key :" + key);
100 | boolean trylock = false;
101 | try {
102 | trylock = locker.tryLock(key, expertime);
103 | } catch (InterruptedException e) {
104 | log.error(e);
105 | }
106 | if (!trylock) {
107 | String message = annotation.message();
108 | log.info(">>>>>>>>>>>>>>>>>>>>>> 获取幂等锁获取锁失败 key:" + key + " <<<<<<<<<<<<<<<<<<<<<<<");
109 | throw new SimplePoseidonException(message);
110 | }
111 | }
112 | }
113 |
114 |
115 | @AfterReturning(pointcut = "request()", returning = "result")
116 | public void doAfterReturning(JoinPoint joinPoint, Object result) {
117 | log.debug(">>>>>>>>>>>>>>>>>>>>>> 操作日志,返回值切面执行 <<<<<<<<<<<<<<<<<<<<<<< ");
118 | if (logProcessor != null) {
119 | logProcessor.recordAfterReturning(result, joinPoint.getArgs());
120 | }
121 | }
122 | }
123 |
124 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/auto/ExpansibilityConfig.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.auto;
2 |
3 |
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.context.annotation.Configuration;
8 |
9 | /**
10 | * 二次开发的扩展配置类
11 | * muggle
12 | */
13 |
14 | @ConditionalOnProperty(prefix = "poseidon", name = "auto", havingValue = "true", matchIfMissing = false)
15 | @Configuration
16 | //@ConditionalOnProperty(TokenService.class)
17 | public class ExpansibilityConfig {
18 |
19 | /**
20 | * logger
21 | */
22 | private static final Logger log = LoggerFactory.getLogger(ExpansibilityConfig.class);
23 |
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/auto/PoseidonSecurityProperties.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.auto;
2 |
3 | import java.util.List;
4 |
5 | import org.springframework.boot.context.properties.ConfigurationProperties;
6 |
7 | /**
8 | * @program: poseidon-cloud-starter
9 | * @description:
10 | * @author: muggle
11 | * @create: 2019-11-04
12 | **/
13 |
14 | @ConfigurationProperties(prefix = "poseidon")
15 | public class PoseidonSecurityProperties {
16 |
17 | /**
18 | * 放行的url
19 | **/
20 | private List ignorePath;
21 |
22 | private List staticPath;
23 |
24 | public List getStaticPath() {
25 | return staticPath;
26 | }
27 |
28 | public void setStaticPath(List staticPath) {
29 | this.staticPath = staticPath;
30 | }
31 |
32 | public List getIgnorePath() {
33 |
34 | return ignorePath;
35 | }
36 |
37 | public void setIgnorePath(List ignorePath) {
38 | this.ignorePath = ignorePath;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/auto/SecurityAutoConfig.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.auto;
2 |
3 | import java.lang.annotation.Annotation;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | import com.muggle.poseidon.adapter.PoseidonAuthConfigAdapter;
9 | import com.muggle.poseidon.aop.RequestAspect;
10 | import com.muggle.poseidon.base.DistributedLocker;
11 | import com.muggle.poseidon.base.exception.SimplePoseidonException;
12 | import com.muggle.poseidon.entity.AuthUrlPathDO;
13 | import com.muggle.poseidon.handler.security.RequestLogProcessor;
14 | import com.muggle.poseidon.service.TokenService;
15 | import com.muggle.poseidon.store.SecurityStore;
16 | import io.swagger.annotations.Api;
17 | import io.swagger.annotations.ApiOperation;
18 | import org.apache.commons.logging.Log;
19 | import org.apache.commons.logging.LogFactory;
20 | import org.springframework.beans.factory.annotation.Autowired;
21 | import org.springframework.boot.CommandLineRunner;
22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
24 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
25 | import org.springframework.boot.web.server.ErrorPage;
26 | import org.springframework.boot.web.server.WebServerFactoryCustomizer;
27 | import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
28 | import org.springframework.context.ApplicationContext;
29 | import org.springframework.context.annotation.Bean;
30 | import org.springframework.context.annotation.Configuration;
31 | import org.springframework.context.annotation.Profile;
32 | import org.springframework.http.HttpStatus;
33 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
34 | import org.springframework.security.web.SecurityFilterChain;
35 | import org.springframework.web.bind.annotation.RequestMapping;
36 | import org.springframework.web.bind.annotation.RequestMethod;
37 | import org.springframework.web.context.WebApplicationContext;
38 | import org.springframework.web.method.HandlerMethod;
39 | import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
40 | import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
41 | import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
42 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
43 |
44 | /**
45 | * @program: poseidon-cloud-starter
46 | * @description: 自动化配置核心类
47 | * @author: muggle
48 | * @create: 2019-11-04
49 | **/
50 |
51 | @Configuration
52 | @EnableConfigurationProperties(PoseidonSecurityProperties.class)
53 | @ConditionalOnProperty(prefix = "poseidon", name = "auto", havingValue = "true", matchIfMissing = false)
54 | //@ConditionalOnProperty(TokenService.class)
55 | @SuppressWarnings("ALL")
56 | public class SecurityAutoConfig {
57 | private static final Log log = LogFactory.getLog(SecurityAutoConfig.class);
58 |
59 | @Autowired
60 | PoseidonSecurityProperties properties;
61 |
62 | @Autowired
63 | private WebApplicationContext applicationContext;
64 |
65 | @Autowired(required = false)
66 | RequestLogProcessor logProcessor;
67 |
68 | @Bean
69 | public PoseidonAuthConfigAdapter getAdapter(TokenService tokenService, SecurityStore securityStore) {
70 | log.info(">>>>>>>>>>>>>>>>>>>>>>> 开启自动化配置 <<<<<<<<<<<<<<<<<<<<<");
71 | if (securityStore == null) {
72 | throw new SimplePoseidonException("请先注册 securityStore");
73 | }
74 | return new PoseidonAuthConfigAdapter(tokenService, securityStore, properties);
75 | }
76 |
77 | /**
78 | * 测试和生产环境生效
79 | *
80 | * @param tokenService
81 | * @return
82 | */
83 | @Bean
84 | @Profile({"uat", "sit", "online", "refresh"})
85 | public CommandLineRunner init(final TokenService tokenService, ApplicationContext context) {
86 | return new CommandLineRunner() {
87 | @Override
88 | public void run(String... strings) throws Exception {
89 | String property = context.getEnvironment().getProperty("log.dir");
90 | if (property==null){
91 | throw new SimplePoseidonException(">>>>>>>>>>>>>>>>>>>>>>> application-log.dir 未配置 <<<<<<<<<<<<<<<<<<<<<");
92 | }
93 | log.info(">>>>>>>>>>>>>>>>>>>>>>> 权限系统开机任务执行 <<<<<<<<<<<<<<<<<<<<<");
94 | List allURL = getAllURL();
95 | tokenService.processUrl(allURL);
96 | }
97 | };
98 | }
99 |
100 | /**
101 | * 读取所有的url 并交给tokenService.saveUrlInfo处理
102 | **/
103 | public List getAllURL() {
104 | List resultList = new ArrayList<>();
105 |
106 | RequestMappingHandlerMapping requestMappingHandlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
107 | // 获取url与类和方法的对应信息
108 | Map map = requestMappingHandlerMapping.getHandlerMethods();
109 |
110 | for (Map.Entry mappingInfoHandlerMethodEntry : map.entrySet()) {
111 |
112 | RequestMappingInfo requestMappingInfo = mappingInfoHandlerMethodEntry.getKey();
113 | HandlerMethod handlerMethod = mappingInfoHandlerMethodEntry.getValue();
114 | AuthUrlPathDO authUrlPathDO = new AuthUrlPathDO();
115 | // 类名
116 | authUrlPathDO.setClassName(handlerMethod.getMethod().getDeclaringClass().getName());
117 |
118 | Annotation[] parentAnnotations = handlerMethod.getBeanType().getAnnotations();
119 | for (Annotation annotation : parentAnnotations) {
120 | if (annotation instanceof Api) {
121 | Api api = (Api) annotation;
122 | authUrlPathDO.setClassDesc(api.value());
123 | } else if (annotation instanceof RequestMapping) {
124 | RequestMapping requestMapping = (RequestMapping) annotation;
125 | if (null != requestMapping.value() && requestMapping.value().length > 0) {
126 | //类URL
127 | authUrlPathDO.setClassUrl(requestMapping.value()[0]);
128 | }
129 | }
130 | }
131 | // 方法名
132 | authUrlPathDO.setMethodName(handlerMethod.getMethod().getName());
133 | Annotation[] annotations = handlerMethod.getMethod().getDeclaredAnnotations();
134 | if (annotations != null) {
135 | // 处理具体的方法信息
136 | for (Annotation annotation : annotations) {
137 | if (annotation instanceof ApiOperation) {
138 | ApiOperation methodDesc = (ApiOperation) annotation;
139 | String desc = methodDesc.value();
140 | //接口描述
141 | authUrlPathDO.setMethodDesc(desc);
142 | }
143 | }
144 | }
145 | PatternsRequestCondition p = requestMappingInfo.getPatternsCondition();
146 | for (String url : p.getPatterns()) {
147 | //请求URL
148 | authUrlPathDO.setMethodURL(url);
149 | }
150 | RequestMethodsRequestCondition methodsCondition = requestMappingInfo.getMethodsCondition();
151 | for (RequestMethod requestMethod : methodsCondition.getMethods()) {
152 | //请求方式:POST/PUT/GET/DELETE
153 | authUrlPathDO.setRequestType(requestMethod.toString());
154 | }
155 | resultList.add(authUrlPathDO);
156 | }
157 | return resultList;
158 | }
159 |
160 | @Bean
161 | @Autowired
162 | @ConditionalOnBean(DistributedLocker.class)
163 | public RequestAspect getLogAspect(DistributedLocker distributedLocker) {
164 | log.info(">>>>>>>>>>>>>>>>>>>>>>> 日志切面注册 <<<<<<<<<<<<<<<<<<<<<");
165 | return new RequestAspect(distributedLocker, logProcessor);
166 | }
167 |
168 |
169 | // 配置错误页面
170 | @Bean
171 | public WebServerFactoryCustomizer containerCustomizer() {
172 | return new WebServerFactoryCustomizer() {
173 | @Override
174 | public void customize(ConfigurableServletWebServerFactory factory) {
175 | log.info(">>>>>>>>>>>>>>>>>>>>>>> 错误页面配置——404(/public/notfound) 500(/error_message) <<<<<<<<<<<<<<<<<<<<<");
176 | factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/public/notfound"), new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error_message"));
177 | }
178 | };
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/BaseBean.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base;
2 |
3 | /**
4 | * @program: poseidon-cloud-starter
5 | * @description: base pojo
6 | * @author: muggle
7 | * @create: 2019-11-05
8 | **/
9 |
10 | public abstract class BaseBean {
11 |
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/BaseController.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base;
2 |
3 | /**
4 | * @Description:
5 | * @Author: muggle
6 | * @Date: 2020/11/11
7 | **/
8 | public abstract class BaseController {
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/BaseQuery.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base;
2 |
3 | import java.util.List;
4 | import java.util.Map;
5 |
6 | import com.github.pagehelper.PageHelper;
7 | import org.springframework.util.CollectionUtils;
8 |
9 | /**
10 | * @Description:
11 | * @Author: muggle
12 | * @Date: 2020/6/5
13 | **/
14 |
15 | public abstract class BaseQuery {
16 |
17 | private List orderBy;
18 |
19 | private List groupBy;
20 |
21 | private Map operatorMap;
22 |
23 | private Sort sort = Sort.DESC;
24 |
25 | private int startPage = 1;
26 |
27 | private int pageSize = 10;
28 |
29 |
30 | public void init() {
31 | PageHelper.startPage(startPage, pageSize);
32 | if (!CollectionUtils.isEmpty(orderBy)) {
33 | String join = String.join(",", orderBy);
34 | PageHelper.orderBy(join + " " + sort);
35 | }
36 | }
37 |
38 | /**
39 | * sql 转化
40 | *
41 | * @param
42 | */
43 | public abstract void processSql();
44 |
45 | /**
46 | * 在mybati中使用sql注入 形如 where ${finalSql}
47 | *
48 | * @return
49 | */
50 | public abstract String getFinalSql();
51 |
52 |
53 | public enum Sort {
54 | DESC, ASC
55 | }
56 |
57 | /**
58 | * 运算符
59 | */
60 | public enum Operator {
61 | equals("=%s "),
62 | notEqual("<>%s "),
63 | moreThan(">%s "),
64 | lessThan("<%s "),
65 | leftLike("LIKE '%s%%' "),
66 | notNull("%s IS NOT NULL "),
67 | isNull("%s IS NULL "),
68 | in("in (%s) "),
69 | allLike("LIKE '%%%s%%' ");
70 |
71 | private String value;
72 |
73 | Operator(String value) {
74 | this.value = value;
75 | }
76 |
77 | public String getValue() {
78 | return value;
79 | }
80 |
81 | public void setValue(String value) {
82 | this.value = value;
83 | }
84 | }
85 |
86 |
87 | public List getOrderBy() {
88 | return orderBy;
89 | }
90 |
91 | public void setOrderBy(List orderBy) {
92 | this.orderBy = orderBy;
93 | }
94 |
95 | public List getGroupBy() {
96 | return groupBy;
97 | }
98 |
99 | public void setGroupBy(List groupBy) {
100 | this.groupBy = groupBy;
101 | }
102 |
103 | public Map getOperatorMap() {
104 | return operatorMap;
105 | }
106 |
107 | public void setOperatorMap(Map operatorMap) {
108 | this.operatorMap = operatorMap;
109 | }
110 |
111 | public Sort getSort() {
112 | return sort;
113 | }
114 |
115 | public void setSort(Sort sort) {
116 | this.sort = sort;
117 | }
118 |
119 | public int getStartPage() {
120 | return startPage;
121 | }
122 |
123 | public void setStartPage(int startPage) {
124 | this.startPage = startPage;
125 | }
126 |
127 | public int getPageSize() {
128 | return pageSize;
129 | }
130 |
131 | public void setPageSize(int pageSize) {
132 | this.pageSize = pageSize;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/BaseService.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base;
2 |
3 | /**
4 | * @program: poseidon-cloud-starter
5 | * @description:
6 | * @author: muggle
7 | * @create: 2019-11-05
8 | **/
9 |
10 | public abstract class BaseService {
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/CommonQuery.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base;
2 |
3 | import java.lang.reflect.Field;
4 | import java.util.Iterator;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | import com.muggle.poseidon.base.exception.SimplePoseidonException;
9 | import org.springframework.util.CollectionUtils;
10 |
11 | /**
12 | * @Description:
13 | * @Author: muggle
14 | * @Date: 2020/6/6
15 | **/
16 | public class CommonQuery extends BaseQuery {
17 |
18 | private String finalSql;
19 |
20 | @Override
21 | public void processSql() {
22 | Map operatorMap = this.getOperatorMap();
23 | StringBuilder builder = new StringBuilder();
24 | if (operatorMap != null) {
25 | Iterator iterator = operatorMap.keySet().iterator();
26 | while (iterator.hasNext()) {
27 | String next = iterator.next();
28 | try {
29 | Object field = getFieldValue(next);
30 | Operator operator = operatorMap.get(next);
31 | builder.append("AND ");
32 | if ((field instanceof Number || Operator.leftLike.equals(operator) || Operator.allLike.equals(operator))) {
33 | builder.append(String.format(next + " " + operator.getValue(), field));
34 | } else {
35 | builder.append(String.format(next + " " + operator.getValue(), "'" + field + "'"));
36 | }
37 | } catch (NoSuchFieldException | IllegalAccessException e) {
38 | throw new SimplePoseidonException("查询参数异常:" + next);
39 | }
40 | }
41 | }
42 |
43 | List groupBy = this.getGroupBy();
44 | if (!CollectionUtils.isEmpty(groupBy)) {
45 | builder.append(" group by");
46 | for (int i = 0; i < groupBy.size(); i++) {
47 | if (i == groupBy.size() - 1) {
48 | builder.append(groupBy.get(i));
49 | } else {
50 | builder.append(groupBy.get(i) + ",");
51 | }
52 | }
53 | }
54 | this.finalSql = builder.toString();
55 | }
56 |
57 | private Object getFieldValue(String next) throws NoSuchFieldException, IllegalAccessException {
58 | Field field = this.getClass().getDeclaredField(next);
59 | //打开私有访问
60 | field.setAccessible(true);
61 | //获取属性值
62 | return field.get(this);
63 | }
64 |
65 | @Override
66 | public String getFinalSql() {
67 | return finalSql;
68 | }
69 |
70 | public void setFinalSql(String finalSql) {
71 | this.finalSql = finalSql;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/DistributedLocker.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base;
2 |
3 | import java.util.concurrent.locks.Lock;
4 |
5 | /**
6 | * @program: poseidon-cloud-starter
7 | * @description:
8 | * @author: muggle
9 | * @create: 2019-12-31
10 | **/
11 |
12 | public interface DistributedLocker extends Lock {
13 |
14 | /**
15 | * 锁
16 | * @param key
17 | * @param expertime
18 | * @return
19 | */
20 | boolean tryLock(String key, long expertime) throws InterruptedException;
21 |
22 | /**
23 | * 阻塞
24 | */
25 | void lock(String key);
26 |
27 | /**
28 | * 解锁
29 | */
30 | void unlock(String key);
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/ErrorCode.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base;
2 |
3 | public class ErrorCode {
4 | public static final ErrorCode JSON_ERROR =new ErrorCode("json序列化异常",1001);
5 | private String message;
6 | private int code;
7 |
8 | ErrorCode(String message, int code) {
9 | this.message = message;
10 | this.code = code;
11 | }
12 |
13 | public String getMessage() {
14 | return message;
15 | }
16 |
17 | public void setMessage(String message) {
18 | this.message = message;
19 | }
20 |
21 | public int getCode() {
22 | return code;
23 | }
24 |
25 | public void setCode(int code) {
26 | this.code = code;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/ResultBean.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base;
2 |
3 |
4 | import java.io.Serializable;
5 |
6 |
7 | /**
8 | * @program: poseidon-cloud-starter
9 | * @description:
10 | * @author: muggle
11 | * @create: 2019-11-05
12 | **/
13 |
14 | public class ResultBean implements Serializable {
15 |
16 | private static final long serialVersionUID = 1553485005784190508L;
17 | private String message;
18 | private Integer code;
19 | private T data;
20 | private Long total;
21 |
22 | public String getMessage() {
23 | return message;
24 | }
25 |
26 | public void setMessage(String message) {
27 | this.message = message;
28 | }
29 |
30 | public Integer getCode() {
31 | return code;
32 | }
33 |
34 | public void setCode(Integer code) {
35 | this.code = code;
36 | }
37 |
38 | public T getData() {
39 | return data;
40 | }
41 |
42 | public void setData(T data) {
43 | this.data = data;
44 | }
45 |
46 | private ResultBean(String message, Integer code, T data) {
47 | this.code = code;
48 | this.message = message;
49 | this.data = data;
50 | }
51 |
52 | private ResultBean(String message, Integer code) {
53 | this.code = code;
54 | this.message = message;
55 | }
56 |
57 |
58 | public static ResultBean getInstance(String message, Integer code, T data) {
59 | return new ResultBean<>(message, code, data);
60 | }
61 |
62 | public static ResultBean getInstance(String message, Integer code) {
63 | return new ResultBean<>(message, code);
64 | }
65 |
66 | public static ResultBean success() {
67 | return new ResultBean<>("请求成功", 200);
68 | }
69 |
70 | public static ResultBean success(String message) {
71 | return new ResultBean<>(message, 200);
72 | }
73 |
74 | public static ResultBean error(String message) {
75 | return new ResultBean<>(message, 5001);
76 | }
77 |
78 | public static ResultBean error(String message, Integer code) {
79 | return new ResultBean<>(message, code);
80 | }
81 |
82 | public static ResultBean successData(T data) {
83 | return new ResultBean<>("请求成功", 200, data);
84 | }
85 |
86 |
87 | public ResultBean() {
88 |
89 | }
90 |
91 | public Long getTotal() {
92 | return total;
93 | }
94 |
95 | public void setTotal(Long total) {
96 | this.total = total;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/exception/BasePoseidonCheckException.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base.exception;
2 |
3 |
4 | /**
5 | * @program: poseidon-cloud-starter
6 | * @description:
7 | * @author: muggle
8 | * @create: 2019-11-06
9 | **/
10 |
11 | public abstract class BasePoseidonCheckException extends Exception {
12 |
13 | public BasePoseidonCheckException(String message) {
14 | super(message);
15 | }
16 |
17 | public abstract Integer getCode();
18 |
19 | public BasePoseidonCheckException(Throwable e){
20 | super(e);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/exception/BasePoseidonException.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base.exception;
2 |
3 | /**
4 | * @program: poseidon-cloud-starter
5 | * @description: 业务异常
6 | * @author: muggle
7 | * @create: 2019-11-05
8 | **/
9 |
10 | public abstract class BasePoseidonException extends RuntimeException {
11 |
12 | public BasePoseidonException(String message) {
13 | super(message);
14 | }
15 | public BasePoseidonException(Throwable e){
16 | super(e);
17 | }
18 |
19 | public abstract Integer getCode();
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/exception/SimplePoseidonCheckException.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base.exception;
2 |
3 | /**
4 | * @program: poseidon-cloud-starter
5 | * @description:
6 | * @author: muggle
7 | * @create: 2019-11-06
8 | **/
9 |
10 | public class SimplePoseidonCheckException extends BasePoseidonCheckException {
11 | private Integer code;
12 |
13 | public SimplePoseidonCheckException(String message) {
14 | super(message);
15 | this.code = 5001;
16 | }
17 |
18 | public SimplePoseidonCheckException(String message, Integer code) {
19 | super(message);
20 | this.code = code;
21 | }
22 |
23 | public SimplePoseidonCheckException(Throwable e) {
24 | super(e);
25 | this.code=5001;
26 | }
27 |
28 | @Override
29 | public Integer getCode() {
30 | return code;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/exception/SimplePoseidonException.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base.exception;
2 |
3 | import com.muggle.poseidon.base.ErrorCode;
4 |
5 | /**
6 | * @program: poseidon-cloud-starter
7 | * @description: 通用业务异常
8 | * @author: muggle
9 | * @create: 2019-11-05
10 | **/
11 |
12 | public class SimplePoseidonException extends BasePoseidonException {
13 |
14 | private Integer code;
15 |
16 | public SimplePoseidonException(String message, Integer code) {
17 | super(message);
18 | this.code = code;
19 | }
20 |
21 | public SimplePoseidonException(String message) {
22 | super(message);
23 | this.code = 5001;
24 | }
25 |
26 | public SimplePoseidonException(Throwable e){
27 | super(e);
28 | this.code=5001;
29 | }
30 |
31 | public SimplePoseidonException(ErrorCode errorCode) {
32 | super(errorCode.getMessage());
33 | this.code=errorCode.getCode();
34 | }
35 |
36 | @Override
37 | public Integer getCode() {
38 | return code;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/base/query/CommonQueryBean.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.base.query;
2 |
3 | import java.util.Map;
4 |
5 | /**
6 | * @Description:
7 | * @Author: muggle
8 | * @Date: 2020/5/20
9 | **/
10 | public class CommonQueryBean {
11 | private T data;
12 |
13 | private Map operator;
14 |
15 | private String orderBy ;
16 |
17 | private int start;
18 |
19 | private int pageSize;
20 |
21 | private String groupBy;
22 |
23 | public String getSql(){
24 | return null;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/entity/AuthUrlPathDO.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.entity;
2 |
3 | /**
4 | * @program: poseidon-cloud-starter
5 | * @description: 用于保存所有的url
6 | * @author: muggle
7 | * @create: 2019-11-05
8 | **/
9 |
10 | public class AuthUrlPathDO {
11 |
12 | private String methodURL;
13 |
14 | private String methodDesc;
15 |
16 | private String requestType;
17 |
18 | private String application;
19 |
20 | private String className;
21 |
22 | private String classDesc;
23 |
24 | private String classUrl;
25 |
26 | private String methodName;
27 |
28 | public String getMethodURL() {
29 | return methodURL;
30 | }
31 |
32 | public void setMethodURL(String methodURL) {
33 | this.methodURL = methodURL;
34 | }
35 |
36 | public String getMethodDesc() {
37 | return methodDesc;
38 | }
39 |
40 | public void setMethodDesc(String methodDesc) {
41 | this.methodDesc = methodDesc;
42 | }
43 |
44 | public String getRequestType() {
45 | return requestType;
46 | }
47 |
48 | public void setRequestType(String requestType) {
49 | this.requestType = requestType;
50 | }
51 |
52 | public String getApplication() {
53 | return application;
54 | }
55 |
56 | public void setApplication(String application) {
57 | this.application = application;
58 | }
59 |
60 | public String getClassName() {
61 | return className;
62 | }
63 |
64 | public void setClassName(String className) {
65 | this.className = className;
66 | }
67 |
68 | public String getClassDesc() {
69 | return classDesc;
70 | }
71 |
72 | public void setClassDesc(String classDesc) {
73 | this.classDesc = classDesc;
74 | }
75 |
76 | public String getClassUrl() {
77 | return classUrl;
78 | }
79 |
80 | public void setClassUrl(String classUrl) {
81 | this.classUrl = classUrl;
82 | }
83 |
84 | public String getMethodName() {
85 | return methodName;
86 | }
87 |
88 | public void setMethodName(String methodName) {
89 | this.methodName = methodName;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/entity/RequestInfoDO.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.entity;
2 |
3 | /**
4 | * @Description:
5 | * @Author: muggle
6 | * @Date: 2020/4/5$
7 | **/
8 | public class RequestInfoDO {
9 | private String username;
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/filter/SecurityLoginFilter.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.filter;
2 |
3 | import jakarta.servlet.http.HttpServletRequest;
4 | import jakarta.servlet.http.HttpServletResponse;
5 |
6 | import com.muggle.poseidon.base.exception.SimplePoseidonCheckException;
7 | import com.muggle.poseidon.service.TokenService;
8 | import com.muggle.poseidon.store.SecurityStore;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.springframework.security.authentication.AuthenticationServiceException;
12 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
13 | import org.springframework.security.core.Authentication;
14 | import org.springframework.security.core.AuthenticationException;
15 | import org.springframework.security.core.userdetails.UserDetails;
16 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
17 |
18 | /**
19 | * @program: poseidon-cloud-starter
20 | * @description: 登陆过滤器
21 | * @author: muggle
22 | * @create: 2019-11-07
23 | **/
24 |
25 | public class SecurityLoginFilter extends UsernamePasswordAuthenticationFilter {
26 | private TokenService tokenService;
27 |
28 | private SecurityStore securityStore;
29 |
30 |
31 | static Logger logger = LoggerFactory.getLogger(SecurityLoginFilter.class);
32 |
33 | public SecurityLoginFilter(TokenService tokenService, SecurityStore securityStore) {
34 | this.tokenService = tokenService;
35 | this.securityStore = securityStore;
36 | }
37 |
38 | @Override
39 | public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
40 | try {
41 | UserDetails login = tokenService.login(request, response);
42 | String token = securityStore.signUserMessage(login);
43 | return new UsernamePasswordAuthenticationToken(token, "");
44 | } catch (SimplePoseidonCheckException e) {
45 | throw new AuthenticationServiceException(e.getMessage());
46 | } catch (Exception e) {
47 | logger.error("系统异常:", e);
48 | throw new AuthenticationServiceException("系统异常");
49 | }
50 |
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/filter/SecurityTokenFilter.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.filter;
2 |
3 |
4 | import jakarta.servlet.FilterChain;
5 | import jakarta.servlet.ServletException;
6 | import jakarta.servlet.http.Cookie;
7 | import jakarta.servlet.http.HttpServletRequest;
8 | import jakarta.servlet.http.HttpServletResponse;
9 | import java.io.IOException;
10 |
11 | import com.muggle.poseidon.auto.PoseidonSecurityProperties;
12 | import com.muggle.poseidon.base.exception.BasePoseidonCheckException;
13 | import com.muggle.poseidon.properties.SecurityMessageProperties;
14 | import com.muggle.poseidon.store.SecurityStore;
15 | import org.slf4j.Logger;
16 | import org.slf4j.LoggerFactory;
17 | import org.springframework.security.access.AccessDeniedException;
18 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
19 | import org.springframework.security.core.context.SecurityContextHolder;
20 | import org.springframework.security.core.userdetails.UserDetails;
21 | import org.springframework.util.AntPathMatcher;
22 | import org.springframework.web.filter.OncePerRequestFilter;
23 |
24 | /**
25 | * @program: poseidon-cloud-starter
26 | * @description: token认证填充用户信息
27 | * @author: muggle
28 | * @create: 2019-11-04
29 | **/
30 |
31 | public class SecurityTokenFilter extends OncePerRequestFilter {
32 |
33 | private SecurityStore securityStore;
34 |
35 | private AntPathMatcher pathMatcher = new AntPathMatcher();
36 |
37 | private PoseidonSecurityProperties properties;
38 |
39 |
40 | /**
41 | * logger
42 | */
43 | private static final Logger log = LoggerFactory.getLogger(SecurityTokenFilter.class);
44 |
45 | public SecurityTokenFilter(SecurityStore securityStore, PoseidonSecurityProperties properties) {
46 | this.properties = properties;
47 | this.securityStore = securityStore;
48 | }
49 |
50 | /**
51 | * 该过滤器会首先从请求头中获取token,如果获取失败则会从cookie 中获取token,key都是 token
52 | *
53 | * @param httpServletRequest
54 | * @param httpServletResponse
55 | * @param filterChain
56 | * @throws ServletException
57 | * @throws IOException
58 | * @throws AccessDeniedException
59 | */
60 | @Override
61 | protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException, AccessDeniedException {
62 | log.debug(">>>>>>>>>>>>>>>>>>>>>>> 开始校验token <<<<<<<<<<<<<<<<<<<<<");
63 | String token = httpServletRequest.getHeader("token");
64 | Cookie[] cookies = httpServletRequest.getCookies();
65 | String cookieToken = null;
66 | if (cookies != null) {
67 | for (Cookie cookie : cookies) {
68 | if (cookie.getName().equals("token")) {
69 | cookieToken = cookie.getValue();
70 | }
71 | }
72 | }
73 | if (token == null && cookieToken == null) {
74 | filterChain.doFilter(httpServletRequest, httpServletResponse);
75 | return;
76 | }
77 |
78 | UserDetails userDetails = null;
79 | try {
80 | userDetails = securityStore.getUserdetail(token == null ? cookieToken : token);
81 | } catch (BasePoseidonCheckException e) {
82 | log.error("》》》》 用户凭证为badToken {}", e.getMessage());
83 | SecurityContextHolder.getContext().setAuthentication(getBadToken(e.getMessage()));
84 | filterChain.doFilter(httpServletRequest, httpServletResponse);
85 | return;
86 | } catch (Exception e) {
87 | log.error("》》》》 token 解析异常:", e);
88 | SecurityContextHolder.getContext().setAuthentication(getBadToken("请求信息非法,无法解析Token"));
89 | filterChain.doFilter(httpServletRequest, httpServletResponse);
90 | return;
91 | }
92 |
93 | if (userDetails == null) {
94 | log.error("该用户不存在, token:{}", token);
95 | SecurityContextHolder.getContext().setAuthentication(getBadToken("该用户不存在,请重新登录"));
96 | filterChain.doFilter(httpServletRequest, httpServletResponse);
97 | return;
98 | }
99 | UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
100 | authenticationToken.setDetails(userDetails);
101 | SecurityContextHolder.getContext().setAuthentication(authenticationToken);
102 | log.debug("》》》》 填充token");
103 | filterChain.doFilter(httpServletRequest, httpServletResponse);
104 | }
105 |
106 | private UsernamePasswordAuthenticationToken getBadToken(String message) {
107 | UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(SecurityMessageProperties.BAD_TOKEN, null, null);
108 | authenticationToken.setDetails(message);
109 | return authenticationToken;
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/handler/query/QuerySqlProcessor.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.handler.query;
2 |
3 | import com.muggle.poseidon.base.BaseQuery;
4 | import com.muggle.poseidon.base.ResultBean;
5 |
6 | /**
7 | * @Description:
8 | * @Author: muggle
9 | * @Date: 2020/6/8
10 | **/
11 | public interface QuerySqlProcessor {
12 |
13 | /**
14 | * 返回值处理逻辑
15 | *
16 | * @param query
17 | */
18 | void afterReturningQuery(ResultBean query);
19 |
20 | /**
21 | * aop执行,调用自定义query处理逻辑
22 | *
23 | * @param query
24 | */
25 | void beforeQuery(BaseQuery query);
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/handler/security/PoseidonAccessDeniedHandler.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.handler.security;
2 |
3 | import jakarta.servlet.ServletException;
4 | import jakarta.servlet.http.HttpServletRequest;
5 | import jakarta.servlet.http.HttpServletResponse;
6 | import java.io.IOException;
7 | import java.io.PrintWriter;
8 |
9 | import com.muggle.poseidon.properties.SecurityMessageProperties;
10 | import org.apache.commons.logging.Log;
11 | import org.apache.commons.logging.LogFactory;
12 | import org.springframework.security.access.AccessDeniedException;
13 | import org.springframework.security.core.Authentication;
14 | import org.springframework.security.core.context.SecurityContextHolder;
15 | import org.springframework.security.core.userdetails.UserDetails;
16 | import org.springframework.security.web.access.AccessDeniedHandler;
17 |
18 | /**
19 | * @program: poseidon
20 | * @description: 403处理器 AuthenticationFailureHandler
21 | * @author: muggle
22 | * @create: 2018-12-27 19:21
23 | **/
24 | public class PoseidonAccessDeniedHandler implements AccessDeniedHandler {
25 | private static final Log log = LogFactory.getLog(PoseidonAccessDeniedHandler.class);
26 |
27 | @Override
28 | public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
29 | log.error("用户沒有权限访问 路径: " + request.getRequestURI());
30 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
31 | Object details = authentication.getDetails();
32 |
33 | if (SecurityMessageProperties.BAD_TOKEN.equals(authentication.getPrincipal())) {
34 | response.setContentType("application/json;charset=UTF-8");
35 | PrintWriter writer = response.getWriter();
36 | writer.write("{\"code\":403,\"message\":\"" + details.toString() + "\"}");
37 | writer.close();
38 | return;
39 | }
40 | if (details instanceof UserDetails) {
41 | if (!((UserDetails) details).isEnabled()) {
42 | response.setContentType("application/json;charset=UTF-8");
43 | PrintWriter writer = response.getWriter();
44 | writer.write("{\"code\":403,\"message\":\"账号过期\"}");
45 | writer.close();
46 | return;
47 | }
48 | if (!((UserDetails) details).isAccountNonLocked()) {
49 | response.setContentType("application/json;charset=UTF-8");
50 | PrintWriter writer = response.getWriter();
51 | writer.write("{\"code\":403,\"message\":\"账号被锁定\"}");
52 | writer.close();
53 | return;
54 | } else {
55 | response.setContentType("application/json;charset=UTF-8");
56 | PrintWriter writer = response.getWriter();
57 | writer.write("{\"code\":403,\"message\":\"没有权限\"}");
58 | writer.close();
59 | return;
60 | }
61 |
62 | } else {
63 | response.setContentType("application/json;charset=UTF-8");
64 | PrintWriter writer = response.getWriter();
65 | writer.write("{\"code\":403,\"message\":\"没有权限\"}");
66 | writer.close();
67 | return;
68 | }
69 |
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/handler/security/PoseidonAuthenticationFailureHandler.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.handler.security;
2 |
3 | import jakarta.servlet.ServletException;
4 | import jakarta.servlet.http.HttpServletRequest;
5 | import jakarta.servlet.http.HttpServletResponse;
6 | import java.io.IOException;
7 | import java.io.PrintWriter;
8 |
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.springframework.security.core.AuthenticationException;
12 | import org.springframework.security.web.authentication.AuthenticationFailureHandler;
13 |
14 | /**
15 | * 登录验证失败处理器
16 | */
17 | public class PoseidonAuthenticationFailureHandler implements AuthenticationFailureHandler {
18 | private static final Logger log = LoggerFactory.getLogger(PoseidonAuthenticationFailureHandler.class);
19 |
20 | @Override
21 | public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
22 | httpServletResponse.setContentType("application/json;charset=UTF-8");
23 | final PrintWriter writer = httpServletResponse.getWriter();
24 | writer.write("{\"code\":5001,\"message\":\"" + e.getMessage() + "\"}");
25 | writer.close();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/handler/security/PoseidonAuthenticationSuccessHandler.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.handler.security;
2 |
3 | import jakarta.servlet.ServletException;
4 | import jakarta.servlet.http.HttpServletRequest;
5 | import jakarta.servlet.http.HttpServletResponse;
6 | import java.io.IOException;
7 | import java.io.PrintWriter;
8 |
9 | import com.fasterxml.jackson.databind.ObjectMapper;
10 | import com.muggle.poseidon.base.ResultBean;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 | import org.springframework.security.core.Authentication;
14 | import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
15 |
16 | public class PoseidonAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
17 | private static final Logger log = LoggerFactory.getLogger(PoseidonAuthenticationSuccessHandler.class);
18 |
19 | @Override
20 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
21 | Object principal = authentication.getPrincipal();
22 | log.debug("登录成功!");
23 | response.setContentType("application/json;charset=UTF-8");
24 | final PrintWriter writer = response.getWriter();
25 | ObjectMapper objectMapper = new ObjectMapper();
26 | String result = objectMapper.writeValueAsString(ResultBean.successData(principal));
27 | writer.write(result);
28 | writer.close();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/handler/security/PoseidonLoginUrlAuthenticationEntryPoint.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.handler.security;
2 |
3 | import jakarta.servlet.ServletException;
4 | import jakarta.servlet.http.HttpServletRequest;
5 | import jakarta.servlet.http.HttpServletResponse;
6 | import java.io.IOException;
7 | import java.io.PrintWriter;
8 |
9 | import org.apache.commons.logging.Log;
10 | import org.apache.commons.logging.LogFactory;
11 | import org.springframework.security.core.AuthenticationException;
12 | import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
13 |
14 | /**
15 | * @program: poseidon
16 | * @description: 未登录处理
17 | * @author: muggle
18 | * @create: 2018-12-31
19 | **/
20 | public class PoseidonLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
21 | private static final Log log = LogFactory.getLog(PoseidonLoginUrlAuthenticationEntryPoint.class);
22 |
23 | public PoseidonLoginUrlAuthenticationEntryPoint(String loginFormUrl) {
24 | super(loginFormUrl);
25 | }
26 |
27 | @Override
28 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
29 | log.error(">>>>>>>>>>>>>>>>>>>>> 用户未登陆 <<<<<<<<<<<<<<<<<<<<<<<<<");
30 | response.setContentType("application/json;charset=UTF-8");
31 | final PrintWriter writer = response.getWriter();
32 | writer.write("{\"code\":401,\"message\":\"用户未登录\"}");
33 | writer.close();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/handler/security/PoseidonLogoutSuccessHandler.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.handler.security;
2 |
3 | import jakarta.servlet.ServletException;
4 | import jakarta.servlet.http.HttpServletRequest;
5 | import jakarta.servlet.http.HttpServletResponse;
6 | import java.io.IOException;
7 | import java.io.PrintWriter;
8 |
9 | import com.muggle.poseidon.store.SecurityStore;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.springframework.security.core.Authentication;
13 | import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
14 |
15 | /**
16 | * @program: poseidon
17 | * @description: 登出成功处理器
18 | * @author: muggle
19 | * @create: 2018-12-31
20 | **/
21 | public class PoseidonLogoutSuccessHandler implements LogoutSuccessHandler {
22 |
23 |
24 | private SecurityStore securityStore;
25 |
26 | public PoseidonLogoutSuccessHandler(SecurityStore securityStore) {
27 | this.securityStore = securityStore;
28 | }
29 |
30 | private final static Logger log = LoggerFactory.getLogger("PoseidonLogoutSuccessHandler");
31 |
32 | @Override
33 | public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
34 | response.setContentType("application/json;charset=UTF-8");
35 | PrintWriter writer = response.getWriter();
36 | if (authentication == null) {
37 | writer.write("{\"code\":401,\"message\":\"用户未登录\"}");
38 | writer.close();
39 | return;
40 | }
41 | Object principal = authentication.getPrincipal();
42 | try {
43 | Boolean success = securityStore.cleanToken((String) principal);
44 | if (success) {
45 | log.info("用户登出, token: {}", principal);
46 | writer.write("{\"code\":200,\"message\":\"登出成功\"}");
47 | } else {
48 | log.info("用户登出失败 token:{}", principal);
49 | writer.write("{\"code\":5001,\"message\":\"登出失败,请重试\"}");
50 | }
51 | } catch (Exception e) {
52 | log.error("登出失败: ", e);
53 | writer.write("{\"code\":\"5001\",\"message\":\"" + e.getMessage() + "\"}");
54 | } finally {
55 | writer.close();
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/handler/security/RequestLogProcessor.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.handler.security;
2 |
3 | import jakarta.servlet.http.HttpServletRequest;
4 |
5 | public interface RequestLogProcessor {
6 | /**
7 | * 日志记录,进入controller之前 只可读,所以用final 修饰
8 | *
9 | * @param request
10 | * @param args
11 | */
12 | void recordBefore(final HttpServletRequest request, final Object[] args);
13 |
14 | /**
15 | * 日志记录,进入controller 获取返回值 result 为返回值,只可读。
16 | *
17 | * @param result 返回值
18 | * @param args 入参
19 | */
20 | void recordAfterReturning(final Object result, final Object[] args);
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/handler/web/RoolMessageHandler.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.handler.web;
2 |
3 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
4 |
5 | /**
6 | * @program: poseidon-cloud-starter
7 | * @description: 权限信息处理器
8 | * 废弃原因——加入到开机任务当中
9 | * @author: muggle
10 | * @create: 2019-11-05
11 | **/
12 | @Deprecated
13 | public class RoolMessageHandler {
14 |
15 | private RequestMappingHandlerMapping handlerMapping;
16 |
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/handler/web/WebResultHandler.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.handler.web;
2 |
3 | import jakarta.servlet.http.HttpServletRequest;
4 |
5 | import com.muggle.poseidon.base.ResultBean;
6 | import com.muggle.poseidon.base.exception.BasePoseidonCheckException;
7 | import com.muggle.poseidon.base.exception.BasePoseidonException;
8 | import com.muggle.poseidon.listener.ExceptionEvent;
9 | import com.muggle.poseidon.util.UserInfoUtils;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
14 | import org.springframework.context.ApplicationContext;
15 | import org.springframework.security.core.userdetails.UserDetails;
16 | import org.springframework.validation.BindException;
17 | import org.springframework.web.HttpRequestMethodNotSupportedException;
18 | import org.springframework.web.bind.MethodArgumentNotValidException;
19 | import org.springframework.web.bind.annotation.ExceptionHandler;
20 | import org.springframework.web.bind.annotation.RestControllerAdvice;
21 | import org.springframework.web.servlet.NoHandlerFoundException;
22 |
23 | @RestControllerAdvice
24 | @ConditionalOnProperty(prefix = "poseidon", name = "auto", havingValue = "true", matchIfMissing = false)
25 | public class WebResultHandler {
26 |
27 | public WebResultHandler() {
28 | log.debug(">>>>>>>>>>>>>>>>>>>>> WebResultHandler 注册 <<<<<<<<<<<<<<<<<<<<");
29 | }
30 |
31 | private static final Logger log = LoggerFactory.getLogger(WebResultHandler.class);
32 |
33 | @Autowired
34 | ApplicationContext applicationContext;
35 |
36 |
37 | /**
38 | * 自定义异常
39 | *
40 | * @param e
41 | * @param req
42 | * @return
43 | */
44 | @ExceptionHandler(value = {BasePoseidonException.class})
45 | public ResultBean poseidonExceptionHandler(BasePoseidonException e, HttpServletRequest req) {
46 | log.error("业务异常,错误码:{}", e.getCode(), e);
47 | ResultBean error = ResultBean.error(e.getMessage(), e.getCode() == null ? 5001 : e.getCode());
48 | return error;
49 | }
50 |
51 | /**
52 | * 参数未通过校验
53 | *
54 | * @param e
55 | * @param req
56 | * @return
57 | */
58 | @ExceptionHandler(value = {MethodArgumentNotValidException.class})
59 | public ResultBean methodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest req) {
60 | log.error("参数未通过校验", e);
61 | ResultBean error = ResultBean.error(e.getBindingResult().getFieldError().getDefaultMessage());
62 | return error;
63 | }
64 |
65 | /**
66 | * BeanPropertyBindingResult
67 | */
68 | @ExceptionHandler(value = {BindException.class})
69 | public ResultBean beanPropertyBindingResult(BindException e, HttpServletRequest req) {
70 | log.error("参数未通过校验", e);
71 | ResultBean error = ResultBean.error(e.getFieldError().getDefaultMessage());
72 | return error;
73 | }
74 |
75 | /**
76 | * 错误的请求方式
77 | *
78 | * @param e
79 | * @param req
80 | * @return
81 | */
82 | @ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class})
83 | public ResultBean notsupported(Exception e, HttpServletRequest req) {
84 | log.error("错误的请求方式", e);
85 | ResultBean error = ResultBean.error("错误的请求方式");
86 | return error;
87 | }
88 |
89 | /**
90 | * 请求路径不存在
91 | *
92 | * @param e
93 | * @param req
94 | * @return
95 | */
96 | @ExceptionHandler(value = {NoHandlerFoundException.class})
97 | public ResultBean notFoundUrl(Exception e, HttpServletRequest req) {
98 | log.error("请求路径不存在", e);
99 | ResultBean error = ResultBean.error("请求路径不存在");
100 | return error;
101 | }
102 |
103 |
104 | /**
105 | * 自定义异常
106 | *
107 | * @param e
108 | * @param req
109 | * @return
110 | */
111 | @ExceptionHandler(value = {BasePoseidonCheckException.class})
112 | public ResultBean checked(BasePoseidonCheckException e, HttpServletRequest req) {
113 | log.error("自定义异常,错误码:{}", e.getCode(), e);
114 | ResultBean error = ResultBean.error(e.getMessage(), e.getCode() == null ? 5001 : e.getCode());
115 | return error;
116 | }
117 |
118 | /**
119 | * 未知异常,需要通知到管理员,对于线上未知的异常,我们应该严肃处理:先将消息传给MQ中心(该平台未实现) 然后日志写库
120 | * 这里的处理方式是抛出事件
121 | *
122 | * @param e
123 | * @param req
124 | * @return
125 | */
126 | @ExceptionHandler(value = {Exception.class})
127 | public ResultBean exceptionHandler(Exception e, HttpServletRequest req) {
128 | try {
129 | UserDetails userInfo = UserInfoUtils.getUserInfo();
130 | log.error("系统异常:" + req.getMethod() + req.getRequestURI() + " user: " + (userInfo == null ? "无用户信息" : userInfo.toString()), e);
131 | ExceptionEvent exceptionEvent = new ExceptionEvent(String.format("系统异常: [ %s ] 时间戳: [%d] ", e.getMessage(), System.currentTimeMillis()), this);
132 | applicationContext.publishEvent(exceptionEvent);
133 | return ResultBean.error("系统异常", 500);
134 | } catch (Exception err) {
135 | log.error("紧急!!! 严重的异常", err);
136 | return ResultBean.error("系统发生严重的错误", 500);
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/handler/web/WebUrlHandler.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.handler.web;
2 |
3 | import jakarta.servlet.http.HttpServletRequest;
4 |
5 | import com.muggle.poseidon.base.ResultBean;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.beans.factory.annotation.Value;
9 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
10 | import org.springframework.boot.web.servlet.error.ErrorController;
11 | import org.springframework.web.bind.annotation.RequestMapping;
12 | import org.springframework.web.bind.annotation.RestController;
13 |
14 | /**
15 | * @program: poseidon-cloud-core
16 | * @description:
17 | * @author: muggle
18 | * @create: 2020-03-12 09:54
19 | */
20 | @RestController
21 | @ConditionalOnProperty(prefix = "poseidon", name = "auto", havingValue = "true", matchIfMissing = false)
22 | public class WebUrlHandler implements ErrorController {
23 | @Value("${spring.application.name:poseidon-boot-starter}")
24 | private String appName;
25 |
26 | public WebUrlHandler() {
27 | log.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>> WebUrlHandler 注册 <<<<<<<<<<<<<<<<<<<<");
28 | }
29 |
30 | private static final Logger log = LoggerFactory.getLogger(WebUrlHandler.class);
31 |
32 | @RequestMapping(value = "/public/notfound", produces = "application/json;charset=UTF-8")
33 | public ResultBean notfund(HttpServletRequest request) {
34 | log.debug(">>>>>>>>>>>>>>>>>>>>>>>> 客户端访问了错误的页面 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
35 | return ResultBean.error("找不到页面", 404);
36 | }
37 |
38 | @Override
39 | public String getErrorPath() {
40 | return "/error_message";
41 | }
42 |
43 |
44 | @RequestMapping("/")
45 | public ResultBean getMessage() {
46 | log.debug("请求发起 访问路径: /");
47 |
48 | return ResultBean.successData(appName);
49 | }
50 |
51 | @RequestMapping(value = "/error", produces = "application/json;charset=UTF-8")
52 | public ResultBean error(HttpServletRequest request) {
53 | log.error(">>>>>>>>>>>>>>>>>>> error <<<<<<<<<<<<<<<<<<<<<<<<");
54 | return ResultBean.error("请求未响应,请稍后再试");
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/listener/ExceptionEvent.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.listener;
2 |
3 | import org.springframework.context.ApplicationEvent;
4 |
5 | /**
6 | * @Description:
7 | * @Author: muggle
8 | * @Date: 2020/4/2$
9 | **/
10 | public class ExceptionEvent extends ApplicationEvent {
11 | private String message;
12 |
13 | /**
14 | * Create a new ApplicationEvent.
15 | *
16 | * @param source the object on which the event initially occurred (never {@code null})
17 | */
18 | public ExceptionEvent(String message, Object source) {
19 | super(source);
20 | this.message = message;
21 | }
22 |
23 | public String getMessage() {
24 | return this.message;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/listener/ExceptionListener.java:
--------------------------------------------------------------------------------
1 | //package com.muggle.poseidon.listener;
2 | //
3 | //import com.muggle.poseidon.properties.DingParamProperties;
4 | //import com.muggle.poseidon.properties.DingSendEnum;
5 | //import com.muggle.poseidon.util.DingUtil;
6 | //import org.springframework.context.ApplicationListener;
7 | //import org.springframework.stereotype.Component;
8 | //
9 | ///**
10 | // * @Description:
11 | // * @Author: muggle
12 | // * @Date: 2020/4/2$
13 | // **/
14 | //
15 | //
16 | //@Component
17 | //public class ExceptionListener implements ApplicationListener {
18 | //
19 | //
20 | // @Override
21 | // public void onApplicationEvent(ExceptionEvent event) {
22 | // // todo
23 | // int i=0;
24 | // while (i<3) {
25 | // try {
26 | // String message = event.getMessage();
27 | // break;
28 | // } catch (Exception e) {
29 | // i++;
30 | // }
31 | // }
32 | // }
33 | //}
34 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/manager/PoseidonFilterInvocationSecurityMetadataSource.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.manager;
2 |
3 | import jakarta.servlet.http.HttpServletRequest;
4 | import java.util.Collection;
5 |
6 | import org.springframework.security.access.ConfigAttribute;
7 | import org.springframework.security.web.FilterInvocation;
8 | import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
9 |
10 | /**
11 | * @program: poseidon
12 | * @description: URL权限填充
13 | * @author: muggle
14 | * @create: 2018-12-30 11:39
15 | **/
16 |
17 | public class PoseidonFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
18 |
19 |
20 | @Override
21 | public Collection getAttributes(Object object) throws IllegalArgumentException {
22 | final HttpServletRequest httpRequest = ((FilterInvocation) object).getHttpRequest();
23 | return null;
24 | }
25 |
26 | @Override
27 | public Collection getAllConfigAttributes() {
28 | return null;
29 | }
30 |
31 | @Override
32 | public boolean supports(Class> aClass) {
33 | return true;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/manager/PoseidonWebExpressionVoter.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.manager;
2 |
3 | import java.util.Collection;
4 |
5 | import com.muggle.poseidon.auto.PoseidonSecurityProperties;
6 | import com.muggle.poseidon.properties.SecurityMessageProperties;
7 | import com.muggle.poseidon.service.TokenService;
8 | import com.muggle.poseidon.store.SecurityStore;
9 | import org.apache.commons.logging.Log;
10 | import org.apache.commons.logging.LogFactory;
11 | import org.springframework.security.access.ConfigAttribute;
12 | import org.springframework.security.core.Authentication;
13 | import org.springframework.security.core.GrantedAuthority;
14 | import org.springframework.security.core.userdetails.UserDetails;
15 | import org.springframework.security.web.FilterInvocation;
16 | import org.springframework.security.web.access.expression.WebExpressionVoter;
17 | import org.springframework.util.AntPathMatcher;
18 |
19 | /**
20 | * @program: poseidon-cloud-starter
21 | * @description: 投票器
22 | * @author: muggle
23 | * @create: 2019-11-05
24 | **/
25 |
26 | public class PoseidonWebExpressionVoter extends WebExpressionVoter {
27 |
28 | private static final Log log = LogFactory.getLog(PoseidonWebExpressionVoter.class);
29 |
30 | private static AntPathMatcher PATH_MATCHER = new AntPathMatcher();
31 |
32 | private TokenService tokenService;
33 |
34 | private PoseidonSecurityProperties properties;
35 |
36 | public PoseidonWebExpressionVoter(TokenService tokenService, PoseidonSecurityProperties properties) {
37 | this.properties = properties;
38 | this.tokenService = tokenService;
39 | }
40 |
41 | /**
42 | * @throws
43 | * @author muggle
44 | * @Description: 权限校验方法(投票器) 1通过,-1不通过 0弃权
45 | * @Param: fixme
46 | * @return:
47 | * @date 2019/11/5 11:21
48 | */
49 | @Override
50 | public int vote(Authentication authentication, FilterInvocation fi, Collection attributes) {
51 | String requestUrl = fi.getRequestUrl();
52 | log.debug("》》》》 请求进入, url:【" + requestUrl + "】用户名:【" + authentication.getPrincipal() + "】");
53 | /** 获取所有放行权限(在adapter中的config 方法配置)*/
54 | for (String pattern :
55 | SecurityStore.ACCESS_PATHS) {
56 | boolean match = PATH_MATCHER.match(pattern, requestUrl);
57 | if (match) {
58 | return ACCESS_GRANTED;
59 | }
60 | }
61 | for (String pattern :
62 | properties.getIgnorePath()) {
63 | boolean match = PATH_MATCHER.match(pattern, requestUrl);
64 | if (match) {
65 | return ACCESS_GRANTED;
66 | }
67 | }
68 | boolean bool = tokenVerify(authentication);
69 | // 未携带token 或者token失效 用户被冻结 用户
70 | if (bool) {
71 | return ACCESS_DENIED;
72 | }
73 | /** 获取用户角色,并通过角色去匹配权限*/
74 | Collection extends GrantedAuthority> authorities = authentication.getAuthorities();
75 |
76 | boolean b = tokenService.rooleMatch(authorities, requestUrl);
77 | if (b) {
78 | return ACCESS_GRANTED;
79 | }
80 | log.debug("》》》》 用户无权限访问,用户名:【" + authentication.getPrincipal() + "】");
81 | return ACCESS_DENIED;
82 | }
83 |
84 | /**
85 | * 验证用户是否已登陆,账号是否被锁定或者被冻结
86 | *
87 | * @param authentication
88 | * @return
89 | */
90 | private boolean tokenVerify(Authentication authentication) {
91 | boolean equals = SecurityMessageProperties.BAD_TOKEN.equals(authentication.getPrincipal());
92 | Object details = authentication.getDetails();
93 | if (details == null || !(details instanceof UserDetails)) {
94 | return true;
95 | }
96 | UserDetails userInfo = (UserDetails) details;
97 | boolean accountNonLocked = userInfo.isAccountNonLocked();
98 | boolean enabled = userInfo.isEnabled();
99 | return equals || !accountNonLocked || !enabled;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/properties/SecurityMessageProperties.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.properties;
2 |
3 | /**
4 | * @program: poseidon-cloud-starter
5 | * @description:
6 | * @author: muggle
7 | * @create: 2019-11-05
8 | **/
9 |
10 | public interface SecurityMessageProperties {
11 | String BAD_TOKEN = "BAD_TOKEN";
12 | String SUBJECT = "POSEIDON_CLAIM";
13 | String ISSUER = "security";
14 | String RANDOM = "RANDOM";
15 | String LOGOUT = "/logout";
16 | String LOGIN_URL = "/sign_in";
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/service/TokenService.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.service;
2 |
3 | import jakarta.servlet.http.HttpServletRequest;
4 | import jakarta.servlet.http.HttpServletResponse;
5 | import java.util.Collection;
6 | import java.util.List;
7 |
8 | import com.muggle.poseidon.base.exception.SimplePoseidonCheckException;
9 | import com.muggle.poseidon.entity.AuthUrlPathDO;
10 | import org.springframework.security.core.GrantedAuthority;
11 | import org.springframework.security.core.userdetails.UserDetails;
12 | import org.springframework.security.core.userdetails.UserDetailsService;
13 |
14 | public interface TokenService extends UserDetailsService {
15 |
16 | UserDetails getUserById(Long id);
17 |
18 | /**
19 | * @author muggle
20 | * @Description: 权限匹配接口
21 | * @Param: path为请求的 url roleCodes 权限编码集合
22 | * @return:
23 | * @date 2019/11/5 18:05
24 | */
25 | boolean rooleMatch(Collection extends GrantedAuthority> authorities, String path);
26 |
27 | /**
28 | * 项目初始化url处理方法
29 | *
30 | * @param list
31 | */
32 | void processUrl(List list);
33 |
34 | /**
35 | * 登录方法(可以自定义登录逻辑,比如加验证码等等)
36 | *
37 | * @param request
38 | * @param response
39 | * @return
40 | * @throws
41 | */
42 | UserDetails login(HttpServletRequest request, HttpServletResponse response) throws SimplePoseidonCheckException;
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/store/SecurityStore.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.store;
2 |
3 | import java.util.List;
4 | import java.util.concurrent.CopyOnWriteArrayList;
5 |
6 | import com.muggle.poseidon.base.exception.BasePoseidonCheckException;
7 | import org.springframework.security.core.userdetails.UserDetails;
8 |
9 | public interface SecurityStore {
10 |
11 | List ACCESS_PATHS = new CopyOnWriteArrayList();
12 |
13 |
14 | /**
15 | * @throws
16 | * @author muggle
17 | * @Description: 根据token获取用户信息,先通过凭证解析token,然后获得storeKey,random,,自定义body,然后根据key 和random(版本号)获取用户信息
18 | * @Param:
19 | * @return:
20 | * @date 2019/11/5 11:40
21 | */
22 | UserDetails getUserdetail(String token) throws BasePoseidonCheckException;
23 |
24 | /**
25 | * @throws
26 | * @author muggle
27 | * @Description: 将用户的登陆信息保存到token仓库中(比如Redis 或者mysql)
28 | * @Param:
29 | * @return:
30 | * @date 2019/11/5 11:40
31 | */
32 | String signUserMessage(UserDetails userDetails);
33 |
34 | /**
35 | * @author muggle
36 | * @Description: 清除用户登录信息(登出)
37 | * @Param:
38 | * @return:
39 | * @date 2019/11/5 11:42
40 | */
41 | Boolean cleanToken(String username);
42 |
43 | /**
44 | * @author muggle
45 | * @Description: 保存放行的url
46 | * @Param:
47 | * @return:
48 | * @date 2019/11/5 11:44
49 | */
50 | static void saveAccessPath(List paths) {
51 | ACCESS_PATHS.addAll(paths);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/store/impl/SimpleRedisSecurityStore.java:
--------------------------------------------------------------------------------
1 | //package com.muggle.poseidon.store.impl;
2 | //
3 | //import com.muggle.poseidon.store.SecurityStore;
4 | //import org.springframework.cglib.core.internal.Function;
5 | //import org.springframework.data.redis.core.RedisTemplate;
6 | //import org.springframework.security.core.userdetails.UserDetails;
7 | //
8 | //import java.util.List;
9 | //import java.util.concurrent.TimeUnit;
10 | //
11 | ///**
12 | // * @program: poseidon-cloud-starter
13 | // * @description: redis存储token的仓库
14 | // * @author: muggle
15 | // * @create: 2019-11-04
16 | // **/
17 | //
18 | //public class SimpleRedisSecurityStore implements SecurityStore {
19 | // private RedisTemplate redisTemplate;
20 | //
21 | //
22 | //
23 | // @Override
24 | // public UserDetails getUserdetail(String token) {
25 | // UserDetails userDetails = redisTemplate.opsForValue().get(token);
26 | // return userDetails;
27 | // }
28 | //
29 | // @Override
30 | // public void saveUser(UserDetails userDetails, long expirationTime, String token) {
31 | // redisTemplate.opsForValue().set(token,userDetails,expirationTime);
32 | // }
33 | //
34 | // @Override
35 | // public Boolean cleanToken(String token) {
36 | // Boolean delete = redisTemplate.delete(token);
37 | // return delete;
38 | // }
39 | //
40 | // @Override
41 | // public void setExpirationTime(long expirationTime, String token) {
42 | // redisTemplate.expire(token,expirationTime, TimeUnit.MILLISECONDS);
43 | // }
44 | //
45 | // @Override
46 | // public UserDetails processToken(UserDetails userDetails, String token, Function function) {
47 | // return null;
48 | // }
49 | //
50 | //}
51 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/BaseDaoUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | /**
4 | * @Description:
5 | * @Author: muggle
6 | * @Date: 2020/8/27
7 | **/
8 | public class BaseDaoUtils {
9 |
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/DateUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import java.text.DateFormat;
4 | import java.text.ParseException;
5 | import java.text.SimpleDateFormat;
6 | import java.util.ArrayList;
7 | import java.util.Calendar;
8 | import java.util.Date;
9 | import java.util.List;
10 |
11 | /**
12 | * @Description:
13 | * @Author: muggle
14 | * @Date: 2020/7/29
15 | **/
16 | public class DateUtils {
17 | public static final String DATE_PATTERN = "yyyy-MM-dd";
18 | public static final String DATE_PATTERN1 = "yyyy_MM_dd";
19 | public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
20 | public static final String TIME_PATTERN = "HH:mm:ss";
21 |
22 | public DateUtils() {
23 | }
24 |
25 | public static String format(long millis, String pattern) {
26 | return format(new Date(millis), pattern);
27 | }
28 |
29 | public static long getDateMinus(String startDate, String endDate, String pattern) {
30 | SimpleDateFormat myFormatter = new SimpleDateFormat(pattern);
31 |
32 | try {
33 | Date date = myFormatter.parse(startDate);
34 | Date mydate = myFormatter.parse(endDate);
35 | long day = (mydate.getTime() - date.getTime()) / 60000L;
36 | return day;
37 | } catch (ParseException var8) {
38 | var8.printStackTrace();
39 | return 0L;
40 | }
41 | }
42 |
43 | public static String addDay(String s, int n) {
44 | try {
45 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
46 | Calendar cd = Calendar.getInstance();
47 | cd.setTime(sdf.parse(s));
48 | cd.add(5, n);
49 | return sdf.format(cd.getTime());
50 | } catch (Exception var4) {
51 | return null;
52 | }
53 | }
54 |
55 | public static int getDaysByYearMonth(String dateString) {
56 | int year = Integer.parseInt(dateString.substring(0, 4));
57 | int month = Integer.parseInt(dateString.substring(5, 7));
58 | Calendar a = Calendar.getInstance();
59 | a.set(1, year);
60 | a.set(2, month - 1);
61 | a.set(5, 1);
62 | a.roll(5, -1);
63 | int maxDate = a.get(5);
64 | return maxDate;
65 | }
66 |
67 | public static String getLastDayOfMonth(int year, int month) {
68 | Calendar cal = Calendar.getInstance();
69 | cal.set(1, year);
70 | cal.set(2, month - 1);
71 | int lastDay = cal.getActualMaximum(5);
72 | cal.set(5, lastDay);
73 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
74 | String lastDayOfMonth = sdf.format(cal.getTime());
75 | return lastDayOfMonth;
76 | }
77 |
78 | public static Date ConverToDate(String strDate) {
79 | SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
80 |
81 | try {
82 | return df.parse(strDate);
83 | } catch (ParseException var3) {
84 | var3.printStackTrace();
85 | return null;
86 | }
87 | }
88 |
89 | public static List findDates(String startTime, String endTime) {
90 | Date startDate = ConverToDate(startTime);
91 | Date endDate = ConverToDate(endTime);
92 | List lDate = new ArrayList();
93 | lDate.add(startDate);
94 | Calendar calBegin = Calendar.getInstance();
95 | calBegin.setTime(startDate);
96 | Calendar calEnd = Calendar.getInstance();
97 | calEnd.setTime(endDate);
98 |
99 | while (endDate.after(calBegin.getTime())) {
100 | calBegin.add(5, 1);
101 | lDate.add(calBegin.getTime());
102 | }
103 |
104 | return lDate;
105 | }
106 |
107 | public static int getWeek(Date date) {
108 | int[] weeks = new int[]{0, 1, 2, 3, 4, 5, 6};
109 | Calendar cal = Calendar.getInstance();
110 | cal.setTime(date);
111 | int week_index = cal.get(7) - 1;
112 | if (week_index < 0) {
113 | week_index = 0;
114 | }
115 |
116 | return weeks[week_index];
117 | }
118 |
119 | public static String getTimeDifference(String startTime, String endTime) {
120 | SimpleDateFormat dfs = new SimpleDateFormat("HH:mm:ss");
121 | long between = 0L;
122 |
123 | try {
124 | Date begin = dfs.parse(startTime);
125 | Date end = dfs.parse(endTime);
126 | between = end.getTime() - begin.getTime();
127 | } catch (Exception var14) {
128 | var14.printStackTrace();
129 | }
130 |
131 | long day = between / 86400000L;
132 | long hour = between / 3600000L - day * 24L;
133 | long min = between / 60000L - day * 24L * 60L - hour * 60L;
134 | long s = between / 1000L - day * 24L * 60L * 60L - hour * 60L * 60L - min * 60L;
135 | String date = day + "天" + hour + "小时" + min + "分" + s + "秒";
136 | if (day == 0L && hour != 0L) {
137 | date = hour + "小时" + min + "分" + s + "秒";
138 | } else if (day == 0L && hour == 0L && min != 0L) {
139 | date = min + "分" + s + "秒";
140 | } else if (day == 0L && hour == 0L && min == 0L) {
141 | date = s + "秒";
142 | }
143 |
144 | return date;
145 | }
146 |
147 | public static int getNextDaySec() {
148 | Date date = new Date();
149 | Calendar cal = Calendar.getInstance();
150 | cal.setTime(date);
151 | cal.add(6, 1);
152 | cal.set(11, 9);
153 | cal.set(12, 0);
154 | cal.set(13, 0);
155 | Long tm = cal.getTimeInMillis() - date.getTime();
156 | return (int) (tm / 1000L);
157 | }
158 |
159 | public static String getWeekOfDate(Date date) {
160 | String[] weekOfDays = new String[]{"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
161 | Calendar cal = Calendar.getInstance();
162 | cal.setTime(date);
163 | int week_index = cal.get(7) - 1;
164 | if (week_index < 0) {
165 | week_index = 0;
166 | }
167 |
168 | return weekOfDays[week_index];
169 | }
170 |
171 | public static String format(Date date, String pattern) {
172 | DateFormat formatter = new SimpleDateFormat(pattern);
173 | return formatter.format(date);
174 | }
175 |
176 | public static String formatDate(Date date) {
177 | return format(date, "yyyy-MM-dd");
178 | }
179 |
180 | public static String formatTime(Date date) {
181 | return format(date, "HH:mm:ss");
182 | }
183 |
184 | public static String formatDateTime(Date date) {
185 | return format(date, "yyyy-MM-dd HH:mm:ss");
186 | }
187 |
188 | public static String formatCurrent(String pattern) {
189 | return format(new Date(), pattern);
190 | }
191 |
192 | public static String formatCurrentDate() {
193 | return format(new Date(), "yyyy-MM-dd");
194 | }
195 |
196 | public static String formatCurrentTime() {
197 | return format(new Date(), "HH:mm:ss");
198 | }
199 |
200 | public static String formatCurrentDateTime() {
201 | return format(new Date(), "yyyy-MM-dd HH:mm:ss");
202 | }
203 |
204 | public static Date getCurrentDate() {
205 | Calendar cal = Calendar.getInstance();
206 | cal.set(11, 0);
207 | cal.set(12, 0);
208 | cal.set(13, 0);
209 | cal.set(14, 0);
210 | return cal.getTime();
211 | }
212 |
213 | public static Date getTheDate(Date date) {
214 | Calendar cal = Calendar.getInstance();
215 | cal.setTime(date);
216 | cal.set(11, 0);
217 | cal.set(12, 0);
218 | cal.set(13, 0);
219 | cal.set(14, 0);
220 | return cal.getTime();
221 | }
222 |
223 | public static int compareDate(Date start, Date end) {
224 | if (start == null && end == null) {
225 | return 0;
226 | } else if (end == null) {
227 | return 1;
228 | } else {
229 | if (start == null) {
230 | start = new Date();
231 | }
232 |
233 | start = getTheDate(start);
234 | end = getTheDate(end);
235 | return start.compareTo(end);
236 | }
237 | }
238 |
239 | public static Date stringToDate(String dateString, String pattern) {
240 | SimpleDateFormat formatter = new SimpleDateFormat(pattern);
241 |
242 | try {
243 | return formatter.parse(dateString);
244 | } catch (ParseException var4) {
245 | throw new RuntimeException(var4);
246 | }
247 | }
248 |
249 | public static Date addYears(Date date, int amount) {
250 | return add(date, 1, amount);
251 | }
252 |
253 | public static Date addMonths(Date date, int amount) {
254 | return add(date, 2, amount);
255 | }
256 |
257 | public static Date addWeeks(Date date, int amount) {
258 | return add(date, 3, amount);
259 | }
260 |
261 | public static Date addDays(Date date, int amount) {
262 | return add(date, 5, amount);
263 | }
264 |
265 | public static Date addHours(Date date, int amount) {
266 | return add(date, 11, amount);
267 | }
268 |
269 | public static Date addMinutes(Date date, int amount) {
270 | return add(date, 12, amount);
271 | }
272 |
273 | public static Date addSeconds(Date date, int amount) {
274 | return add(date, 13, amount);
275 | }
276 |
277 | public static Date addMilliseconds(Date date, int amount) {
278 | return add(date, 14, amount);
279 | }
280 |
281 | private static Date add(Date date, int calendarField, int amount) {
282 | if (date == null) {
283 | throw new IllegalArgumentException("日期对象不允许为null!");
284 | } else {
285 | Calendar c = Calendar.getInstance();
286 | c.setTime(date);
287 | c.add(calendarField, amount);
288 | return c.getTime();
289 | }
290 | }
291 |
292 | public static Date getDateAfterNatureDays(Date date, int days, int hours) {
293 | if (date == null) {
294 | date = new Date();
295 | }
296 |
297 | Calendar c = Calendar.getInstance();
298 | c.setTime(date);
299 | c.add(5, days);
300 | c.add(10, hours);
301 | return c.getTime();
302 | }
303 |
304 | public static Date getDateAfterWorkDays(Date date, int days, int hours) {
305 | if (date == null) {
306 | date = new Date();
307 | }
308 |
309 | Calendar c = Calendar.getInstance();
310 | c.setTime(date);
311 | c.add(5, days);
312 | c.add(10, hours);
313 | return c.getTime();
314 | }
315 |
316 | public static String dateToStamp(String s) throws ParseException {
317 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
318 | Date date = simpleDateFormat.parse(s);
319 | long ts = date.getTime();
320 | String res = String.valueOf(ts);
321 | return res;
322 | }
323 |
324 | public static String stampToDate(String s) {
325 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
326 | long lt = new Long(s);
327 | Date date = new Date(lt);
328 | return simpleDateFormat.format(date);
329 | }
330 |
331 | public static void main(String[] args) {
332 | String s = stampToDate("1502964348398");
333 | System.out.println(s);
334 | }
335 | }
336 |
337 |
338 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/ICollectionUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import org.springframework.util.CollectionUtils;
4 |
5 | import java.util.ArrayList;
6 | import java.util.HashMap;
7 | import java.util.List;
8 | import java.util.Map;
9 | import java.util.function.Function;
10 | import java.util.stream.Collectors;
11 |
12 | /**
13 | * @Description: 集合处理工具集
14 | * @Author: muggle
15 | * @Date: 2020/7/28
16 | **/
17 | public class ICollectionUtils extends CollectionUtils {
18 |
19 | /**
20 | * 寻求优化空间 如自定义map 自定义list
21 | * @param args
22 | */
23 | public static void main(String[] args) {
24 | Map map=new HashMap<>();
25 | List list=new ArrayList<>();
26 | List collect = map.values().stream().collect(Collectors.toList());
27 | Map collect1 = list.stream().collect(Collectors.toMap(key -> key, value -> value, (k1, k2) -> k2));
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/INumberUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import org.springframework.util.NumberUtils;
4 |
5 | /**
6 | * @Description:
7 | * @Author: muggle
8 | * @Date: 2020/6/5
9 | **/
10 | public class INumberUtils extends NumberUtils {
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/IStringUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import org.springframework.util.StringUtils;
4 |
5 | /**
6 | * @Description:
7 | * @Author: muggle
8 | * @Date: 2020/6/5
9 | **/
10 | public class IStringUtils extends StringUtils {
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/JSONUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.TimeZone;
5 |
6 | import com.fasterxml.jackson.annotation.JsonInclude;
7 | import com.fasterxml.jackson.core.JsonProcessingException;
8 | import com.fasterxml.jackson.databind.ObjectMapper;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.springframework.util.StringUtils;
12 |
13 | /**
14 | * @Description:
15 | * @Author: muggle
16 | * @Date: 2020/8/27
17 | **/
18 | public class JSONUtils {
19 |
20 | private static final Logger logger = LoggerFactory.getLogger(JSONUtils.class);
21 |
22 | private static final ObjectMapper MAPPER = new ObjectMapper();
23 |
24 | private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
25 |
26 | static {
27 | MAPPER.setTimeZone(TimeZone.getDefault());
28 | MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
29 | }
30 |
31 | /**
32 | * 将对象序列化为JSON字符串
33 | *
34 | * @param object
35 | * @return
36 | */
37 | public static String toJacksonString(Object object) {
38 | if (object == null) {
39 | return null;
40 | }
41 | try {
42 | return MAPPER.writeValueAsString(object);
43 | } catch (JsonProcessingException e) {
44 | logger.warn("Parse object to json error: ", e);
45 | }
46 | return "";
47 | }
48 |
49 | public static T paserJacsonObject(String src, Class clazz) {
50 | if (StringUtils.isEmpty(src) || clazz == null) {
51 | return null;
52 | }
53 | try {
54 | return String.class.equals(clazz) ? (T) src : MAPPER.readValue(src, clazz);
55 | } catch (Exception e) {
56 | logger.warn("Parse json to object error: ", e);
57 | }
58 | return null;
59 | }
60 | public static T paserJacsonObject(String src, Class clazz, SimpleDateFormat dateFormat) {
61 | if (StringUtils.isEmpty(src) || clazz == null) {
62 | return null;
63 | }
64 | try {
65 | ObjectMapper objectMapper = buildJacson(dateFormat);
66 | return String.class.equals(clazz) ? (T) src : objectMapper.readValue(src, clazz);
67 | } catch (Exception e) {
68 | logger.warn("Parse json to object error: ", e);
69 | }
70 | return null;
71 | }
72 | private static ObjectMapper buildJacson(SimpleDateFormat dateFormat){
73 | ObjectMapper objectMapper = new ObjectMapper();
74 | objectMapper.setTimeZone(TimeZone.getDefault());
75 | objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
76 | objectMapper.setDateFormat(dateFormat);
77 | return objectMapper;
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/JwtTokenUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import java.util.Arrays;
4 | import java.util.Date;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 | import java.util.UUID;
8 |
9 | import com.muggle.poseidon.base.exception.SimplePoseidonException;
10 | import com.muggle.poseidon.properties.SecurityMessageProperties;
11 | import io.jsonwebtoken.Claims;
12 | import io.jsonwebtoken.ExpiredJwtException;
13 | import io.jsonwebtoken.Jwts;
14 | import io.jsonwebtoken.SignatureAlgorithm;
15 |
16 | /**
17 | * @program: poseidon
18 | * @description: Token工具类
19 | * @author: muggle
20 | * @create: 2018-12-22 15:05
21 | **/
22 |
23 | public class JwtTokenUtils {
24 | private static final long EXPIRATION = 3600000L;
25 |
26 | /**
27 | * 创建一个带过期时间的token experTime单位为小时
28 | *
29 | * @param map
30 | * @param credential
31 | * @param experTime
32 | * @return
33 | */
34 | public static String createToken(Map map, String credential, Long experTime) {
35 | String compact = Jwts.builder().signWith(SignatureAlgorithm.HS512, credential)
36 | .setIssuer(SecurityMessageProperties.ISSUER)
37 | .setSubject(SecurityMessageProperties.SUBJECT)
38 | .setIssuedAt(new Date())
39 | .setExpiration(new Date(System.currentTimeMillis() + experTime * EXPIRATION))
40 | .setClaims(map)
41 | .compact();
42 | return compact;
43 | }
44 |
45 | /**
46 | * 获得用户信息所使用的key
47 | *
48 | * @param token
49 | * @param credential
50 | * @return
51 | */
52 | public static String getStoreKey(String token, String credential) {
53 | Claims body = Jwts.parser()
54 | .setSigningKey(credential)
55 | .parseClaimsJws(token)
56 | .getBody();
57 | String key = body.get("key", String.class);
58 | return key;
59 | }
60 |
61 | /**
62 | * 获得版本号
63 | *
64 | * @param token
65 | * @param credential
66 | * @return
67 | */
68 | public static String getRandom(String token, String credential) {
69 | try {
70 | Claims body = Jwts.parser()
71 | .setSigningKey(credential)
72 | .parseClaimsJws(token)
73 | .getBody();
74 | String random = body.get(SecurityMessageProperties.RANDOM, String.class);
75 | return random;
76 | } catch (ExpiredJwtException e) {
77 | throw new SimplePoseidonException("用户登录过期,请重新登录");
78 | }
79 | }
80 |
81 | /**
82 | * 根据key获得body 扩展性方法
83 | *
84 | * @param token
85 | * @param credential
86 | * @param key
87 | * @return
88 | */
89 | public static Object getBody(String token, String credential, String key) {
90 | try {
91 | Claims claims = Jwts.parser()
92 | .setSigningKey(credential)
93 | .parseClaimsJws(token)
94 | .getBody();
95 | return claims.get(key, Object.class);
96 | } catch (ExpiredJwtException e) {
97 | throw new SimplePoseidonException("用户登录过期,请重新登录");
98 | }
99 |
100 | }
101 |
102 | public static String createToken(String storeKey, Map body, String credential, Long experTime) {
103 | UUID uuid = UUID.randomUUID();
104 | body.put(SecurityMessageProperties.RANDOM, uuid.toString());
105 | body.put("key", storeKey);
106 | return createToken(body, credential, experTime);
107 | }
108 |
109 | public static String createToken(Map body, String credential) {
110 | String compact = Jwts.builder().signWith(SignatureAlgorithm.HS512, credential)
111 | .setIssuedAt(new Date())
112 | .setExpiration(new Date(System.currentTimeMillis() + 12 * EXPIRATION))
113 | .setClaims(body)
114 | .compact();
115 | return compact;
116 | }
117 |
118 | public static void main(String[] args) {
119 | //
120 | Map body = new HashMap<>();
121 | body.put("username", "muggle");
122 | body.put("version", System.currentTimeMillis());
123 | body.put("roles", Arrays.asList("admin", "guest"));
124 | String test = createToken(body, "test");
125 | System.out.println(test);
126 | }
127 | }
128 | /**
129 | * token使用思路
130 | * 1.token 的实效性
131 | * 创建token时带过期时间,每次先校验token是否过期
132 | * 2.token对应的用户信息存储
133 | * 存储在redis中
134 | * 3.登录再登出后作废token仍然生效。采用版本号
135 | * 4.token 的多人登录和单人登录要求灵活切换
136 | * 数据字典对应的系统设置
137 | * Redis信息多版本。
138 | */
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/LocalDateUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | /**
4 | * @Description:
5 | * @Author: muggle
6 | * @Date: 2020/8/27
7 | **/
8 | public class LocalDateUtils {
9 | // todo
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/NamedThreadFactory.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import java.util.concurrent.ThreadFactory;
4 | import java.util.concurrent.atomic.AtomicLong;
5 |
6 | /**
7 | * @Description:
8 | * @Author: muggle
9 | * @Date: 2020/7/28
10 | **/
11 | public class NamedThreadFactory implements ThreadFactory {
12 | private final String prefix;
13 | private final AtomicLong threadIds;
14 |
15 | NamedThreadFactory(String prefix) {
16 | this.prefix = prefix;
17 | this.threadIds = new AtomicLong();
18 | }
19 |
20 | @Override
21 | public Thread newThread(Runnable r) {
22 | Thread t = new Thread(r, this.prefix + this.threadIds.incrementAndGet());
23 | t.setDaemon(false);
24 | return t;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/PoseidonIdGenerator.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * @program: poseidon-cloud-starter
7 | * @description: 发号器
8 | * @author: muggle
9 | * @create: 2019-11-25
10 | **/
11 |
12 | public abstract class PoseidonIdGenerator {
13 |
14 |
15 | /**
16 | * 起始的时间戳
17 | */
18 | private final static long START_STMP = 1480166465631L;
19 |
20 | /**
21 | * 每一部分占用的位数
22 | */
23 | private final static long SEQUENCE_BIT = 12; //序列号占用的位数
24 | private final static long MACHINE_BIT = 5; //机器标识占用的位数
25 | private final static long DATACENTER_BIT = 5;//数据中心占用的位数
26 |
27 | /**
28 | * 每一部分的最大值
29 | */
30 | private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
31 | private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
32 | private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
33 |
34 | /**
35 | * 每一部分向左的位移
36 | */
37 | private final static long MACHINE_LEFT = SEQUENCE_BIT;
38 | private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
39 | private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
40 |
41 | private long datacenterId; //数据中心
42 | private long machineId; //机器标识
43 | private long sequence = 0L; //序列号
44 | private long lastStmp = -1L;//上一次时间戳
45 |
46 | /**
47 | * 获取一个流水单号
48 | *
49 | * @return
50 | */
51 | public abstract String getNextSerialNumber(String perfix, String mark, int size);
52 |
53 |
54 | /**
55 | * 获取多个流水号
56 | *
57 | * @param perfix
58 | * @param mark
59 | * @param length
60 | * @return
61 | */
62 | public abstract List getBatchSerialNumber(String perfix, String mark, int length, int size);
63 |
64 | //
65 | public PoseidonIdGenerator(long datacenterId, long machineId) {
66 | if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
67 | throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
68 | }
69 | if (machineId > MAX_MACHINE_NUM || machineId < 0) {
70 | throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
71 | }
72 | this.datacenterId = datacenterId;
73 | this.machineId = machineId;
74 | }
75 |
76 | /**
77 | * 产生下一个ID
78 | *
79 | * @return
80 | */
81 | public synchronized long simpleNextId() {
82 | long currStmp = getNewstmp();
83 | if (currStmp < lastStmp) {
84 | throw new RuntimeException("Clock moved backwards. Refusing to generate id");
85 | }
86 |
87 | if (currStmp == lastStmp) {
88 | //相同毫秒内,序列号自增
89 | sequence = (sequence + 1) & MAX_SEQUENCE;
90 | //同一毫秒的序列数已经达到最大
91 | if (sequence == 0L) {
92 | currStmp = getNextMill();
93 | }
94 | } else {
95 | //不同毫秒内,序列号置为0
96 | sequence = 0L;
97 | }
98 |
99 | lastStmp = currStmp;
100 |
101 | return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
102 | | datacenterId << DATACENTER_LEFT //数据中心部分
103 | | machineId << MACHINE_LEFT //机器标识部分
104 | | sequence; //序列号部分
105 | }
106 |
107 | private long getNextMill() {
108 | long mill = getNewstmp();
109 | while (mill <= lastStmp) {
110 | mill = getNewstmp();
111 | }
112 | return mill;
113 | }
114 |
115 | private long getNewstmp() {
116 | return System.currentTimeMillis();
117 | }
118 |
119 | public abstract long nextId();
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/RSACoder.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 |
4 | /**
5 | * @program: security-test
6 | * @description: 非对称加密算法
7 | * @author: muggle
8 | * @create: 2019-04-20
9 | **/
10 |
11 |
12 | import jakarta.crypto.Cipher;
13 | import java.security.Key;
14 | import java.security.KeyFactory;
15 | import java.security.KeyPair;
16 | import java.security.KeyPairGenerator;
17 | import java.security.PrivateKey;
18 | import java.security.PublicKey;
19 | import java.security.interfaces.RSAPrivateKey;
20 | import java.security.interfaces.RSAPublicKey;
21 | import java.security.spec.PKCS8EncodedKeySpec;
22 | import java.security.spec.X509EncodedKeySpec;
23 | import java.util.HashMap;
24 | import java.util.Map;
25 |
26 | /**
27 | * 非对称加密算法RSA算法组件
28 | * 非对称算法一般是用来传送对称加密算法的密钥来使用的,相对于DH算法,RSA算法只需要一方构造密钥,不需要
29 | * 大费周章的构造各自本地的密钥对了。DH算法只能算法非对称算法的底层实现。而RSA算法算法实现起来较为简单
30 | *
31 | * @author kongqz
32 | */
33 | public class RSACoder {
34 | //非对称密钥算法
35 | public static final String KEY_ALGORITHM = "RSA";
36 |
37 |
38 | /**
39 | * 密钥长度,DH算法的默认密钥长度是1024
40 | * 密钥长度必须是64的倍数,在512到65536位之间
41 | */
42 | private static final int KEY_SIZE = 512;
43 | //公钥
44 | private static final String PUBLIC_KEY = "RSAPublicKey";
45 |
46 | //私钥
47 | private static final String PRIVATE_KEY = "RSAPrivateKey";
48 |
49 | /**
50 | * 初始化密钥对
51 | *
52 | * @return Map 甲方密钥的Map
53 | */
54 | public static Map initKey() throws Exception {
55 | //实例化密钥生成器
56 | KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
57 | //初始化密钥生成器
58 | keyPairGenerator.initialize(KEY_SIZE);
59 | //生成密钥对
60 | KeyPair keyPair = keyPairGenerator.generateKeyPair();
61 | //甲方公钥
62 | RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
63 | //甲方私钥
64 | RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
65 | //将密钥存储在map中
66 | Map keyMap = new HashMap();
67 | keyMap.put(PUBLIC_KEY, publicKey);
68 | keyMap.put(PRIVATE_KEY, privateKey);
69 | return keyMap;
70 |
71 | }
72 |
73 |
74 | /**
75 | * 私钥加密
76 | *
77 | * @param data 待加密数据
78 | * @param key 密钥
79 | * @return byte[] 加密数据
80 | */
81 | public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {
82 |
83 | //取得私钥
84 | PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
85 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
86 | //生成私钥
87 | PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
88 | //数据加密
89 | Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
90 | cipher.init(Cipher.ENCRYPT_MODE, privateKey);
91 | return cipher.doFinal(data);
92 | }
93 |
94 | /**
95 | * 公钥加密
96 | *
97 | * @param data 待加密数据
98 | * @param key 密钥
99 | * @return byte[] 加密数据
100 | */
101 | public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
102 |
103 | //实例化密钥工厂
104 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
105 | //初始化公钥
106 | //密钥材料转换
107 | X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
108 | //产生公钥
109 | PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
110 |
111 | //数据加密
112 | Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
113 | cipher.init(Cipher.ENCRYPT_MODE, pubKey);
114 | return cipher.doFinal(data);
115 | }
116 |
117 | /**
118 | * 私钥解密
119 | *
120 | * @param data 待解密数据
121 | * @param key 密钥
122 | * @return byte[] 解密数据
123 | */
124 | public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {
125 | //取得私钥
126 | PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
127 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
128 | //生成私钥
129 | PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
130 | //数据解密
131 | Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
132 | cipher.init(Cipher.DECRYPT_MODE, privateKey);
133 | return cipher.doFinal(data);
134 | }
135 |
136 | /**
137 | * 公钥解密
138 | *
139 | * @param data 待解密数据
140 | * @param key 密钥
141 | * @return byte[] 解密数据
142 | */
143 | public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {
144 |
145 | //实例化密钥工厂
146 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
147 | //初始化公钥
148 | //密钥材料转换
149 | X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
150 | //产生公钥
151 | PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
152 | //数据解密
153 | Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
154 | cipher.init(Cipher.DECRYPT_MODE, pubKey);
155 | return cipher.doFinal(data);
156 | }
157 |
158 | /**
159 | * 取得私钥
160 | *
161 | * @param keyMap 密钥map
162 | * @return byte[] 私钥
163 | */
164 | public static byte[] getPrivateKey(Map keyMap) {
165 | Key key = (Key) keyMap.get(PRIVATE_KEY);
166 | return key.getEncoded();
167 | }
168 |
169 | /**
170 | * 取得公钥
171 | *
172 | * @param keyMap 密钥map
173 | * @return byte[] 公钥
174 | */
175 | public static byte[] getPublicKey(Map keyMap) throws Exception {
176 | Key key = (Key) keyMap.get(PUBLIC_KEY);
177 | return key.getEncoded();
178 | }
179 |
180 | public static void main(String[] args) throws Exception {
181 | //初始化密钥
182 | //生成密钥对
183 | Map keyMap = RSACoder.initKey();
184 | //公钥
185 | byte[] publicKey = RSACoder.getPublicKey(keyMap);
186 |
187 | //私钥
188 | byte[] privateKey = RSACoder.getPrivateKey(keyMap);
189 |
190 | String str = "RSA密码交换算法";
191 |
192 | //甲方进行数据的加密
193 | byte[] code1 = RSACoder.encryptByPrivateKey(str.getBytes(), privateKey);
194 |
195 | //乙方进行数据的解密
196 | byte[] decode1 = RSACoder.decryptByPublicKey(code1, publicKey);
197 |
198 | Map ss = RSACoder.initKey();
199 |
200 | //公钥
201 | byte[] a = RSACoder.getPublicKey(keyMap);
202 |
203 | //私钥
204 | byte[] b = RSACoder.getPrivateKey(keyMap);
205 |
206 | byte[] dexx = RSACoder.decryptByPublicKey(code1, a);
207 |
208 | System.out.println(new String(dexx));
209 |
210 | /* str = "乙方向甲方发送数据RSA算法";
211 |
212 | //乙方使用公钥对数据进行加密
213 | byte[] code2 = RSACoder.encryptByPublicKey(str.getBytes(), publicKey);
214 |
215 | //甲方使用私钥对数据进行解密
216 | byte[] decode2 = RSACoder.decryptByPrivateKey(code2, privateKey);
217 |
218 | System.out.println("甲方解密后的数据:" + new String(decode2));*/
219 | }
220 |
221 | }
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/RequestUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import jakarta.servlet.http.HttpServletRequest;
4 |
5 | /**
6 | * @program: poseidon-cloud-starter
7 | * @description:
8 | * @author: muggle
9 | * @create: 2019-11-29
10 | **/
11 |
12 | public class RequestUtils {
13 |
14 | /**
15 | * 获取真实的IP地址
16 | *
17 | * @param request 请求
18 | * @return
19 | */
20 | public static String getIP(HttpServletRequest request) {
21 | String ip = request.getHeader("x-forwarded-for");
22 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
23 | ip = request.getHeader("Proxy-Client-IP");
24 | }
25 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
26 | ip = request.getHeader("WL-Proxy-Client-IP");
27 | }
28 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
29 | ip = request.getHeader("HTTP_CLIENT_IP");
30 | }
31 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
32 | ip = request.getHeader("HTTP_X_FORWARDED_FOR");
33 | }
34 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
35 | ip = request.getRemoteAddr();
36 | }
37 | return ip;
38 | }
39 | // todo
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/SHA256Utils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import java.io.UnsupportedEncodingException;
4 | import java.nio.charset.StandardCharsets;
5 | import java.security.MessageDigest;
6 | import java.security.NoSuchAlgorithmException;
7 |
8 | /**
9 | * @Description:
10 | * @Author: muggle
11 | * @Date: 2020/8/28
12 | **/
13 | public class SHA256Utils {
14 |
15 | public final static String SHA256="SHA-256";
16 |
17 | private SHA256Utils() {
18 | throw new UnsupportedOperationException();
19 | }
20 |
21 | public static String getSHA256StrJava(String timeStamp, String token, String passId, String collection) {
22 | return getSHA256StrJava(timeStamp + token + passId + collection);
23 | }
24 |
25 | public static String getSHA256StrJava(String str) {
26 | String encodeStr = "";
27 |
28 | try {
29 | MessageDigest messageDigest = MessageDigest.getInstance(SHA256);
30 | messageDigest.update(str.getBytes(StandardCharsets.UTF_8));
31 | encodeStr = byte2Hex(messageDigest.digest());
32 | } catch (NoSuchAlgorithmException var4) {
33 | var4.printStackTrace();
34 | }
35 |
36 | return encodeStr;
37 | }
38 |
39 | public static String getSHA512Encrypt(String str) {
40 | String encodeStr = "";
41 |
42 | try {
43 | MessageDigest messageDigest = MessageDigest.getInstance(SHA256);
44 | messageDigest.update(str.getBytes(StandardCharsets.UTF_8));
45 | encodeStr = byte2Hex(messageDigest.digest());
46 | } catch (NoSuchAlgorithmException var4) {
47 | var4.printStackTrace();
48 | }
49 |
50 | return encodeStr;
51 | }
52 |
53 | private static String byte2Hex(byte[] bytes) {
54 | StringBuffer stringBuffer = new StringBuffer();
55 | String temp = null;
56 |
57 | for(int i = 0; i < bytes.length; ++i) {
58 | temp = Integer.toHexString(bytes[i] & 255);
59 | if (temp.length() == 1) {
60 | stringBuffer.append("0");
61 | }
62 |
63 | stringBuffer.append(temp);
64 | }
65 |
66 | return stringBuffer.toString();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/SimpleLocker.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import java.util.Iterator;
4 | import java.util.Map;
5 | import java.util.Set;
6 | import java.util.concurrent.ConcurrentHashMap;
7 | import java.util.concurrent.TimeUnit;
8 | import java.util.concurrent.locks.Condition;
9 |
10 | import com.muggle.poseidon.base.DistributedLocker;
11 | import com.muggle.poseidon.base.exception.BasePoseidonCheckException;
12 | import com.muggle.poseidon.base.exception.SimplePoseidonCheckException;
13 |
14 |
15 | public class SimpleLocker implements DistributedLocker {
16 |
17 |
18 | @Override
19 | public boolean tryLock(String key, long expertime) throws InterruptedException {
20 | return false;
21 | }
22 |
23 | @Override
24 | public void lock(String key) {
25 |
26 | }
27 |
28 | @Override
29 | public void unlock(String key) {
30 |
31 | }
32 |
33 | @Override
34 | public void lock() {
35 |
36 | }
37 |
38 | @Override
39 | public void lockInterruptibly() throws InterruptedException {
40 |
41 | }
42 |
43 | @Override
44 | public boolean tryLock() {
45 | return false;
46 | }
47 |
48 | @Override
49 | public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
50 | return false;
51 | }
52 |
53 | @Override
54 | public void unlock() {
55 |
56 | }
57 |
58 | @Override
59 | public Condition newCondition() {
60 | return null;
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/ThreadPoolUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.util.concurrent.*;
7 | import java.util.concurrent.atomic.AtomicInteger;
8 |
9 | /**
10 | * @Description:
11 | * @Author: muggle
12 | * @Date: 2020/7/28
13 | **/
14 | public class ThreadPoolUtils {
15 | private static final Logger log = LoggerFactory.getLogger(ThreadPoolUtils.class);
16 | private static final String DEFAULT_EXEUTOR_NAME = "POSEIDON-DEFAULT-POOL-";
17 | private static final int DEFAULT_POOL_SIEZ = 100;
18 | private static final int DEFAULT_MAX_POOL_SIZE = 200;
19 | private static final int DEFAULT_QUEUE_SIZE = 1000;
20 | private static final long DEFAULT_KEEP_ALIVE = 5L;
21 |
22 | private ThreadPoolUtils() {
23 |
24 | }
25 |
26 | // 1. 线程池工厂 thraedfactory 作用 2. 四种handler
27 | /**
28 | * 1. AbortPolicy:丢弃任务并抛出 RejectedExecutionException 异常。(默认这种)
29 | * 2. DiscardPolicy:也是丢弃任务,但是不抛出异常
30 | * 3. DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
31 | * 4. CallerRunsPolicy:由调用线程处理该任务
32 | * */
33 | public static ThreadPoolExecutor buildDefaultPool() {
34 | ThreadPoolExecutor executor = new ThreadPoolExecutor(DEFAULT_POOL_SIEZ, DEFAULT_MAX_POOL_SIZE, DEFAULT_KEEP_ALIVE, TimeUnit.MINUTES,
35 | new LinkedBlockingQueue(DEFAULT_QUEUE_SIZE), new NamedThreadFactory(DEFAULT_EXEUTOR_NAME),
36 | new ThreadPoolExecutor.CallerRunsPolicy());
37 | return executor;
38 | }
39 |
40 | public static ThreadPoolExecutor buildThreadPool(String poolName){
41 | ThreadPoolExecutor executor = new ThreadPoolExecutor(DEFAULT_POOL_SIEZ, DEFAULT_MAX_POOL_SIZE, DEFAULT_KEEP_ALIVE, TimeUnit.MINUTES,
42 | new LinkedBlockingQueue(DEFAULT_QUEUE_SIZE), new NamedThreadFactory(poolName),
43 | new ThreadPoolExecutor.CallerRunsPolicy());
44 | return executor;
45 | }
46 |
47 | public static ThreadPoolExecutor buildThreadPool(String poolName,RejectedExecutionHandler handler){
48 | ThreadPoolExecutor executor = new ThreadPoolExecutor(DEFAULT_POOL_SIEZ, DEFAULT_MAX_POOL_SIZE, DEFAULT_KEEP_ALIVE, TimeUnit.MINUTES,
49 | new LinkedBlockingQueue(DEFAULT_QUEUE_SIZE), new NamedThreadFactory(poolName), handler);
50 | return executor;
51 | }
52 |
53 | public static void main(String[] args) {
54 | ThreadPoolExecutor threadPoolExecutor = ThreadPoolUtils.buildDefaultPool();
55 | threadPoolExecutor.execute(()->{
56 | System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>.");
57 | });
58 | threadPoolExecutor.shutdown();
59 | }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/UserInfoUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 | import com.muggle.poseidon.base.exception.BasePoseidonCheckException;
4 | import com.muggle.poseidon.base.exception.SimplePoseidonCheckException;
5 | import org.springframework.security.core.Authentication;
6 | import org.springframework.security.core.context.SecurityContextHolder;
7 | import org.springframework.security.core.userdetails.UserDetails;
8 |
9 | /**
10 | * @program: poseidon-cloud-starter
11 | * @description: 获取用户信息
12 | * @author: muggle
13 | * @create: 2019-11-06
14 | **/
15 |
16 | public class UserInfoUtils {
17 |
18 | public static UserDetails getUserInfo() throws BasePoseidonCheckException {
19 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
20 | if (authentication == null || authentication.getDetails() == null || authentication.getPrincipal().equals("anonymousUser")) {
21 | return null;
22 | }
23 | if (!(authentication.getDetails() instanceof UserDetails)) {
24 | throw new SimplePoseidonCheckException("用户登陆信息异常");
25 | }
26 | return (UserDetails) authentication.getDetails();
27 | }
28 | }
--------------------------------------------------------------------------------
/src/main/java/com/muggle/poseidon/util/ZipUtils.java:
--------------------------------------------------------------------------------
1 | package com.muggle.poseidon.util;
2 |
3 |
4 | import java.io.*;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 | import java.util.zip.ZipEntry;
8 | import java.util.zip.ZipInputStream;
9 | import java.util.zip.ZipOutputStream;
10 |
11 | /**
12 | * 压缩工具
13 | * @author nick
14 | */
15 | public class ZipUtils {
16 |
17 | public static class ZipItem {
18 | /**文件名,包含目录形式:用/隔开,例如a/b/c.txt*/
19 | public String fileName;
20 | /**文件对应的输入流*/
21 | public InputStream in;
22 | }
23 |
24 | public static class Iterator {
25 | private ZipInputStream zin;
26 | private Iterator(ZipInputStream zin) {
27 | this.zin = zin;
28 | }
29 | /**
30 | * 获得下一个ZipItem,当返回null则表示读取完。【重要】ZipItem中的输入流in必须在本次读取完。
31 | * @return
32 | * @throws IOException
33 | */
34 | public ZipItem next() throws IOException {
35 | ZipEntry ze = zin.getNextEntry();
36 | if(ze == null) {
37 | return null;
38 | }
39 | ZipItem zipItem = new ZipItem();
40 | zipItem.fileName = ze.getName();
41 | zipItem.in = zin;
42 | return zipItem;
43 | }
44 | }
45 |
46 | /**
47 | * 压缩文件
48 | * @param zipItems
49 | * @param out 不会自动close
50 | */
51 | public static void zip(List zipItems, OutputStream out) throws IOException {
52 | ZipOutputStream zipOut = new ZipOutputStream(out);
53 | if(zipItems != null) {
54 | for(ZipItem zipItem : zipItems) {
55 | zipOut.putNextEntry(new ZipEntry(zipItem.fileName));
56 | int len = -1;
57 | byte[] buff = new byte[4096];
58 | while ((len = zipItem.in.read(buff)) != -1) {
59 | zipOut.write(buff, 0, len);
60 | }
61 | zipItem.in.close();
62 | }
63 | }
64 | zipOut.close();
65 | }
66 |
67 | /**
68 | * 解压文件,节省内存方式
69 | * @param in 不会自动close
70 | * @return
71 | */
72 | public static Iterator unzip(InputStream in) throws Exception {
73 | ZipInputStream zin = new ZipInputStream(in);
74 | return new Iterator(zin);
75 | }
76 |
77 | /**
78 | * 解压文件,会将文件解压到内存中,该方式会占用较多内存
79 | * @param in
80 | * @return
81 | * @throws Exception
82 | */
83 | public static List unzipAll(InputStream in) throws Exception {
84 | Iterator it = unzip(in);
85 | ZipItem zipItem = null;
86 | List zipItems = new ArrayList<>();
87 | while((zipItem = it.next()) != null) {
88 | ByteArrayOutputStream out = new ByteArrayOutputStream();
89 | // IOUtils.copy(zipItem.in, out);
90 | zipItem.in = new ByteArrayInputStream(out.toByteArray());
91 | zipItems.add(zipItem);
92 | }
93 | return zipItems;
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | com.muggle.poseidon.auto.ExpansibilityConfig,\
3 | com.muggle.poseidon.auto.SecurityAutoConfig,\
4 | com.muggle.poseidon.handler.web.WebUrlHandler,\
5 | com.muggle.poseidon.handler.web.WebResultHandler
--------------------------------------------------------------------------------
/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | /$$ /$$
2 | |__/ | $$
3 | /$$$$$$ /$$$$$$ /$$$$$$$ /$$$$$$ /$$ /$$$$$$$ /$$$$$$ /$$$$$$$
4 | /$$__ $$ /$$__ $$ /$$_____/ /$$__ $$| $$ /$$__ $$ /$$__ $$| $$__ $$
5 | | $$ \ $$| $$ \ $$| $$$$$$ | $$$$$$$$| $$| $$ | $$| $$ \ $$| $$ \ $$
6 | | $$ | $$| $$ | $$ \____ $$| $$_____/| $$| $$ | $$| $$ | $$| $$ | $$
7 | | $$$$$$$/| $$$$$$/ /$$$$$$$/| $$$$$$$| $$| $$$$$$$| $$$$$$/| $$ | $$
8 | | $$____/ \______/ |_______/ \_______/|__/ \_______/ \______/ |__/ |__/
9 | | $$
10 | | $$
11 | |__/
--------------------------------------------------------------------------------
/src/main/resources/poseidon-logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | %white(POSEIDON----) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %cyan(%logger) - %msg%n
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | ${log_dir}/%d{yyyy-MM-dd}-info.log
29 |
30 | ${maxHistory}
31 |
32 |
33 |
34 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %logger - %msg%n
35 |
36 |
37 |
38 | INFO
39 | ACCEPT
40 | DENY
41 |
42 |
43 |
44 |
45 |
46 |
47 | ${log_dir}/%d{yyyy-MM-dd}-error.log
48 |
49 | ${maxHistory}
50 |
51 |
52 |
53 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %logger - %msg%n
54 |
55 |
56 |
57 | ERROR
58 | ACCEPT
59 | DENY
60 |
61 |
62 |
63 |
64 |
65 | ${log_dir}/%d{yyyy-MM-dd}-debug.log
66 |
67 | ${maxHistory}
68 |
69 |
70 |
71 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %logger - %msg%n
72 |
73 |
74 |
75 | DEBUG
76 | ACCEPT
77 | DENY
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------