Explorar el Código

:sparkles: 添加新特性。 定制 entrypoint 未绑定异常返回

冷冷 hace 7 años
padre
commit
a56875aa90

+ 3 - 3
pigx-auth/src/main/java/com/pig4cloud/pigx/auth/service/PigxUserDetailsServiceImpl.java

@@ -94,15 +94,15 @@ public class PigxUserDetailsServiceImpl implements PigxUserDetailsService {
 			String url = String.format(WX_AUTHORIZATION_CODE_URL
 				, wxSocialConfig.getAppid(), wxSocialConfig.getSecret(), code);
 			String result = restTemplate.getForObject(url, String.class);
-			log.debug("微信响应报文:{}", result);
+			log.warn("微信响应报文:{}", result);
 
 			Object obj = JSONUtil.parseObj(result).get("openid");
 			if (obj != null) {
 				userInfo = remoteUserService.social(EnumLoginType.WECHAT.getType(), obj.toString());
-			} else {
-				throw new UsernameNotFoundException("获取用户openid失败");
 			}
+
 		}
+
 		return getUserDetails(userInfo);
 	}
 

+ 1 - 1
pigx-auth/src/main/resources/bootstrap.yml

@@ -20,4 +20,4 @@ eureka:
     prefer-ip-address: true
   client:
     service-url:
-      defaultZone: http://pig:pig@pigx-eureka:1025/eureka/
+      defaultZone: http://pig:pig@localhost:1025/eureka/

+ 82 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationEntryPoint.java

@@ -0,0 +1,82 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.security.mobile;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
+import org.springframework.security.oauth2.provider.error.AbstractOAuth2SecurityExceptionHandler;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @author lengleng
+ * @date 2018/8/16
+ * 手机号登录异常处理
+ */
+public class MobileAuthenticationEntryPoint extends AbstractOAuth2SecurityExceptionHandler implements
+	AuthenticationEntryPoint {
+	private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
+	private static final String SUFFIX = ",";
+
+	@Override
+	public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
+		throws IOException, ServletException {
+		doHandle(request, response, authException);
+	}
+
+	@Override
+	protected ResponseEntity<OAuth2Exception> enhanceResponse(ResponseEntity<OAuth2Exception> response, Exception exception) {
+		HttpHeaders headers = response.getHeaders();
+		String existing = null;
+		if (headers.containsKey(WWW_AUTHENTICATE)) {
+			existing = extractTypePrefix(headers.getFirst("WWW-Authenticate"));
+		}
+		StringBuilder builder = new StringBuilder();
+		String typeName = OAuth2AccessToken.BEARER_TYPE;
+		builder.append(typeName + " ");
+		String realmName = "oauth";
+		builder.append("realm=\"" + realmName + "\"");
+		if (existing != null) {
+			builder.append(", " + existing);
+		}
+		HttpHeaders update = new HttpHeaders();
+		update.putAll(response.getHeaders());
+		update.set("WWW-Authenticate", builder.toString());
+		return new ResponseEntity<>(response.getBody(), update, HttpStatus.EXPECTATION_FAILED);
+	}
+
+	private String extractTypePrefix(String header) {
+		String existing = header;
+		String[] tokens = existing.split(" +");
+		if (tokens.length > 1 && !tokens[0].endsWith(SUFFIX)) {
+			existing = StringUtils.arrayToDelimitedString(tokens, " ").substring(existing.indexOf(" ") + 1);
+		}
+		return existing;
+	}
+
+}
+

+ 37 - 1
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationFilter.java

@@ -21,10 +21,17 @@ import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
 import lombok.Getter;
 import lombok.Setter;
 import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationEventPublisher;
 import org.springframework.security.authentication.AuthenticationServiceException;
+import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
+import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
+import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
 import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 
 import javax.servlet.http.HttpServletRequest;
@@ -37,6 +44,8 @@ import javax.servlet.http.HttpServletResponse;
  */
 public class MobileAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
 	private static final String SPRING_SECURITY_FORM_MOBILE_KEY = "mobile";
+	private AuthenticationEventPublisher eventPublisher = new MobileAuthenticationFilter.NullEventPublisher();
+	private AuthenticationEntryPoint authenticationEntryPoint = new MobileAuthenticationEntryPoint();
 	@Getter
 	@Setter
 	private String mobileParameter = SPRING_SECURITY_FORM_MOBILE_KEY;
