Просмотр исходного кода

:sparkles: 添加新特性。手机号登录后端代码

冷冷 7 лет назад
Родитель
Сommit
933da71ff0

+ 40 - 2
pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/WebSecurityConfigurer.java

@@ -19,15 +19,24 @@
 
 package com.pig4cloud.pigx.auth.config;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.pig4cloud.pigx.common.security.mobile.MobileLoginSuccessHandler;
+import com.pig4cloud.pigx.common.security.mobile.MobileSecurityConfigurer;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.context.annotation.Primary;
 import org.springframework.core.annotation.Order;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.crypto.factory.PasswordEncoderFactories;
 import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.provider.ClientDetailsService;
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
 
 /**
  * @author lengleng
@@ -38,14 +47,27 @@ import org.springframework.security.crypto.password.PasswordEncoder;
 @Order(90)
 @Configuration
 public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
+	@Autowired
+	private ObjectMapper objectMapper;
+	@Autowired
+	private ClientDetailsService clientDetailsService;
+	@Autowired
+	private UserDetailsService pigxUserDetailsServiceImpl;
+	@Lazy
+	@Autowired
+	private AuthorizationServerTokenServices defaultAuthorizationServerTokenServices;
 
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
 		http
 			.authorizeRequests()
-			.antMatchers("/actuator/**", "/oauth/removeToken").permitAll()
+			.antMatchers(
+				"/actuator/**",
+				"/oauth/remvoveToken",
+				"/mobile/**").permitAll()
 			.anyRequest().authenticated()
-			.and().csrf().disable();
+			.and().csrf().disable()
+			.apply(mobileSecurityConfigurer());
 	}
 
 	@Bean
@@ -54,6 +76,22 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
 		return super.authenticationManagerBean();
 	}
 
+	@Bean
+	public AuthenticationSuccessHandler mobileLoginSuccessHandler() {
+		return MobileLoginSuccessHandler.builder()
+			.objectMapper(objectMapper)
+			.clientDetailsService(clientDetailsService)
+			.passwordEncoder(passwordEncoder())
+			.defaultAuthorizationServerTokenServices(defaultAuthorizationServerTokenServices).build();
+	}
+
+	@Bean
+	public MobileSecurityConfigurer mobileSecurityConfigurer() {
+		return new MobileSecurityConfigurer(mobileLoginSuccessHandler()
+			, pigxUserDetailsServiceImpl);
+	}
+
+
 	/**
 	 * https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#password-storage-updated
 	 * Encoded password does not look like BCrypt

+ 1 - 0
pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/RevokeTokenEndpoint.java

@@ -54,6 +54,7 @@ public class RevokeTokenEndpoint {
 			}
 			tokenStore.removeAccessToken(accessToken);
 		}
+
 		return new R<>(Boolean.TRUE);
 	}
 }

+ 4 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java

@@ -74,4 +74,8 @@ public interface SecurityConstants {
 	 */
 	String DEFAULT_SELECT_STATEMENT = BASE_FIND_STATEMENT + " where client_id = ?";
 
+	/**
+	 * 手机号登录URL
+	 */
+	String MOBILE_TOKEN_URL = "/mobile/token";
 }

+ 83 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationFilter.java

@@ -0,0 +1,83 @@
+/*
+ *    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 com.pig4cloud.pigx.common.core.constant.SecurityConstants;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationServiceException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author lengleng
+ * @date 2018/1/9
+ * 手机号登录验证filter
+ */
+public class MobileAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
+	private static final String SPRING_SECURITY_FORM_MOBILE_KEY = "mobile";
+	@Getter
+	@Setter
+	private String mobileParameter = SPRING_SECURITY_FORM_MOBILE_KEY;
+	@Getter
+	@Setter
+	private boolean postOnly = true;
+
+	public MobileAuthenticationFilter() {
+		super(new AntPathRequestMatcher(SecurityConstants.MOBILE_TOKEN_URL, "POST"));
+	}
+
+	@Override
+	public Authentication attemptAuthentication(HttpServletRequest request,
+												HttpServletResponse response) throws AuthenticationException {
+		if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
+			throw new AuthenticationServiceException(
+				"Authentication method not supported: " + request.getMethod());
+		}
+
+		String mobile = obtainMobile(request);
+
+		if (mobile == null) {
+			mobile = "";
+		}
+
+		mobile = mobile.trim();
+
+		MobileAuthenticationToken mobileAuthenticationToken = new MobileAuthenticationToken(mobile);
+
+		setDetails(request, mobileAuthenticationToken);
+
+		return this.getAuthenticationManager().authenticate(mobileAuthenticationToken);
+	}
+
+	private String obtainMobile(HttpServletRequest request) {
+		return request.getParameter(mobileParameter);
+	}
+
+	private void setDetails(HttpServletRequest request,
+							MobileAuthenticationToken authRequest) {
+		authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
+	}
+}
+

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

