Skip to content

Commit 15d8920

Browse files
committed
feat: 认证事件监听
1 parent a695f60 commit 15d8920

File tree

15 files changed

+231
-11
lines changed

15 files changed

+231
-11
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ bin/
1515

1616
### IntelliJ IDEA ###
1717
.idea
18+
!.idea/copyright/*.xml
1819
*.iws
1920
*.iml
2021
*.ipr

.idea/copyright/power4j_apache_v2.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/copyright/profiles_settings.xml

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flygon-admin/src/main/java/com/power4j/flygon/admin/modules/demo/notify/ding/DingMessagePusher.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ private String renderMarkdownMsg(ErrorEvent event) {
5858

5959
// @formatter:off
6060

61-
final String msgTemplate = "" + StrUtil.CR +
61+
final String msgTemplate = "" + StrUtil.CR + StrUtil.CR +
6262
"## 请求信息" + StrUtil.CR +
6363
"- 时间(UTC): `%s`" + StrUtil.CR +
6464
"- 请求ID: `%s`" + StrUtil.CR +
@@ -73,9 +73,15 @@ private String renderMarkdownMsg(ErrorEvent event) {
7373
"%s" + StrUtil.CR +
7474
"```" + StrUtil.CR;
7575

76-
return String.format(msgTemplate, DATE_TIME_FORMATTER.format(event.getTimeUtc()), event.getRequestId(),
77-
event.getRequestUri(), event.getRequestMethod(), event.getRequestQueryString(), event.getEx(),
78-
event.getExMsg(), StrUtil.maxLength(event.getExStack(), 500));
76+
return String.format(msgTemplate,
77+
DATE_TIME_FORMATTER.format(event.getTimeUtc()),
78+
event.getRequestId(),
79+
event.getRequestUri(),
80+
event.getRequestMethod(),
81+
event.getRequestQueryString(),
82+
event.getEx(),
83+
event.getExMsg(),
84+
StrUtil.maxLength(event.getExStack(), 500));
7985

8086
// @formatter:on
8187
}

flygon-admin/src/main/resources/application-dev.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ logging:
5555
level:
5656
org:
5757
springframework:
58-
security: info
58+
security: debug
5959
com:
6060
power4j:
6161
flygon:

flygon-admin/src/main/resources/application.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ spring:
2424
dingers:
2525
# 使用钉钉机器人, 请根据自己机器人配置信息进行修改
2626
dingtalk:
27-
tokenId: ${DING_TALK_TOKEN:4ef4bee34d2b37d40e60b6d9f2abad82062ffa3cdefce1ec87389b63867a902a}
27+
tokenId: ${DING_TALK_TOKEN}
2828
secret: ${DING_TALK_SECRET}
2929

3030
springdoc:
@@ -79,7 +79,7 @@ flygon:
7979
# 公众号消息通知
8080
wx-mp:
8181
enabled: true
82-
app-id: ${WX_MP_APPID:wxc6222bd36479c057}
82+
app-id: ${WX_MP_APPID}
8383
secret: ${WX_MP_SECRET}
8484
subscribers: oiwtWuMNNa6njL3bE7_9ADOKMEWc
8585
# 自定义验证码产生地址和消费地址

flygon-admin/src/main/resources/logback-spring.xml

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<property name="log.path" value="logs/${spring.application.name}"/>
2222

2323
<property name="CONSOLE_LOG_PATTERN"
24-
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr([%X{requestId:-}]){red} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
24+
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr([R %X{requestId:-}]){red} %clr([U %X{accountId:-}]){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
2525
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
2626
<conversionRule conversionWord="wex"
2727
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
@@ -43,7 +43,7 @@
4343
<maxHistory>10</maxHistory>
4444
</rollingPolicy>
4545
<encoder>
46-
<pattern>%date [%X{requestId:-}] [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
46+
<pattern>%date [R %X{requestId:-}] [U %X{accountId:-}] [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
4747
</encoder>
4848
</appender>
4949

@@ -56,7 +56,7 @@
5656
<maxHistory>30</maxHistory>
5757
</rollingPolicy>
5858
<encoder>
59-
<pattern>%date [%X{requestId:-}] [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
59+
<pattern>%date [R %X{requestId:-}] [U %X{accountId:-}] [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
6060
</encoder>
6161
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
6262
<level>ERROR</level>

flygon-common/flygon-common-core/src/main/java/com/power4j/flygon/common/core/context/RequestContext.java

+8
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ public Optional<String> getAccountId() {
4343
return Optional.ofNullable(getHeaders().getFirst(contextProperties.getHeaderMapping().getAccountId()));
4444
}
4545

46+
public void setRequestId(String val) {
47+
getHeaders().set(contextProperties.getHeaderMapping().getRequestId(), val);
48+
}
49+
50+
public void setAccountId(String val) {
51+
getHeaders().set(contextProperties.getHeaderMapping().getAccountId(), val);
52+
}
53+
4654
protected HttpHeaders getHeaders() {
4755
return ThreadStore.get(REQUEST_CONTEXT_KEY, () -> loadHeader()).get();
4856
}

flygon-common/flygon-common-security/src/main/java/com/power4j/flygon/common/security/config/WebSecurityConfig.java

+13
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818

1919
import cn.hutool.core.util.StrUtil;
2020
import com.fasterxml.jackson.databind.ObjectMapper;
21+
import com.power4j.flygon.common.core.context.RequestContext;
2122
import com.power4j.flygon.common.security.filter.SignInFilter;
2223
import com.power4j.flygon.common.security.handler.SignInFailureHandler;
2324
import com.power4j.flygon.common.security.handler.SignInSuccessHandler;
2425
import com.power4j.flygon.common.security.handler.SignOutHandler;
2526
import com.power4j.flygon.common.security.handler.SignOutSuccessHandler;
27+
import com.power4j.flygon.common.security.listener.AuthenticationFailureListener;
28+
import com.power4j.flygon.common.security.listener.AuthenticationSuccessListener;
2629
import com.power4j.flygon.common.security.service.PermissionService;
2730
import com.power4j.flygon.common.security.service.TokenService;
2831
import com.power4j.flygon.common.security.token.ApiTokenAuthenticationEntryPoint;
@@ -117,6 +120,16 @@ public SignInFilter signInFilter() throws Exception {
117120
return filter;
118121
}
119122

123+
@Bean
124+
public AuthenticationSuccessListener authenticationSuccessListener(RequestContext requestContext) {
125+
return new AuthenticationSuccessListener(requestContext);
126+
}
127+
128+
@Bean
129+
public AuthenticationFailureListener authenticationFailureListener() {
130+
return new AuthenticationFailureListener();
131+
}
132+
120133
@Override
121134
protected void configure(AuthenticationManagerBuilder auth) {
122135
auth.authenticationProvider(apiTokenAuthenticationProvider());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2020 ChenJun ([email protected])
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.power4j.flygon.common.security.listener;
18+
19+
import org.springframework.security.core.Authentication;
20+
import org.springframework.security.core.AuthenticationException;
21+
22+
/**
23+
* @author CJ ([email protected])
24+
* @date 2021/1/17
25+
* @since 1.0
26+
*/
27+
public interface AuthenticationFailureHandler {
28+
29+
/**
30+
* 认证失败回调
31+
* @param authentication
32+
* @param exception
33+
*/
34+
void handleAuthenticationFailure(Authentication authentication, AuthenticationException exception);
35+
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2020 ChenJun ([email protected])
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.power4j.flygon.common.security.listener;
18+
19+
import org.springframework.beans.factory.ObjectProvider;
20+
import org.springframework.beans.factory.annotation.Autowired;
21+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
22+
import org.springframework.context.ApplicationListener;
23+
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
24+
25+
/**
26+
* @author CJ ([email protected])
27+
* @date 2021/1/17
28+
* @since 1.0
29+
*/
30+
public class AuthenticationFailureListener implements ApplicationListener<AbstractAuthenticationFailureEvent> {
31+
32+
@Autowired
33+
private ObjectProvider<AuthenticationFailureHandler> authenticationFailureHandlerObjectProvider;
34+
35+
@Override
36+
public void onApplicationEvent(AbstractAuthenticationFailureEvent event) {
37+
authenticationFailureHandlerObjectProvider.stream()
38+
.forEach(h -> h.handleAuthenticationFailure(event.getAuthentication(), event.getException()));
39+
}
40+
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2020 ChenJun ([email protected])
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.power4j.flygon.common.security.listener;
18+
19+
import org.springframework.security.core.Authentication;
20+
21+
/**
22+
* @author CJ ([email protected])
23+
* @date 2021/1/17
24+
* @since 1.0
25+
*/
26+
public interface AuthenticationSuccessHandler {
27+
28+
/**
29+
* 认证失败回调
30+
* @param authentication
31+
*/
32+
void handleAuthenticationSuccess(Authentication authentication);
33+
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2020 ChenJun ([email protected])
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.power4j.flygon.common.security.listener;
18+
19+
import com.power4j.flygon.common.core.constant.CommonConstant;
20+
import com.power4j.flygon.common.core.context.RequestContext;
21+
import com.power4j.flygon.common.security.LoginUser;
22+
import com.power4j.flygon.common.security.model.ApiToken;
23+
import com.power4j.flygon.common.security.token.ApiTokenAuthentication;
24+
import lombok.RequiredArgsConstructor;
25+
import org.slf4j.MDC;
26+
import org.springframework.beans.factory.ObjectProvider;
27+
import org.springframework.beans.factory.annotation.Autowired;
28+
import org.springframework.context.ApplicationListener;
29+
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
30+
import org.springframework.security.core.Authentication;
31+
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
32+
33+
import java.util.Optional;
34+
35+
/**
36+
* @author CJ ([email protected])
37+
* @date 2021/1/17
38+
* @since 1.0
39+
*/
40+
@RequiredArgsConstructor
41+
public class AuthenticationSuccessListener implements ApplicationListener<AuthenticationSuccessEvent> {
42+
43+
private final RequestContext requestContext;
44+
45+
@Autowired
46+
private ObjectProvider<AuthenticationSuccessHandler> authenticationSuccessHandlerObjectProvider;
47+
48+
@Override
49+
public void onApplicationEvent(AuthenticationSuccessEvent event) {
50+
Authentication authentication = event.getAuthentication();
51+
updateContext(authentication);
52+
authenticationSuccessHandlerObjectProvider.stream().forEach(h -> h.handleAuthenticationSuccess(authentication));
53+
}
54+
55+
private void updateContext(Authentication authentication) {
56+
String uid = null;
57+
if (authentication instanceof LoginUser) {
58+
uid = ((LoginUser) authentication).getUid().toString();
59+
}
60+
else if (authentication instanceof PreAuthenticatedAuthenticationToken) {
61+
uid = Optional.ofNullable(authentication.getDetails()).filter(o -> o instanceof ApiToken)
62+
.map(o -> ((ApiToken) o).getUuid().toString()).orElse(null);
63+
}
64+
if (uid != null) {
65+
requestContext.setAccountId(uid);
66+
MDC.put(CommonConstant.MDC_ACCOUNT_ID, uid);
67+
}
68+
}
69+
70+
}

flygon-common/flygon-common-security/src/main/java/com/power4j/flygon/common/security/token/ApiTokenAuthenticationEntryPoint.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import cn.hutool.http.HttpStatus;
2020
import com.fasterxml.jackson.databind.ObjectMapper;
21+
import com.power4j.flygon.common.core.constant.SysErrorCodes;
2122
import com.power4j.flygon.common.core.model.ApiResponse;
2223
import com.power4j.flygon.common.core.util.ApiResponseUtil;
2324
import com.power4j.flygon.common.security.msg.SecurityMessageSource;
@@ -58,7 +59,7 @@ public void commence(HttpServletRequest request, HttpServletResponse response,
5859
log.debug("Handling {} : {} {}", authException.getClass().getSimpleName(), authException.getMessage(), reqUrl);
5960
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
6061
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
61-
ApiResponse<Object> result = ApiResponseUtil.fail(authException.getMessage());
62+
ApiResponse<Object> result = ApiResponse.of(SysErrorCodes.E_UNAUTHORIZED, authException.getMessage());
6263
result.setData(reqUrl);
6364

6465
if (authException instanceof InsufficientAuthenticationException) {

flygon-common/flygon-common-security/src/main/java/com/power4j/flygon/common/security/token/ApiTokenAuthenticationProvider.java

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
7474
UserDetails userDetails = userDetailsService.loadUserByUsername(apiToken.getUsername());
7575
PreAuthenticatedAuthenticationToken preAuthenticatedAuthenticationToken = new PreAuthenticatedAuthenticationToken(
7676
userDetails, tokenValue, userDetails.getAuthorities());
77+
preAuthenticatedAuthenticationToken.setDetails(apiToken);
7778
preAuthenticatedAuthenticationToken.setAuthenticated(true);
7879
return preAuthenticatedAuthenticationToken;
7980
}

0 commit comments

Comments
 (0)