@@ -68,7 +77,24 @@ public class MobileAuthenticationFilter extends AbstractAuthenticationProcessing
 
 		setDetails(request, mobileAuthenticationToken);
 
-		return this.getAuthenticationManager().authenticate(mobileAuthenticationToken);
+		try {
+			return this.getAuthenticationManager().authenticate(mobileAuthenticationToken);
+
+		} catch (Exception failed) {
+			SecurityContextHolder.clearContext();
+			logger.debug("Authentication request failed: " + failed);
+
+			eventPublisher.publishAuthenticationFailure(new BadCredentialsException(failed.getMessage(), failed),
+				new PreAuthenticatedAuthenticationToken("access-token", "N/A"));
+
+			try {
+				authenticationEntryPoint.commence(request, response,
+					new UsernameNotFoundException(failed.getMessage(), failed));
+			} catch (Exception e) {
+				logger.error("authenticationEntryPoint handle error:{}", failed);
+			}
+		}
+		return null;
 	}
 
 	private String obtainMobile(HttpServletRequest request) {
@@ -79,5 +105,15 @@ public class MobileAuthenticationFilter extends AbstractAuthenticationProcessing
 							MobileAuthenticationToken authRequest) {
 		authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
 	}
+
+	private static final class NullEventPublisher implements AuthenticationEventPublisher {
+		@Override
+		public void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication) {
+		}
+
+		@Override
+		public void publishAuthenticationSuccess(Authentication authentication) {
+		}
+	}
 }
 

+ 15 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationProvider.java

@@ -20,10 +20,16 @@ package com.pig4cloud.pigx.common.security.mobile;
 import com.pig4cloud.pigx.common.security.util.PigxUserDetailsService;
 import lombok.Getter;
 import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.support.MessageSourceAccessor;
+import org.springframework.security.authentication.AuthenticationEventPublisher;
 import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.SpringSecurityMessageSource;
 import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter;
 
 /**
  * @author lengleng
@@ -31,7 +37,9 @@ import org.springframework.security.core.userdetails.UserDetails;
  * 手机登录校验逻辑
  * 验证码登录、社交登录
  */