@@ -0,0 +1,51 @@
+/*
+ *    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 lombok.Getter;
+import lombok.Setter;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+
+/**
+ * @author lengleng
+ * @date 2018/8/5
+ * 手机号登录校验逻辑
+ */
+public class MobileAuthenticationProvider implements AuthenticationProvider {
+	@Getter
+	@Setter
+	private UserDetailsService userDetailsService;
+
+	@Override
+	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+		MobileAuthenticationToken mobileAuthenticationToken = (MobileAuthenticationToken) authentication;
+		UserDetails userDetails = userDetailsService.loadUserByUsername("admin");
+		MobileAuthenticationToken authenticationToken = new MobileAuthenticationToken(userDetails, userDetails.getAuthorities());
+		authenticationToken.setDetails(mobileAuthenticationToken.getDetails());
+		return authenticationToken;
+	}
+
+	@Override
+	public boolean supports(Class<?> authentication) {
+		return MobileAuthenticationToken.class.isAssignableFrom(authentication);
+	}
+}

+ 75 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileAuthenticationToken.java

@@ -0,0 +1,75 @@
+/*
+ *    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.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.SpringSecurityCoreVersion;
+
+import java.util.Collection;
+
+/**
+ * @author lengleng
+ * @date 2018/1/9
+ * 手机号登录令牌
+ */
+public class MobileAuthenticationToken extends AbstractAuthenticationToken {
+
+    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
+
+    private final Object principal;
+
+    public MobileAuthenticationToken(String mobile) {
+        super(null);
+        this.principal = mobile;
+        setAuthenticated(false);
+    }
+
+    public MobileAuthenticationToken(Object principal,
+									 Collection<? extends GrantedAuthority> authorities) {
+        super(authorities);
+        this.principal = principal;
+        super.setAuthenticated(true);
+    }
+
+    @Override
+    public Object getPrincipal() {
+        return this.principal;
+    }
+
+    @Override
+    public Object getCredentials() {
+        return null;
+    }
+
+    @Override
+    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
+        if (isAuthenticated) {
+            throw new IllegalArgumentException(
+                    "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
+        }
+
+        super.setAuthenticated(false);
+    }
+
+    @Override
+    public void eraseCredentials() {
+        super.eraseCredentials();
+    }
+}
+

+ 106 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileLoginSuccessHandler.java

@@ -0,0 +1,106 @@
+/*
+ *    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 cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.CharsetUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.pig4cloud.pigx.common.core.constant.CommonConstant;
+import com.pig4cloud.pigx.common.security.util.AuthUtils;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
+import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
+import org.springframework.security.oauth2.provider.*;
+import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @author lengleng
+ * @date 2018/8/5
+ * 手机号登录成功,返回oauth token
+ */
+@Slf4j
+@Builder
+public class MobileLoginSuccessHandler implements AuthenticationSuccessHandler {
+	private static final String BASIC_ = "Basic ";
+	private ObjectMapper objectMapper;
+	private PasswordEncoder passwordEncoder;
+	private ClientDetailsService clientDetailsService;
+	private AuthorizationServerTokenServices defaultAuthorizationServerTokenServices;
+
+	/**
+	 * Called when a user has been successfully authenticated.
+	 * 调用spring security oauth API 生成 oAuth2AccessToken
+	 *
+	 * @param request        the request which caused the successful authentication
+	 * @param response       the response
+	 * @param authentication the <tt>Authentication</tt> object which was created during
+	 */
+	@Override
+	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
+		String header = request.getHeader("Authorization");
+
+		if (header == null || !header.startsWith(BASIC_)) {
+			throw new UnapprovedClientAuthenticationException("请求头中client信息为空");
+		}
+
+		try {
+			String[] tokens = AuthUtils.extractAndDecodeHeader(header);
+			assert tokens.length == 2;
+			String clientId = tokens[0];
+
+			ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
+
+			//校验secret
+			if (!passwordEncoder.matches(tokens[1], clientDetails.getClientSecret())) {
+				throw new InvalidClientException("Given client ID does not match authenticated client");
+
+			}
+
+			TokenRequest tokenRequest = new TokenRequest(MapUtil.newHashMap(), clientId, clientDetails.getScope(), "mobile");
+
+			//校验scope
+			new DefaultOAuth2RequestValidator().validateScope(tokenRequest, clientDetails);
+			OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
+			OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
+			OAuth2AccessToken oAuth2AccessToken = defaultAuthorizationServerTokenServices.createAccessToken(oAuth2Authentication);
+			log.info("获取token 成功:{}", oAuth2AccessToken.getValue());
+
+			response.setCharacterEncoding(CharsetUtil.UTF_8);
+			response.setContentType(CommonConstant.CONTENT_TYPE);
+			PrintWriter printWriter = response.getWriter();
+			printWriter.append(objectMapper.writeValueAsString(oAuth2AccessToken));
+		} catch (IOException e) {
+			throw new BadCredentialsException(
+				"Failed to decode basic authentication token");
+		}
+	}
+
+
+}

+ 52 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/mobile/MobileSecurityConfigurer.java

@@ -0,0 +1,52 @@
+/*
+ *    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 lombok.AllArgsConstructor;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.web.DefaultSecurityFilterChain;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author lengleng
+ * @date 2018/8/5
+ * 手机号登录配置入口
+ */
+@Component
+@AllArgsConstructor
+public class MobileSecurityConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
+	private AuthenticationSuccessHandler mobileLoginSuccessHandler;
+	private UserDetailsService userDetailsService;
+
+	@Override
+	public void configure(HttpSecurity http) {
+		MobileAuthenticationFilter mobileAuthenticationFilter = new MobileAuthenticationFilter();
+		mobileAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
+		mobileAuthenticationFilter.setAuthenticationSuccessHandler(mobileLoginSuccessHandler);
+
+		MobileAuthenticationProvider mobileAuthenticationProvider = new MobileAuthenticationProvider();
+		mobileAuthenticationProvider.setUserDetailsService(userDetailsService);
+		http.authenticationProvider(mobileAuthenticationProvider)
+			.addFilterAfter(mobileAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
+	}
+}

+ 82 - 0
pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/AuthUtils.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.util;
+
+import cn.hutool.core.util.CharsetUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.crypto.codec.Base64;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * @author lengleng
+ * @date 2018/5/13
+ * 认证授权相关工具类
+ */
+@Slf4j
+public class AuthUtils {
+	private static final String BASIC_ = "Basic ";
+
+	/**
+	 * 从header 请求中的clientId/clientsecect
+	 *
+	 * @param header header中的参数
+	 * @throws RuntimeException if the Basic header is not present or is not valid
+	 *                          Base64
+	 */
+	public static String[] extractAndDecodeHeader(String header)
+		throws IOException {
+
+		byte[] base64Token = header.substring(6).getBytes("UTF-8");
+		byte[] decoded;
+		try {
+			decoded = Base64.decode(base64Token);
+		} catch (IllegalArgumentException e) {
+			throw new RuntimeException(
+				"Failed to decode basic authentication token");
+		}
+
+		String token = new String(decoded, CharsetUtil.UTF_8);
+
+		int delim = token.indexOf(":");
+
+		if (delim == -1) {
+			throw new RuntimeException("Invalid basic authentication token");
+		}
+		return new String[]{token.substring(0, delim), token.substring(delim + 1)};
+	}
+
+	/**
+	 * *从header 请求中的clientId/clientsecect
+	 *
+	 * @param request
+	 * @return
+	 * @throws IOException
+	 */
+	public static String[] extractAndDecodeHeader(HttpServletRequest request)
+		throws IOException {
+		String header = request.getHeader("Authorization");
+
+		if (header == null || !header.startsWith(BASIC_)) {
+			throw new RuntimeException("请求头中client信息为空");
+		}
+
+		return extractAndDecodeHeader(header);
+	}
+}

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

@@ -88,10 +88,12 @@ swagger:
       - scope: 'server'
         description: 'server all'
     token-url-list:
-      - ${security.oauth2.resource.token-info-uri}
+      - ${security.auth.server}/token
 
 ## spring security 配置
 security:
+  auth:
+    server: http://localhost:9999/auth/oauth
   oauth2:
     resource:
-      token-info-uri: http://localhost:9999/auth/oauth/check_token
+      token-info-uri: ${security.auth.server}/check_token

+ 0 - 10
pigx-visual/pigx-codegen/src/main/resources/mapper/SysGeneratorMapper.xml

@@ -9,16 +9,6 @@
 			and table_name like concat('%', #{tableName}, '%')
 		</if>
 		order by create_time desc
-		<if test="offset != null and limit != null">
-			limit #{offset}, #{limit}
-		</if>
-	</select>
-
-	<select id="queryTotal" resultType="int">
-		select count(*) from information_schema.tables where table_schema = (select database())
-		<if test="tableName != null and tableName.trim() != ''">
-			and table_name like concat('%', #{tableName}, '%')
-		</if>
 	</select>
 
 	<select id="queryTable" resultType="map">