+@Slf4j
 public class MobileAuthenticationProvider implements AuthenticationProvider {
+	private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
 	@Getter
 	@Setter
 	private PigxUserDetailsService userDetailsService;
@@ -42,7 +50,14 @@ public class MobileAuthenticationProvider implements AuthenticationProvider {
 
 		String principal = mobileAuthenticationToken.getPrincipal().toString();
 		UserDetails userDetails = userDetailsService.loadUserBySocial(principal);
+		if (userDetails == null) {
+			log.debug("Authentication failed: no credentials provided");
 
+			throw new BadCredentialsException(messages.getMessage(
+				"AbstractUserDetailsAuthenticationProvider.noopBindAccount",
+				"Noop Bind Account"));
+
+		}
 
 		MobileAuthenticationToken authenticationToken = new MobileAuthenticationToken(userDetails, userDetails.getAuthorities());
 		authenticationToken.setDetails(mobileAuthenticationToken.getDetails());

+ 1 - 0
pigx-common/pigx-common-security/src/main/resources/org/springframework/security/messages_zh_CN.properties

@@ -20,6 +20,7 @@ AbstractAccessDecisionManager.accessDenied=\u4E0D\u5141\u8BB8\u8BBF\u95EE
 AbstractLdapAuthenticationProvider.emptyPassword=\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A
 AbstractSecurityInterceptor.authenticationNotFound=\u672A\u5728SecurityContext\u4E2D\u67E5\u627E\u5230\u8BA4\u8BC1\u5BF9\u8C61
 AbstractUserDetailsAuthenticationProvider.badCredentials=\u7528\u6237\u540D\u4E0D\u5B58\u5728\u6216\u8005\u5BC6\u7801\u9519\u8BEF
+AbstractUserDetailsAuthenticationProvider.noopBindAccount=\u672A\u7ED1\u5B9A\u767B\u5F55\u8D26\u53F7\uFF0C\u8BF7\u4F7F\u7528\u5BC6\u7801\u767B\u5F55\u540E\u7ED1\u5B9A
 AbstractUserDetailsAuthenticationProvider.credentialsExpired=\u7528\u6237\u51ED\u8BC1\u5DF2\u8FC7\u671F
 AbstractUserDetailsAuthenticationProvider.disabled=\u7528\u6237\u672A\u6FC0\u6D3B
 AbstractUserDetailsAuthenticationProvider.expired=\u7528\u6237\u5E10\u53F7\u5DF2\u8FC7\u671F

+ 1 - 1
pigx-config/src/main/resources/bootstrap.yml

@@ -19,7 +19,7 @@ eureka:
     prefer-ip-address: true
   client:
     service-url:
-      defaultZone: http://pig:pig@pigx-eureka:1025/eureka/
+      defaultZone: http://pig:pig@localhost:1025/eureka/
 
 # 暴露监控端点
 management:

+ 1 - 1
pigx-config/src/main/resources/config/application-dev.yml

@@ -2,7 +2,7 @@
 spring:
   redis:
     password:
-    host: redis
+    host: localhost
 # 暴露监控端点
 management:
   endpoints:

+ 6 - 0
pigx-config/src/main/resources/config/pigx-auth-dev.yml

@@ -12,3 +12,9 @@ social:
   wx:
     appid: wxd1678d3f83b1d83a
     secret: 6ddb043f94da5d2172926abe8533504f
+
+# 社交登录配置新
+social:
+  wx:
+    appid: wxd1678d3f83b1d83a
+    secret: 6ddb043f94da5d2172926abe8533504f

+ 1 - 1
pigx-config/src/main/resources/config/pigx-codegen-dev.yml

@@ -13,7 +13,7 @@ spring:
     driver-class-name: com.mysql.jdbc.Driver
     username: root
     password: root
-    url: jdbc:mysql://mysql:3306/pigx?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
+    url: jdbc:mysql://114.116.45.246:13306/pigx?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
   jackson:
     time-zone: GMT+8
     date-format: yyyy-MM-dd HH:mm:ss

+ 1 - 1
pigx-config/src/main/resources/config/pigx-upms-dev.yml

@@ -13,7 +13,7 @@ spring:
     driver-class-name: com.mysql.jdbc.Driver
     username: root
     password: root
-    url: jdbc:mysql://mysql:3306/pigx?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
+    url: jdbc:mysql://114.116.45.246:13306/pigx?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
 
 # mybaits 模块配置
 mybatis-plus:

+ 1 - 1
pigx-gateway/src/main/resources/bootstrap.yml

@@ -22,6 +22,6 @@ eureka:
     prefer-ip-address: true
   client:
     service-url:
-      defaultZone: http://pig:pig@pigx-eureka:1025/eureka/
+      defaultZone: http://pig:pig@localhost:1025/eureka/
 
 

+ 1 - 1
pigx-upms/pigx-upms-biz/src/main/resources/bootstrap.yml

@@ -23,4 +23,4 @@ eureka:
     prefer-ip-address: true
   client:
     service-url:
-      defaultZone: http://pig:pig@pigx-eureka:1025/eureka/
+      defaultZone: http://pig:pig@localhost:1025/eureka/

+ 1 - 1
pigx-visual/pigx-codegen/src/main/resources/bootstrap.yml

@@ -20,7 +20,7 @@ eureka:
     prefer-ip-address: true
   client:
     service-url:
-      defaultZone: http://pig:pig@pigx-eureka:1025/eureka/
+      defaultZone: http://pig:pig@localhost:1025/eureka/
 logging:
   level:
     root: debug

+ 1 - 1
pigx-visual/pigx-daemon/src/main/resources/bootstrap.yml

@@ -20,4 +20,4 @@ eureka:
     prefer-ip-address: true
   client:
     service-url:
-      defaultZone: http://pig:pig@pigx-eureka:1025/eureka/
+      defaultZone: http://pig:pig@localhost:1025/eureka/

+ 1 - 1
pigx-visual/pigx-monitor/src/main/resources/bootstrap.yml

@@ -20,4 +20,4 @@ eureka:
     prefer-ip-address: true
   client:
     service-url:
-      defaultZone: http://pig:pig@pigx-eureka:1025/eureka/
+      defaultZone: http://pig:pig@localhost:1025/eureka/