commit 3eb965f380b239fb4de243fa83133ea0f2387b63 Author: JOETION <1322874562@qq.com> Date: Wed Jan 20 18:30:23 2021 +0800 初始化提交 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cbbb146 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +target/ +**/target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +*.iml +.idea +modules/log +modules/logs +.project +.settings +.classpath +logs +out +application.yml +bootstrap.yml diff --git a/auth/authentication-client/.gitignore b/auth/authentication-client/.gitignore new file mode 100644 index 0000000..3a05198 --- /dev/null +++ b/auth/authentication-client/.gitignore @@ -0,0 +1,16 @@ +target/ +logs/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr diff --git a/auth/authentication-client/pom.xml b/auth/authentication-client/pom.xml new file mode 100644 index 0000000..640c967 --- /dev/null +++ b/auth/authentication-client/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + + business.chaoran + authentication-client + 0.0.1-SNAPSHOT + jar + + authentication-client + Demo Oauth2 project for Spring Cloud Oauth2 Authentication Client + + + UTF-8 + UTF-8 + 1.8 + 1.8 + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/libs-milestone + + false + + + + + + + + org.springframework.cloud + spring-cloud-openfeign + 2.0.0.RC2 + pom + import + + + + + + + business.chaoran + core + 0.0.1-SNAPSHOT + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + io.github.openfeign + feign-okhttp + + + org.projectlombok + lombok + RELEASE + provided + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + junit + junit + 4.12 + test + + + org.mockito + mockito-core + 1.10.19 + + + diff --git a/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/config/FeignOkHttpConfig.java b/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/config/FeignOkHttpConfig.java new file mode 100644 index 0000000..d78dced --- /dev/null +++ b/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/config/FeignOkHttpConfig.java @@ -0,0 +1,37 @@ +package com.springboot.cloud.auth.client.config; + +import feign.Feign; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.cloud.openfeign.FeignAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.concurrent.TimeUnit; + +@AutoConfigureBefore(FeignAutoConfiguration.class) +@Configuration +@ConditionalOnClass(Feign.class) +/**** + * 需要修改成OKHTTP的客户端,需要在配置文件增加 + * feign.httpclient.enabled=false + feign.okhttp.enabled=true + */ +public class FeignOkHttpConfig { + + private int feignOkHttpReadTimeout = 60; + private int feignConnectTimeout = 60; + private int feignWriteTimeout = 120; + + //如果此处定义拦截器,则服务之间相互调用控制不了,此模块仅用于远程授权 + @Bean + public okhttp3.OkHttpClient okHttpClient() { + return new okhttp3.OkHttpClient.Builder() + .readTimeout(feignOkHttpReadTimeout, TimeUnit.SECONDS) + .connectTimeout(feignConnectTimeout, TimeUnit.SECONDS) + .writeTimeout(feignWriteTimeout, TimeUnit.SECONDS) +// .connectionPool(new ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit)) //自定义链接池 +// .addInterceptor(XXXXXXXInterceptor) //自定义拦截器 + .build(); + } +} diff --git a/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/provider/AuthProvider.java b/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/provider/AuthProvider.java new file mode 100644 index 0000000..1ced0a9 --- /dev/null +++ b/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/provider/AuthProvider.java @@ -0,0 +1,54 @@ +package com.springboot.cloud.auth.client.provider; + +import com.springboot.cloud.common.core.entity.vo.Result; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +@Component +@FeignClient(name = "authentication-server", fallback = AuthProvider.AuthProviderFallback.class, path = "authentication-server") +//@FeignClient(name = "authentication-server", fallback = AuthProvider.AuthProviderFallback.class) +public interface AuthProvider { + /** + * 调用签权服务,判断用户是否有权限 + * + * @param authentication + * @param url + * @param companyId + * @return
+     * Result:
+     * {
+     *   code:"000000"
+     *   mesg:"请求成功"
+     *   data: true/false
+     * }
+     * 
+ */ + @PostMapping(value = "/auth/permission") + Result auth(@RequestParam("companyId") String companyId, @RequestHeader(HttpHeaders.AUTHORIZATION) String authentication, @RequestParam("url") String url); + + @Component + class AuthProviderFallback implements AuthProvider { + /** + * 降级统一返回无权限 + * + * @param authentication + * @param url + * @param companyId + * @return
+         * Result:
+         * {
+         *   code:"-1"
+         *   mesg:"系统异常"
+         * }
+         * 
+ */ + @Override + public Result auth(String authentication, String url, String companyId) { + return Result.fail(); + } + } +} diff --git a/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/service/IAuthService.java b/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/service/IAuthService.java new file mode 100644 index 0000000..8ae9bab --- /dev/null +++ b/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/service/IAuthService.java @@ -0,0 +1,60 @@ +package com.springboot.cloud.auth.client.service; + +import com.springboot.cloud.common.core.entity.vo.Result; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; + +public interface IAuthService { + /** + * 调用签权服务,判断用户是否有权限 + * + * @param authentication + * @param url + * @return Result + */ + Result authenticate(String companyId,String authentication, String url); + + /** + * 判断url是否在忽略的范围内 + * 只要是配置中的开头,即返回true + * + * @param url + * @return + */ + boolean ignoreAuthentication(String url); + + /** + * 查看签权服务器返回结果,有权限返回true + * + * @param authResult + * @return + */ + boolean hasPermission(Result authResult); + + /** + * 调用签权服务,判断用户是否有权限 + * + * + * @param companyId + * @param authentication + * @param url + * @return true/false + */ + boolean hasPermission(String companyId,String authentication, String url); + + /** + * 是否无效authentication + * + * @param authentication + * @return + */ + boolean invalidJwtAccessToken(String authentication); + + /** + * 从认证信息中提取jwt token 对象 + * + * @param jwtToken toke信息 header.payload.signature + * @return Jws对象 + */ + Jws getJwt(String jwtToken); +} diff --git a/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/service/impl/AuthService.java b/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/service/impl/AuthService.java new file mode 100644 index 0000000..270ddeb --- /dev/null +++ b/auth/authentication-client/src/main/java/com/springboot/cloud/auth/client/service/impl/AuthService.java @@ -0,0 +1,92 @@ +package com.springboot.cloud.auth.client.service.impl; + +import com.springboot.cloud.auth.client.provider.AuthProvider; +import com.springboot.cloud.auth.client.service.IAuthService; +import com.springboot.cloud.common.core.entity.vo.Result; +import io.jsonwebtoken.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.stream.Stream; + +@Service +@Slf4j +public class AuthService implements IAuthService { + /** + * Authorization认证开头是"bearer " + */ + private static final String BEARER = "Bearer "; + + @Autowired + private AuthProvider authProvider; + + /** + * jwt token 密钥,主要用于token解析,签名验证 + */ + @Value("${spring.security.oauth2.jwt.signingKey}") + private String signingKey; + + /** + * 不需要网关签权的url配置(/oauth,/open) + * 默认/oauth开头是不需要的 + */ + @Value("${gate.ignore.authentication.startWith}") + private String ignoreUrls = "/oauth"; + + @Override + public Result authenticate(String companyId,String authentication, String url) { + return authProvider.auth(companyId,authentication, url); + } + + @Override + public boolean ignoreAuthentication(String url) { + return Stream.of(this.ignoreUrls.split(",")).anyMatch(ignoreUrl -> url.startsWith(StringUtils.trim(ignoreUrl))); + } + + @Override + public boolean hasPermission(Result authResult) { + log.debug("签权结果:{}", authResult.getData()); + return authResult.isSuccess() && (boolean) authResult.getData(); + } + + @Override + public boolean hasPermission(String companyId, String authentication, String url) { + // 如果请求未携带token信息, 直接权限 + if (StringUtils.isBlank(authentication) || !authentication.startsWith(BEARER)) { + log.error("user token is null"); + return Boolean.FALSE; + } + //token是否有效,在网关进行校验,无效/过期等 + if (invalidJwtAccessToken(authentication)) { + return Boolean.FALSE; + } + //从认证服务获取是否有权限,远程调用 + return hasPermission(authenticate(companyId,authentication, url)); + } + + @Override + public Jws getJwt(String jwtToken) { + if (jwtToken.startsWith(BEARER)) { + jwtToken = StringUtils.substring(jwtToken, BEARER.length()); + } + return Jwts.parser() //得到DefaultJwtParser + .setSigningKey(signingKey.getBytes()) //设置签名的秘钥 + .parseClaimsJws(jwtToken); + } + + @Override + public boolean invalidJwtAccessToken(String authentication) { + // 是否无效true表示无效 + boolean invalid = Boolean.TRUE; + try { + getJwt(authentication); + invalid = Boolean.FALSE; + } catch (SignatureException | ExpiredJwtException | MalformedJwtException ex) { + log.error("user token error :{}", ex.getMessage()); + } + return invalid; + } +} diff --git a/auth/authentication-client/src/test/java/com/springboot/cloud/auth/client/service/impl/AuthServiceTest.java b/auth/authentication-client/src/test/java/com/springboot/cloud/auth/client/service/impl/AuthServiceTest.java new file mode 100644 index 0000000..1c2d190 --- /dev/null +++ b/auth/authentication-client/src/test/java/com/springboot/cloud/auth/client/service/impl/AuthServiceTest.java @@ -0,0 +1,111 @@ +package com.springboot.cloud.auth.client.service.impl; + +import com.springboot.cloud.auth.client.provider.AuthProvider; +import com.springboot.cloud.auth.client.service.IAuthService; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.lang.reflect.Field; + +public class AuthServiceTest { + + @InjectMocks + IAuthService authService; + + @Mock + AuthProvider authProvider; + + private static final String VALID_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiXSwib3JnYW5pemF0aW9uIjoiYWRtaW4iLCJleHAiOjEzNTcyMDIxNjM3LCJhdXRob3JpdGllcyI6WyJBRE1JTiJdLCJqdGkiOiI4MzcyMzI0Ny00ZDA5LTQ0YjYtYTNlOS01OGUzYzZiMGUzYjIiLCJjbGllbnRfaWQiOiJ0ZXN0X2NsaWVudCJ9.IkOtKapS5PJLKU1NfiqVSCgsQngE7qGnIx1NziJMvVA"; + private static final String BEARER = "Bearer "; + + @Before + public void before() throws NoSuchFieldException, IllegalAccessException { + authService = new AuthService(); + setInstancePrivateField(authService, "signingKey", "123456"); + setInstancePrivateField(authService, "ignoreUrls", "/oauth,/open"); + MockitoAnnotations.initMocks(this); + } + + private void setInstancePrivateField(Object instance, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException { + Field signingKeyField = instance.getClass().getDeclaredField(fieldName); + signingKeyField.setAccessible(true); + signingKeyField.set(instance, value); + } + + @Test + public void testInvalidJwtAccessToken_假如授权服务通过给定密钥生成了token_当输入该token组成的authentication_那么返回false表示token有效() { + Assert.assertFalse(authService.invalidJwtAccessToken(BEARER + VALID_TOKEN)); + } + + @Test + public void testInvalidJwtAccessToken_假如_当输入随机字串_那么返回true表示token无效() { + String authentication = BEARER + "im random string"; + Assert.assertTrue(authService.invalidJwtAccessToken(authentication)); + } + + @Test + public void testInvalidJwtAccessToken_假如有人获取用户token_当输入篡改过playload中信息_那么返回true表示token无效() { + String authentication = BEARER + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.111eyJGc2VyX25hbWUiOiJ6aG91dGFvbyIsInNjb3BlIjpbInJlYWQiXSwib3JnYW5pemF0aW9uIjoiemhvdXRhb28iLCJleHAiOjE1Mjc0NTM5NDQsImF1dGhvcml0aWVzIjpbIkFETUlOIiwiSVQiXSwianRpIjoiZTZiNzM5ZmUtYWEzZC00Y2RmLWIxZjUtNzZkMmVlMjU0ODU1IiwiY2xpZW50X2lkIjoidGVzdF9jbGllbnQifQ.l6PQrs98zT40H6Ad4NHE7NSXyeWnMn-ZhURw3zO-EfE"; + Assert.assertTrue(authService.invalidJwtAccessToken(authentication)); + } + + @Test + public void testInvalidJwtAccessToken_假如有人获取用户token_当输入token去掉了signature_那么返回true表示token无效() { + String authentication = BEARER + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ6aG91dGFvbyIsInNjb3BlIjpbInJlYWQiXSwib3JnYW5pemF0aW9uIjoiemhvdXRhb28iLCJleHAiOjE1Mjc0NTM5NDQsImF1dGhvcml0aWVzIjpbIkFETUlOIiwiSVQiXSwianRpIjoiZTZiNzM5ZmUtYWEzZC00Y2RmLWIxZjUtNzZkMmVlMjU0ODU1IiwiY2xpZW50X2lkIjoidGVzdF9jbGllbnQifQ"; + Assert.assertTrue(authService.invalidJwtAccessToken(authentication)); + } + + @Test + public void testAuthenticate_假如用户authentication正确且有对请求url有权限_当用户请求该url_那么返回成功有权限() { +// when(authProvider.auth(BEARER + VALID_TOKEN, "/users", , "POST")).thenReturn(Result.success(true)); + Assert.assertTrue((Boolean) authService.authenticate(BEARER + VALID_TOKEN, "/users", "POST").getData()); + } + + @Test + public void testAuthenticate_假如用户authentication正确且有对请求url只有POST权限_当用户请求该url的GET_那么返回成功无权限() { +// when(authProvider.auth(BEARER + VALID_TOKEN, "/users", , "GET")).thenReturn(Result.success(false)); + Assert.assertFalse((Boolean) authService.authenticate(BEARER + VALID_TOKEN, "/users", "GET").getData()); + } + + @Test + public void testHasPermission_假如_当传入无效token_那么返回无权限() { +// Assert.assertFalse(authService.hasPermission(, "invalid token", "/users")); + } + + @Test + public void testHasPermission_假如用户authentication正确且有对请求url有权限_当用户请求该url_那么返回成功有权限() { +// when(authProvider.auth(BEARER + VALID_TOKEN, "/users", , "POST")).thenReturn(Result.success(true)); +// Assert.assertTrue(authService.hasPermission(, BEARER + VALID_TOKEN, "/users")); + } + + @Test + public void testHasPermission_假如用户authentication正确且有对请求url只有POST权限_当用户请求该url的GET_那么返回成功无权限() { +// when(authProvider.auth(BEARER + VALID_TOKEN, "/users", , "GET")).thenReturn(Result.success(false)); +// Assert.assertFalse(authService.hasPermission(, BEARER + VALID_TOKEN, "/users")); + } + + @Test + public void testIgnoreAuthentication_假如配置的忽略前缀为oauth和open_当用户请求以oauth开头的url_那么返回返回true() { + Assert.assertTrue(authService.ignoreAuthentication("/oauth/token?test=123")); + } + + @Test + public void testIgnoreAuthentication_假如配置的忽略前缀为oauth和open_当用户请求以open开头的url_那么返回返回true() { + Assert.assertTrue(authService.ignoreAuthentication("/open/")); + } + + @Test + public void testIgnoreAuthentication_假如配置的忽略前缀为oauth和open_当用户请求以test开头的url_那么返回返回true() { + Assert.assertFalse(authService.ignoreAuthentication("/test")); + } + + @Test + public void testIgnoreAuthentication_假如配置的忽略前缀为oauth和open_当用户请求以open结尾的url_那么返回返回true() { + Assert.assertFalse(authService.ignoreAuthentication("/test/open")); + } + +} \ No newline at end of file diff --git a/auth/authentication-server/.gitignore b/auth/authentication-server/.gitignore new file mode 100644 index 0000000..3a05198 --- /dev/null +++ b/auth/authentication-server/.gitignore @@ -0,0 +1,16 @@ +target/ +logs/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr diff --git a/auth/authentication-server/pom.xml b/auth/authentication-server/pom.xml new file mode 100644 index 0000000..fb14c2f --- /dev/null +++ b/auth/authentication-server/pom.xml @@ -0,0 +1,107 @@ + + + 4.0.0 + + business.chaoran + authentication-server + 0.0.1-SNAPSHOT + war + + + authentication-server + Demo Oauth2 project for Spring Cloud Oauth2 Authentication Server + + + business.chaoran + auth + 0.0.1-SNAPSHOT + + + + + business.chaoran + web + 0.0.1-SNAPSHOT + + + + org.springframework.cloud + spring-cloud-security + + + + io.springfox + springfox-swagger2 + + + io.springfox + springfox-swagger-ui + + + + com.alicp.jetcache + jetcache-starter-redis + + + + + + + + + + + + org.slf4j + slf4j-simple + compile + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + org.springframework.boot + spring-boot-starter-logging + + + + + javax.servlet + javax.servlet-api + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.1.4.RELEASE + + + + build-info + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.0.0 + + + authentication-server + + + + diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/Oauth2AuthenticationApplication.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/Oauth2AuthenticationApplication.java new file mode 100644 index 0000000..b9861c4 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/Oauth2AuthenticationApplication.java @@ -0,0 +1,24 @@ +package com.springboot.cloud.auth.authentication; + +import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; + +@SpringBootApplication +@EnableDiscoveryClient +@EnableFeignClients +@EnableCreateCacheAnnotation +public class Oauth2AuthenticationApplication extends SpringBootServletInitializer{ + public static void main(String[] args) { + SpringApplication.run(Oauth2AuthenticationApplication.class, args); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { + return builder.sources(Oauth2AuthenticationApplication.class); + } +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/BusConfig.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/BusConfig.java new file mode 100644 index 0000000..5372fbc --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/BusConfig.java @@ -0,0 +1,104 @@ +package com.springboot.cloud.auth.authentication.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.springboot.cloud.auth.authentication.events.BusReceiver; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.*; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; +import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 消息设置 + */ +@Configuration +@Slf4j +public class BusConfig { + + private static final String EXCHANGE_NAME = "spring-boot-exchange"; + private static final String ROUTING_KEY = "organization-popedom"; + + @Value("${spring.application.name}") + private String appName; + + + /** + * 配置监听队列,mq只能直接监听队列,不能直接监听交换机 + * @return 队列 + */ + @Bean + Queue queue() { + String queueName = new Base64UrlNamingStrategy(appName + ".").generateName(); + log.info("queue name:{}", queueName); + return new Queue(queueName, false); + } + + /** + * 采用主题交换机 + * @return 主题交换机 + */ + @Bean + TopicExchange exchange() { + log.info("exchange:{}", EXCHANGE_NAME); + return new TopicExchange(EXCHANGE_NAME); + } + + /** + * 将队列绑定到主题交换机上,以router_key作为键 + * @param queue + * @param exchange + * @return + */ + @Bean + Binding binding(Queue queue, TopicExchange exchange) { + log.info("binding {} to {} with {}", queue, exchange, ROUTING_KEY); + return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY); + } + + /** + * 设置消息处理监听器 + * @param connectionFactory mq连接工厂,用于配置mq服务器地址,端口,连接关闭或者断开监听器等等 + * @param messageListenerAdapter 消息监听适配器,用于收到消息后对消息进行处理,或者是代理到其他对象进行处理的适配器,默认处理方法为handleMessage + * @param queue 消息接收队列,可以配置多个队列 + * @return 消息监听容器,可以设置消费者数量、最大最小数量、批量消费等等 + */ + @Bean + SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory, MessageListenerAdapter messageListenerAdapter, Queue queue) { + log.info("init simpleMessageListenerContainer {}", queue.getName()); + SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); + container.setQueueNames(queue.getName()); + container.setMessageListener(messageListenerAdapter); + return container; + } + + /** + * 设置消息监听适配器 + * @param busReceiver 处理消息的代理对象 + * @param messageConverter 消息转换器,此处用Jackson作为json转换工具类 + * @return + */ + @Bean + MessageListenerAdapter messageListenerAdapter(BusReceiver busReceiver, MessageConverter messageConverter) { + log.info("new listener"); + return new MessageListenerAdapter(busReceiver, messageConverter); + } + + /** + * 消息转换器 + * @return Jackson转换器 + */ + @Bean + public MessageConverter messageConverter() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + return new ContentTypeDelegatingMessageConverter(new Jackson2JsonMessageConverter(objectMapper)); + } +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/InterceptConfig.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/InterceptConfig.java new file mode 100644 index 0000000..82e83ae --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/InterceptConfig.java @@ -0,0 +1,21 @@ +package com.springboot.cloud.auth.authentication.config; + +/* + ********************************************** + * DATE PERSON REASON + * 2020/12/7 FXY Created + ********************************************** + */ + +import com.springboot.cloud.common.web.interceptor.FeignBasicAuthRequestInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class InterceptConfig { + + @Bean + public FeignBasicAuthRequestInterceptor interceptor(){ + return new FeignBasicAuthRequestInterceptor(); + } +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/LoadResourceDefine.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/LoadResourceDefine.java new file mode 100644 index 0000000..431c362 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/LoadResourceDefine.java @@ -0,0 +1,19 @@ +package com.springboot.cloud.auth.authentication.config; + +import com.springboot.cloud.auth.authentication.service.PopedomService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +class LoadResourceDefine { + + @Autowired + private PopedomService popedomService; + + @PostConstruct + public void resourceConfigAttributes() { + popedomService.loadPopedom(); + } +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/NacosRegisterConfig.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/NacosRegisterConfig.java new file mode 100644 index 0000000..dcc6432 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/NacosRegisterConfig.java @@ -0,0 +1,56 @@ +package com.springboot.cloud.auth.authentication.config; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-24 FXY Created + ********************************************** + */ + +import com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.annotation.Configuration; + +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.Query; +import java.lang.management.ManagementFactory; +import java.util.Set; + +@Configuration +@Slf4j +public class NacosRegisterConfig implements ApplicationRunner { + + @Autowired(required = false) + private NacosAutoServiceRegistration registration; + + private Integer port; + + public NacosRegisterConfig() { + try { + this.port = Integer.parseInt(getTomcatPort()); + } catch (Exception e) { + log.error("获取tomcat端口出错了,原因:{}", e.toString()); + } + } + + @Override + public void run(ApplicationArguments args) { + if (registration != null && port != null) { + registration.setPort(port); + registration.start(); + } + } + + //获取tomcat端口 + private String getTomcatPort() throws Exception { + MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer(); + Set objectNames = beanServer.queryNames(new ObjectName("*:type=Connector,*"), Query.match(Query.attr("protocol"), Query.value("HTTP/1.1"))); + String port = objectNames.iterator().next().getKeyProperty("port"); + return port; + } + +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/ResourceServerConfig.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/ResourceServerConfig.java new file mode 100644 index 0000000..7bbf9d7 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/config/ResourceServerConfig.java @@ -0,0 +1,51 @@ +package com.springboot.cloud.auth.authentication.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; +import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; +import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; + +@Slf4j +@Configuration +@EnableResourceServer +public class ResourceServerConfig extends ResourceServerConfigurerAdapter { + + @Value("${spring.security.oauth2.jwt.signingKey}") + private String signingKey; + + @Override + public void configure(ResourceServerSecurityConfigurer resourceServerSecurityConfigurer) { + resourceServerSecurityConfigurer + .tokenStore(tokenStore()) + .resourceId("WEBS"); + } + + @Override + public void configure(HttpSecurity http) throws Exception { + log.debug("HttpSecurity configure method"); + http.csrf().disable(); + http.authorizeRequests() + .antMatchers("/actuator/**").permitAll() + .antMatchers("/v2/api-docs").permitAll() + .anyRequest().authenticated(); + } + + @Bean + public TokenStore tokenStore() { + return new JwtTokenStore(accessTokenConverter()); + } + + @Bean + public JwtAccessTokenConverter accessTokenConverter() { + JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); + converter.setSigningKey(signingKey); + return converter; + } +} \ No newline at end of file diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/entity/License.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/entity/License.java new file mode 100644 index 0000000..a1921f6 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/entity/License.java @@ -0,0 +1,26 @@ +package com.springboot.cloud.auth.authentication.entity; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +@Data +@NoArgsConstructor +public class License { + private String companyId; + private String franchiserId; + private String applicationCode; + private String grade; + private Date expireDate; + private boolean isForever; + private String state; +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/entity/Popedom.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/entity/Popedom.java new file mode 100644 index 0000000..60c0d27 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/entity/Popedom.java @@ -0,0 +1,32 @@ +package com.springboot.cloud.auth.authentication.entity; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class Popedom { + private String id; + private String applicationCode; + private String name; + private String parentId; + private String url; + private String icon; + private String isMenu; + private String description; + private String path; + private String redirect; + private String component; + private String title; + private boolean alwaysShow; + private boolean hidden; + private String companyId; + private Integer orderNo; +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/events/BusReceiver.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/events/BusReceiver.java new file mode 100644 index 0000000..eb5d8f2 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/events/BusReceiver.java @@ -0,0 +1,30 @@ +package com.springboot.cloud.auth.authentication.events; + +import com.springboot.cloud.auth.authentication.entity.Popedom; +import com.springboot.cloud.auth.authentication.service.PopedomService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 消息接收者,收到消息后进行处理,内部反射调用,默认回调方法handleMessage,方法参数由消息 + * 发送方和接收方约定,方法参数尽可能作为一个对象,多个参数向上封装成一个对象 + * + * @see MessageListenerAdapter + * @see org.springframework.amqp.core.MessageListener + */ +@Component +@Slf4j +public class BusReceiver { + + @Autowired + private PopedomService popedomService; + + public void handleMessage(List popedoms) { + log.info("Received Message:<{}>", popedoms); + popedomService.savePopedom(popedoms); + } +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/provider/PopedomProvider.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/provider/PopedomProvider.java new file mode 100644 index 0000000..62cd975 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/provider/PopedomProvider.java @@ -0,0 +1,24 @@ +package com.springboot.cloud.auth.authentication.provider; + +import com.springboot.cloud.auth.authentication.entity.License; +import com.springboot.cloud.auth.authentication.entity.Popedom; +import com.springboot.cloud.common.core.entity.vo.Result; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@FeignClient(name = "organization", fallback = PopedomProviderFallback.class, path = "organization") +//@FeignClient(name = "organization", fallback = PopedomProviderFallback.class) +public interface PopedomProvider { + + @GetMapping(value = "/company/getAllPopedom") + Result> popedoms(); + + @GetMapping(value = "/company/getPopedom") + Result> popedoms(@RequestParam("companyId") String companyId,@RequestParam("username")String username); + + @GetMapping(value = "/company/license") + Result license(@RequestParam("companyId")String companyId,@RequestParam("applicationCode")String applicationCode); +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/provider/PopedomProviderFallback.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/provider/PopedomProviderFallback.java new file mode 100644 index 0000000..c38a6e0 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/provider/PopedomProviderFallback.java @@ -0,0 +1,36 @@ +package com.springboot.cloud.auth.authentication.provider; + +import com.springboot.cloud.auth.authentication.entity.License; +import com.springboot.cloud.auth.authentication.entity.Popedom; +import com.springboot.cloud.common.core.entity.vo.Result; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Component +@Slf4j +public class PopedomProviderFallback implements PopedomProvider { + + @Override + public Result> popedoms() { + log.error("认证服务启动时加载资源异常!未加载到资源!"); + return Result.fail(); + } + + @Override + public Result> popedoms(String companyId, String username) { + log.error("认证服务查询用户异常!查询用户资源为空!"); + return Result.success(new ArrayList()); + } + + @Override + public Result license(String companyId, String applicationCode) { + log.error("认证服务查询企业应用有效期异常!企业应用过期!"); + return Result.success(new License()); + } + +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/rest/AuthenticationController.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/rest/AuthenticationController.java new file mode 100644 index 0000000..ee672e3 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/rest/AuthenticationController.java @@ -0,0 +1,34 @@ +package com.springboot.cloud.auth.authentication.rest; + +import com.springboot.cloud.auth.authentication.service.AuthenticationService; +import com.springboot.cloud.common.core.entity.vo.Result; +import io.swagger.annotations.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +@RestController +@Api("auth") +@Slf4j +public class AuthenticationController { + + @Autowired + AuthenticationService authenticationService; + + @ApiOperation(value = "权限验证", notes = "根据用户token,访问的url和method判断用户是否有权限访问") + @ApiImplicitParams({ + @ApiImplicitParam(paramType = "query", name = "url", value = "访问的url", required = true, dataType = "string"), + @ApiImplicitParam(paramType = "query", name = "method", value = "访问的method", required = true, dataType = "string") + }) + @ApiResponses(@ApiResponse(code = 200, message = "处理成功", response = Result.class)) + @PostMapping(value = "/auth/permission") + public Result decide(@RequestParam String url, HttpServletRequest request) { + boolean decide = authenticationService.decide(new HttpServletRequestAuthWrapper(request, url)); + return Result.success(decide); + } + +} \ No newline at end of file diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/rest/HttpServletRequestAuthWrapper.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/rest/HttpServletRequestAuthWrapper.java new file mode 100644 index 0000000..797b6f3 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/rest/HttpServletRequestAuthWrapper.java @@ -0,0 +1,22 @@ +package com.springboot.cloud.auth.authentication.rest; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +public class HttpServletRequestAuthWrapper extends HttpServletRequestWrapper { + + private String url; + + /** + * @param url + */ + public HttpServletRequestAuthWrapper(HttpServletRequest request, String url) { + super(request); + this.url = url; + } + + @Override + public String getServletPath() { + return this.url; + } +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/AuthenticationService.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/AuthenticationService.java new file mode 100644 index 0000000..1cc0ee3 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/AuthenticationService.java @@ -0,0 +1,17 @@ +package com.springboot.cloud.auth.authentication.service; + +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +@Service +public interface AuthenticationService { + /** + * 校验权限 + * + * @param authRequest + * @return 是否有权限 + */ + boolean decide(HttpServletRequest authRequest); + +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/NewMvcRequestMatcher.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/NewMvcRequestMatcher.java new file mode 100644 index 0000000..98d607a --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/NewMvcRequestMatcher.java @@ -0,0 +1,31 @@ +package com.springboot.cloud.auth.authentication.service; + +import com.google.common.base.Objects; +import lombok.Getter; +import org.springframework.http.HttpMethod; +import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; + +@Getter +public class NewMvcRequestMatcher extends MvcRequestMatcher { + + private String pattern; + + public NewMvcRequestMatcher(HandlerMappingIntrospector introspector, String pattern) { + super(introspector, pattern); + this.pattern = pattern; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NewMvcRequestMatcher that = (NewMvcRequestMatcher) o; + return Objects.equal(pattern, that.pattern); + } + + @Override + public int hashCode() { + return Objects.hashCode(pattern); + } +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/PopedomService.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/PopedomService.java new file mode 100644 index 0000000..77aa046 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/PopedomService.java @@ -0,0 +1,52 @@ +package com.springboot.cloud.auth.authentication.service; + +import com.springboot.cloud.auth.authentication.entity.Popedom; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +@Service +public interface PopedomService { + + /** + * 动态新增更新权限 + * + * @param popedoms + */ + void savePopedom(List popedoms); + + /** + * 动态删除权限 + * + * @param popedom + */ + void removePopedom(Popedom popedom); + + /** + * 加载权限资源数据 + */ + void loadPopedom(); + + /** + * 根据url和method查询到对应的权限信息 + * + * @param authRequest + * @return + */ + List findConfigAttributesByUrl(HttpServletRequest authRequest); + + /** + * 根据用户名查询 该用户所拥有的角色对应的资源信息 + * @param companyId + * @param username + * @return + */ + List queryByUsername(String companyId,String username); + + /** + * 资源对应的应用是否过期 + */ + boolean license(String companyId, String applicationCode); +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/impl/AuthenticationServiceImpl.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/impl/AuthenticationServiceImpl.java new file mode 100644 index 0000000..e46fe15 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/impl/AuthenticationServiceImpl.java @@ -0,0 +1,84 @@ +package com.springboot.cloud.auth.authentication.service.impl; + +import com.springboot.cloud.auth.authentication.entity.Popedom; +import com.springboot.cloud.auth.authentication.service.AuthenticationService; +import com.springboot.cloud.auth.authentication.service.PopedomService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.access.SecurityConfig; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Optional; + +@Service +@Slf4j +public class AuthenticationServiceImpl implements AuthenticationService { + + @Autowired + private PopedomService popedomService; + + /** + * @param authRequest 访问的url,method + * @return 有权限true, 无权限或全局资源中未找到请求url返回否 + */ + @Override + public boolean decide(HttpServletRequest authRequest) { + log.debug("正在访问的url是:{}", authRequest.getServletPath()); + //获取用户认证信息 + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + //获取此url访问对应的权限资源信息 + List configAttributes = popedomService.findConfigAttributesByUrl(authRequest); + if (configAttributes.size() == 0) { + //如果未匹配到资源,则返回未授权 + return false; + } else if (configAttributes.size() == 1) { + //默认授权所有资源,所有资源都会匹配,如果仅匹配到一个资源,则必定不是功能接口 + return true; + } else { + String companyId = Optional.ofNullable(authRequest.getParameter("companyId")).orElseGet(String::new); +// String companyId = Optional.ofNullable(UserContextHolder.getInstance().getCurrentCompany()).orElseGet(String::new); + //获取此访问用户所有角色拥有的权限资源 + List userPopedoms = findPopedomByUsername(companyId, authentication.getName()); + //用户拥有权限资源 与 url要求的资源进行对比 + return isMatch(companyId,configAttributes, userPopedoms); + } + + } + + /** + * url对应资源与用户拥有资源进行匹配 + * 前端传入所在公司 + * @param userPopedoms + * @return + */ + public boolean isMatch(String companyId,List urlConfigAttributes, List userPopedoms) { + //首先检查用户所属角色是否有资源权限 + Optional optionalPopedom = userPopedoms.stream().filter(popedom -> urlConfigAttributes.contains(new SecurityConfig(popedom.getId()))).findAny(); + if(optionalPopedom.isPresent()){ + //再检查用户所在公司应用是否过期 + return popedomService.license(companyId, optionalPopedom.orElseGet(Popedom::new).getApplicationCode()); + }else{ + return false; + } + } + + /** + * 根据用户所被授予的角色,查询到用户所拥有的资源 + * + * @param username + * @return + */ + private List findPopedomByUsername(String companyId, String username) { + //用户被授予的角色资源 + List popedoms = popedomService.queryByUsername(companyId, username); + if (log.isDebugEnabled()) { + log.debug("用户被授予角色的资源数量是:{}, 资源集合信息为:{}", popedoms.size(), popedoms); + } + return popedoms; + } +} diff --git a/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/impl/PopedomServiceImpl.java b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/impl/PopedomServiceImpl.java new file mode 100644 index 0000000..416c3f5 --- /dev/null +++ b/auth/authentication-server/src/main/java/com/springboot/cloud/auth/authentication/service/impl/PopedomServiceImpl.java @@ -0,0 +1,127 @@ +package com.springboot.cloud.auth.authentication.service.impl; + +import com.springboot.cloud.auth.authentication.entity.License; +import com.springboot.cloud.auth.authentication.entity.Popedom; +import com.springboot.cloud.auth.authentication.provider.PopedomProvider; +import com.springboot.cloud.auth.authentication.service.NewMvcRequestMatcher; +import com.springboot.cloud.auth.authentication.service.PopedomService; +import com.springboot.cloud.common.core.entity.vo.Result; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.access.SecurityConfig; +import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.stereotype.Service; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class PopedomServiceImpl implements PopedomService { + + @Autowired + private HandlerMappingIntrospector mvcHandlerMappingIntrospector; + + @Autowired + private PopedomProvider popedomProvider; + + /** + * 系统中权限分组集合 + * key:companyId,value:{key:url,value:config} + */ + private static final Map> popedomConfigAttributes = new HashMap<>(); + + @Override + public synchronized void savePopedom(List popedoms) { + popedoms.stream().forEach(popedom -> { + if (popedomConfigAttributes.containsKey(popedom.getCompanyId())) { + //如果包含company对应的权限表,则更新 + Map attributeMap = popedomConfigAttributes.get(popedom.getCompanyId()); + attributeMap.put(this.newMvcRequestMatcher(popedom.getUrl()), new SecurityConfig(popedom.getId())); + } else { + //如果不包含company对应的权限表,则新增 + Map map = new HashMap<>(); + map.put(this.newMvcRequestMatcher(popedom.getUrl()), new SecurityConfig(popedom.getId())); + popedomConfigAttributes.put(popedom.getCompanyId(), map); + } + }); + log.info("popedomConfigAttributes size:{}", popedomConfigAttributes.size()); + } + + @Override + public synchronized void removePopedom(Popedom popedom) { + if (popedomConfigAttributes.containsKey(popedom.getCompanyId())) { + Map attributeMap = popedomConfigAttributes.get(popedom.getCompanyId()); + attributeMap.remove(this.newMvcRequestMatcher(popedom.getUrl())); + } + log.info("resourceConfigAttributes size:{}", popedomConfigAttributes.size()); + } + + @Override + public synchronized void loadPopedom() { + Result> resourcesResult = popedomProvider.popedoms(); + if (resourcesResult.isFail()) { + System.exit(1); + } + List popedoms = resourcesResult.getData(); + //先根据公司分组,然后放入内存 + Map> map = popedoms.stream().filter(a -> null != a.getUrl() && !a.getUrl().equals("")).collect(Collectors.groupingBy(Popedom::getCompanyId, Collectors.toMap(a -> newMvcRequestMatcher(a.getUrl()), a -> new SecurityConfig(a.getId())))); + popedomConfigAttributes.putAll(map); + log.debug("init resourceConfigAttributes:{}", popedomConfigAttributes); + } + + @Override + public List findConfigAttributesByUrl(HttpServletRequest authRequest) { + String companyId = Optional.ofNullable(authRequest.getParameter("companyId")).orElseGet(String::new); +// String companyId = Optional.ofNullable(UserContextHolder.getInstance().getCurrentCompany()).orElseGet(String::new); + if (popedomConfigAttributes.containsKey(companyId)) { + Map attributeMap = popedomConfigAttributes.get(companyId); + return attributeMap.keySet().stream() + .filter(requestMatcher -> requestMatcher.matches(authRequest)) + .map(requestMatcher -> attributeMap.get(requestMatcher)) + .peek(urlConfigAttribute -> log.debug("url在资源池中配置:{}", urlConfigAttribute.getAttribute())) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + @Override + public List queryByUsername(String companyId, String username) { + return popedomProvider.popedoms(companyId, username).getData(); + } + + @Override + public boolean license(String companyId, String applicationCode) { + Result licenseResult = popedomProvider.license(companyId, applicationCode); + if (licenseResult.isFail()) { + return false; + } + License data = licenseResult.getData(); + if (null == data) { + return false; + } + if (data.isForever()) { + return true; + } + if (data.getExpireDate().getTime() > new Date().getTime()) { + return true; + } else { + return false; + } + } + + /** + * 创建RequestMatcher + * + * @param url + * @return + */ + private MvcRequestMatcher newMvcRequestMatcher(String url) { + return new NewMvcRequestMatcher(mvcHandlerMappingIntrospector, url); + } +} \ No newline at end of file diff --git a/auth/authentication-server/src/test/java/com/springboot/cloud/auth/authentication/ApplicationTests.java b/auth/authentication-server/src/test/java/com/springboot/cloud/auth/authentication/ApplicationTests.java new file mode 100644 index 0000000..bc7aeef --- /dev/null +++ b/auth/authentication-server/src/test/java/com/springboot/cloud/auth/authentication/ApplicationTests.java @@ -0,0 +1,54 @@ +package com.springboot.cloud.auth.authentication; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; + +import java.util.List; +import java.util.stream.Collectors; + + +public class ApplicationTests { + + @Test + public void testMethod() { + List authorities; + SimpleGrantedAuthority admin = new SimpleGrantedAuthority("ADMIN"); + SimpleGrantedAuthority user = new SimpleGrantedAuthority("USER"); + authorities = Lists.newArrayList(admin, user); + authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList()); + } + + @Test + public void testMethod1() throws JsonProcessingException { + +// Resource resource = new Resource(); +// resource.setCode("user_manager:all"); +// resource.setMethod("GET"); +// resource.setUrl("/users/a"); +// +// ObjectMapper objectMapper = new ObjectMapper(); +// objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); +// +// System.out.println(objectMapper.writeValueAsString(resource)); + } + + @Test + public void testMatcher() { + MvcRequestMatcher mvcRequestMatcher = new MvcRequestMatcher(new HandlerMappingIntrospector(), "/users/{id}"); + System.out.println(mvcRequestMatcher.matches(new MockHttpServletRequest("GET", "/users/1"))); + System.out.println(mvcRequestMatcher.matches(new MockHttpServletRequest("GET", "/users/aaa"))); + System.out.println(mvcRequestMatcher.matches(new MockHttpServletRequest("GET", "/users"))); + System.out.println(mvcRequestMatcher.matches(new MockHttpServletRequest("POST", "/users/1"))); + System.out.println(mvcRequestMatcher.matches(new MockHttpServletRequest("PUT", "/users/1"))); + System.out.println(mvcRequestMatcher.matches(new MockHttpServletRequest("DELETE", "/users/1"))); + } + +} diff --git a/auth/authentication-server/src/test/java/com/springboot/cloud/auth/authentication/service/impl/AuthenticationServiceImplTest.java b/auth/authentication-server/src/test/java/com/springboot/cloud/auth/authentication/service/impl/AuthenticationServiceImplTest.java new file mode 100644 index 0000000..8300238 --- /dev/null +++ b/auth/authentication-server/src/test/java/com/springboot/cloud/auth/authentication/service/impl/AuthenticationServiceImplTest.java @@ -0,0 +1,31 @@ +package com.springboot.cloud.auth.authentication.service.impl; + +import com.google.common.collect.Sets; +import com.springboot.cloud.auth.authentication.entity.Popedom; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.security.access.SecurityConfig; + +import java.util.Set; + +public class AuthenticationServiceImplTest { + + @Test + public void testIsMatch_假如存在如上资源信息_当给定包含在资源信息时_那么返回true() { + AuthenticationServiceImpl authenticationServiceImpl = new AuthenticationServiceImpl(); + Popedom popedom = new Popedom(); + popedom.setApplicationCode("user_manager:view"); + Set popedoms = Sets.newHashSet(popedom); +// Assert.assertTrue(authenticationServiceImpl.isMatch(new SecurityConfig("user_manager:view"), popedoms)); + } + + @Test + public void testIsMatch_假如存在如上资源信息_当给不包含在资源信息时_那么返回false() { + AuthenticationServiceImpl authenticationServiceImpl = new AuthenticationServiceImpl(); + Popedom popedom = new Popedom(); + popedom.setApplicationCode("user_manager:manager"); + Set popedoms = Sets.newHashSet(popedom); +// Assert.assertFalse(authenticationServiceImpl.isMatch(new SecurityConfig("user_manager:view"), popedoms)); + } + +} \ No newline at end of file diff --git a/auth/authentication-server/src/test/java/com/springboot/cloud/auth/authentication/service/impl/PopedomServiceImplTest.java b/auth/authentication-server/src/test/java/com/springboot/cloud/auth/authentication/service/impl/PopedomServiceImplTest.java new file mode 100644 index 0000000..6ace8b7 --- /dev/null +++ b/auth/authentication-server/src/test/java/com/springboot/cloud/auth/authentication/service/impl/PopedomServiceImplTest.java @@ -0,0 +1,73 @@ +package com.springboot.cloud.auth.authentication.service.impl; + +import com.springboot.cloud.auth.authentication.provider.PopedomProvider; +import com.springboot.cloud.auth.authentication.rest.HttpServletRequestAuthWrapper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.security.access.ConfigAttribute; + +//@RunWith(SpringRunner.class) +//@SpringBootTest +public class PopedomServiceImplTest { + +/* private Map resourceConfigAttributes = new HashMap() { + { + MvcRequestMatcher mvcRequestMatcher1 = new MvcRequestMatcher(new HandlerMappingIntrospector(), "/users"); + mvcRequestMatcher1.setMethod(HttpMethod.resolve("POST")); + MvcRequestMatcher mvcRequestMatcher2 = new MvcRequestMatcher(new HandlerMappingIntrospector(), "/users/{id}"); + mvcRequestMatcher2.setMethod(HttpMethod.resolve("PUT")); + MvcRequestMatcher mvcRequestMatcher3 = new MvcRequestMatcher(new HandlerMappingIntrospector(), "/users/{id}"); + mvcRequestMatcher3.setMethod(HttpMethod.resolve("DELETE")); + MvcRequestMatcher mvcRequestMatcher4 = new MvcRequestMatcher(new HandlerMappingIntrospector(), "/users/{id}"); + mvcRequestMatcher4.setMethod(HttpMethod.resolve("GET")); + MvcRequestMatcher mvcRequestMatcher5 = new MvcRequestMatcher(new HandlerMappingIntrospector(), "/users/{id}/order"); + mvcRequestMatcher5.setMethod(HttpMethod.resolve("GET")); + put(mvcRequestMatcher1, new SecurityConfig("user_manager:btn_add")); + put(mvcRequestMatcher2, new SecurityConfig("user_manager:btn_edit")); + put(mvcRequestMatcher3, new SecurityConfig("user_manager:btn_del")); + put(mvcRequestMatcher4, new SecurityConfig("user_manager:view")); + put(mvcRequestMatcher5, new SecurityConfig("user_order:view")); + } + };*/ + + @InjectMocks + private PopedomServiceImpl popedomServiceImpl; + + @Mock + private PopedomProvider popedomProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + @Ignore + public void testGetConfigAttributesByUrl_假如存在如上资源信息_当请求不存在method的资源时_那么返回NONEXISTENT_URL() { +// ConfigAttribute attributesByUrl = popedomServiceImpl +// .findConfigAttributesByUrl("", new HttpServletRequestAuthWrapper(new MockHttpServletRequest(), "/users/1/order")); +// Assert.assertEquals("NONEXISTENT_URL", attributesByUrl.getAttribute()); + } + + @Test + @Ignore + public void testGetConfigAttributesByUrl_假如存在如上资源信息_当请求url存在参数时_那么返回匹配的资源信息() { +// ConfigAttribute attributesByUrl = popedomServiceImpl +// .findConfigAttributesByUrl("", new HttpServletRequestAuthWrapper(new MockHttpServletRequest(), "/users/1/order")); +// Assert.assertEquals("NONEXISTENT_URL", attributesByUrl.getAttribute()); + } + + @Test + @Ignore + public void testGetConfigAttributesByUrl_假如存在如上资源信息_当请求存在的资源时_那么返回url和method都匹配的资源信息() { +// ConfigAttribute attributesByUrl = popedomServiceImpl +// .findConfigAttributesByUrl("", new HttpServletRequestAuthWrapper(new MockHttpServletRequest(), "/users")); +// Assert.assertEquals("user_manager:btn_add", attributesByUrl.getAttribute()); + } +} \ No newline at end of file diff --git a/auth/authorization-server/.gitignore b/auth/authorization-server/.gitignore new file mode 100644 index 0000000..3a05198 --- /dev/null +++ b/auth/authorization-server/.gitignore @@ -0,0 +1,16 @@ +target/ +logs/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr diff --git a/auth/authorization-server/pom.xml b/auth/authorization-server/pom.xml new file mode 100644 index 0000000..5631978 --- /dev/null +++ b/auth/authorization-server/pom.xml @@ -0,0 +1,114 @@ + + + 4.0.0 + + business.chaoran + authorization-server + 0.0.1-SNAPSHOT + war + + + authorization-server + Demo Oauth2 project for Spring Cloud Oauth2 Authorization Server + + + business.chaoran + auth + 0.0.1-SNAPSHOT + + + + + business.chaoran + web + 0.0.1-SNAPSHOT + + + + org.springframework.cloud + spring-cloud-security + + + com.fasterxml.jackson.core + jackson-databind + 2.10.0.pr1 + compile + + + + + com.fasterxml.jackson.core + jackson-core + 2.9.0 + + + com.fasterxml.jackson.core + jackson-databind + 2.9.0 + + + com.fasterxml.jackson.core + jackson-annotations + 2.9.0 + + + + + + + + + + + + + org.slf4j + slf4j-simple + compile + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + org.springframework.boot + spring-boot-starter-logging + + + + + javax.servlet + javax.servlet-api + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.1.4.RELEASE + + + + build-info + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.0.0 + + + authorization-server + + + diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/Oauth2AuthorizationApplication.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/Oauth2AuthorizationApplication.java new file mode 100644 index 0000000..57f6372 --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/Oauth2AuthorizationApplication.java @@ -0,0 +1,23 @@ +package com.springboot.auth.authorization; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; + +@SpringBootApplication +@EnableDiscoveryClient +@EnableFeignClients +public class Oauth2AuthorizationApplication extends SpringBootServletInitializer { + public static void main(String[] args) { + SpringApplication.run(Oauth2AuthorizationApplication.class, args); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { + return builder.sources(Oauth2AuthorizationApplication.class); + } + +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/AuthorizationServerConfig.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/AuthorizationServerConfig.java new file mode 100644 index 0000000..2037091 --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/AuthorizationServerConfig.java @@ -0,0 +1,179 @@ +package com.springboot.auth.authorization.config; + +import com.google.common.collect.Lists; +import com.springboot.auth.authorization.exception.CustomWebResponseExceptionTranslator; +import com.springboot.auth.authorization.oauth2.enhancer.CustomTokenEnhancer; +import com.springboot.auth.authorization.oauth2.granter.MobileTokenGranter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; +import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; +import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; +import org.springframework.security.oauth2.provider.CompositeTokenGranter; +import org.springframework.security.oauth2.provider.TokenGranter; +import org.springframework.security.oauth2.provider.approval.Approval; +import org.springframework.security.oauth2.provider.approval.ApprovalStore; +import org.springframework.security.oauth2.provider.approval.InMemoryApprovalStore; +import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; +import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices; +import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator; +import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; + +import java.util.Arrays; +import java.util.List; + +@Configuration +@EnableAuthorizationServer +public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { + + @Autowired + @Qualifier("authenticationManagerBean") + private AuthenticationManager authenticationManager; + +// @Qualifier("dataSource") +// @Autowired +// DataSource dataSource; + + @Autowired + @Qualifier("userDetailsService") + UserDetailsService userDetailsService; + + /** + * jwt 对称加密密钥 + */ + @Value("${spring.security.oauth2.jwt.signingKey}") + private String signingKey; + + @Override + public void configure(AuthorizationServerSecurityConfigurer oauthServer) { + // 支持将client参数放在header或body中 + oauthServer.allowFormAuthenticationForClients(); + + //认证策略,默认为denyAll() + oauthServer.tokenKeyAccess("isAuthenticated()") + .checkTokenAccess("permitAll()"); + } + + @Override + public void configure(ClientDetailsServiceConfigurer clients) throws Exception { + // 配置客户端信息,从数据库中读取,对应oauth_client_details表 +// clients.jdbc(dataSource); + clients.inMemory().withClient("test_client").secret("$2a$10$2szDKjvKHJCWE6YQNznogOeQF3USZHmCYj1fG7YbfK.vnTgNKLzri").scopes("read") + .authorizedGrantTypes("client_credentials", "authorization_code", "mobile", "password", "refresh_token") + .redirectUris("http://www.baidu.com").accessTokenValiditySeconds(3600).refreshTokenValiditySeconds(3600); + } + + @Override + public void configure(AuthorizationServerEndpointsConfigurer endpoints) { + // 配置token的数据源、自定义的tokenServices等信息,配置身份认证器,配置认证方式,TokenStore,TokenGranter,OAuth2RequestFactory + endpoints.tokenStore(tokenStore()) + .authorizationCodeServices(authorizationCodeServices()) + .approvalStore(approvalStore()) + .exceptionTranslator(customExceptionTranslator()) + .tokenEnhancer(tokenEnhancerChain()) + .authenticationManager(authenticationManager) + .userDetailsService(userDetailsService) + //update by joe_chen add granter + .tokenGranter(tokenGranter(endpoints)); + + } + + /** + * 自定义OAuth2异常处理 + * + * @return CustomWebResponseExceptionTranslator + */ + @Bean + public WebResponseExceptionTranslator customExceptionTranslator() { + return new CustomWebResponseExceptionTranslator(); + } + + /** + * 授权信息持久化实现 + * 密码模式无用 + * @return JdbcApprovalStore + */ + @Bean + public ApprovalStore approvalStore() { + InMemoryApprovalStore memoryApprovalStore = new InMemoryApprovalStore(); + Approval approval = new Approval("1", "test_client", "read", 3600, Approval.ApprovalStatus.APPROVED); + memoryApprovalStore.addApprovals(Arrays.asList(approval)); +// return new JdbcApprovalStore(dataSource); + return memoryApprovalStore; + } + + /** + * 授权码模式持久化授权码code + * 密码模式无用 + * @return JdbcAuthorizationCodeServices + */ + @Bean + protected AuthorizationCodeServices authorizationCodeServices() { + // 授权码存储等处理方式类,使用jdbc,操作oauth_code表 + InMemoryAuthorizationCodeServices authorizationCodeServices = new InMemoryAuthorizationCodeServices(); +// return new JdbcAuthorizationCodeServices(dataSource); + return authorizationCodeServices; + } + + /** + * token的持久化 + * + * @return JwtTokenStore + */ + @Bean + public TokenStore tokenStore() { + return new JwtTokenStore(accessTokenConverter()); + } + + /** + * 自定义token + * + * @return tokenEnhancerChain + */ + @Bean + public TokenEnhancerChain tokenEnhancerChain() { + TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); + tokenEnhancerChain.setTokenEnhancers(Arrays.asList(new CustomTokenEnhancer(), accessTokenConverter())); + return tokenEnhancerChain; + } + + /** + * jwt token的生成配置 + * + * @return + */ + @Bean + public JwtAccessTokenConverter accessTokenConverter() { + JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); + converter.setSigningKey(signingKey); + return converter; + } + + /** + * 配置自定义的granter,手机号验证码登陆 + * + * @param endpoints + * @return + */ + public TokenGranter tokenGranter(final AuthorizationServerEndpointsConfigurer endpoints) { + List granters = Lists.newArrayList(endpoints.getTokenGranter()); + granters.add(new MobileTokenGranter( + authenticationManager, + endpoints.getTokenServices(), + endpoints.getClientDetailsService(), + endpoints.getOAuth2RequestFactory())); + return new CompositeTokenGranter(granters); + } + +} \ No newline at end of file diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/InterceptConfig.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/InterceptConfig.java new file mode 100644 index 0000000..52c8bca --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/InterceptConfig.java @@ -0,0 +1,21 @@ +package com.springboot.auth.authorization.config; + +/* + ********************************************** + * DATE PERSON REASON + * 2020/12/7 FXY Created + ********************************************** + */ + +import com.springboot.cloud.common.web.interceptor.FeignBasicAuthRequestInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class InterceptConfig { + + @Bean + public FeignBasicAuthRequestInterceptor interceptor(){ + return new FeignBasicAuthRequestInterceptor(); + } +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/NacosRegisterConfig.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/NacosRegisterConfig.java new file mode 100644 index 0000000..61af4af --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/NacosRegisterConfig.java @@ -0,0 +1,56 @@ +package com.springboot.auth.authorization.config; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-24 FXY Created + ********************************************** + */ + +import com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.annotation.Configuration; + +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.Query; +import java.lang.management.ManagementFactory; +import java.util.Set; + +@Configuration +@Slf4j +public class NacosRegisterConfig implements ApplicationRunner { + + @Autowired(required = false) + private NacosAutoServiceRegistration registration; + + private Integer port; + + public NacosRegisterConfig() { + try { + this.port = Integer.parseInt(getTomcatPort()); + } catch (Exception e) { + log.error("获取tomcat端口出错了,原因:{}", e.toString()); + } + } + + @Override + public void run(ApplicationArguments args) { + if (registration != null && port != null) { + registration.setPort(port); + registration.start(); + } + } + + //获取tomcat端口 + private String getTomcatPort() throws Exception { + MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer(); + Set objectNames = beanServer.queryNames(new ObjectName("*:type=Connector,*"), Query.match(Query.attr("protocol"), Query.value("HTTP/1.1"))); + String port = objectNames.iterator().next().getKeyProperty("port"); + return port; + } + +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/WebServerSecurityConfig.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/WebServerSecurityConfig.java new file mode 100644 index 0000000..8b0749b --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/config/WebServerSecurityConfig.java @@ -0,0 +1,83 @@ +package com.springboot.auth.authorization.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +import com.springboot.auth.authorization.oauth2.granter.MobileAuthenticationProvider; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Configuration +@EnableWebSecurity +public class WebServerSecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + @Qualifier("userDetailsService") + private UserDetailsService userDetailsService; + + @Autowired + @Qualifier("mobileUserDetailsService") + private UserDetailsService mobileUserDetailsService; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable(); + http.authorizeRequests() + .antMatchers("/actuator/**").permitAll() + .anyRequest().authenticated() + .and() + .formLogin().permitAll(); + } + + /** + * 注入自定义的userDetailsService实现,获取用户信息,设置密码加密方式 + * + * @param authenticationManagerBuilder + * @throws Exception + */ + @Override + protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { + authenticationManagerBuilder + .userDetailsService(userDetailsService) + .passwordEncoder(passwordEncoder()); + // 设置手机验证码登陆的AuthenticationProvider + authenticationManagerBuilder.authenticationProvider(mobileAuthenticationProvider()); + } + + /** + * 将 AuthenticationManager 注册为 bean , 方便配置 oauth server 的时候使用 + */ + @Bean + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + /** + * 创建手机验证码登陆的AuthenticationProvider + * + * @return mobileAuthenticationProvider + */ + @Bean + public MobileAuthenticationProvider mobileAuthenticationProvider() { + MobileAuthenticationProvider mobileAuthenticationProvider = new MobileAuthenticationProvider(this.mobileUserDetailsService); + mobileAuthenticationProvider.setPasswordEncoder(passwordEncoder()); + return mobileAuthenticationProvider; + } +} \ No newline at end of file diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/entity/Company.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/entity/Company.java new file mode 100644 index 0000000..588a48c --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/entity/Company.java @@ -0,0 +1,24 @@ +package com.springboot.auth.authorization.entity; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class Company { + private String companyId; + private String userId; + private String organizationId; + private String empNo; + private String position; + private Integer isDefault; + private Integer state; + private String mobile; +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/entity/User.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/entity/User.java new file mode 100644 index 0000000..b46dc3c --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/entity/User.java @@ -0,0 +1,31 @@ +package com.springboot.auth.authorization.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class User { + private String id; + private String name; + private Date registryTime; + private String identity; + private String nickName; + private String photo; + private String lastModifier; + private Date lastModifyTime; + private Double state; + private String mobile; + private String email; + private String introduce; + private String avatar; + private String signature; + private String password; + private String username; +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/AuthErrorType.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/AuthErrorType.java new file mode 100644 index 0000000..39a6f9b --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/AuthErrorType.java @@ -0,0 +1,38 @@ +package com.springboot.auth.authorization.exception; + +import com.springboot.cloud.common.core.exception.ErrorType; +import lombok.Getter; + +@Getter +public enum AuthErrorType implements ErrorType { + + INVALID_REQUEST("040001", "无效请求"), + INVALID_CLIENT("040002", "无效client_id"), + INVALID_GRANT("040003", "无效授权"), + INVALID_SCOPE("040004", "无效scope"), + INVALID_TOKEN("040005", "无效token"), + INSUFFICIENT_SCOPE("040010", "授权不足"), + REDIRECT_URI_MISMATCH("040020", "redirect url不匹配"), + ACCESS_DENIED("040030", "拒绝访问"), + METHOD_NOT_ALLOWED("040040", "不支持该方法"), + SERVER_ERROR("040050", "权限服务错误"), + UNAUTHORIZED_CLIENT("040060", "未授权客户端"), + UNAUTHORIZED("040061", "未授权"), + UNSUPPORTED_RESPONSE_TYPE("040070", " 支持的响应类型"), + UNSUPPORTED_GRANT_TYPE("040071", "不支持的授权类型"); + + /** + * 错误类型码 + */ + private String code; + /** + * 错误类型描述信息 + */ + private String mesg; + + AuthErrorType(String code, String mesg) { + this.code = code; + this.mesg = mesg; + } + +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/CustomOauthException.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/CustomOauthException.java new file mode 100644 index 0000000..d327ee6 --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/CustomOauthException.java @@ -0,0 +1,20 @@ +package com.springboot.auth.authorization.exception; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.springboot.cloud.common.core.entity.vo.Result; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; + +@EqualsAndHashCode(callSuper = true) +@Data +@JsonSerialize(using = CustomOauthExceptionSerializer.class) +class CustomOauthException extends OAuth2Exception { + + private final Result result; + + CustomOauthException(OAuth2Exception oAuth2Exception) { + super(oAuth2Exception.getSummary(), oAuth2Exception); + this.result = Result.fail(AuthErrorType.valueOf(oAuth2Exception.getOAuth2ErrorCode().toUpperCase()), oAuth2Exception); + } +} \ No newline at end of file diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/CustomOauthExceptionSerializer.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/CustomOauthExceptionSerializer.java new file mode 100644 index 0000000..3504a3b --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/CustomOauthExceptionSerializer.java @@ -0,0 +1,18 @@ +package com.springboot.auth.authorization.exception; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +import java.io.IOException; + +public class CustomOauthExceptionSerializer extends StdSerializer { + public CustomOauthExceptionSerializer() { + super(CustomOauthException.class); + } + + @Override + public void serialize(CustomOauthException value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeObject(value.getResult()); + } +} \ No newline at end of file diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/CustomWebResponseExceptionTranslator.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/CustomWebResponseExceptionTranslator.java new file mode 100644 index 0000000..1773603 --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/CustomWebResponseExceptionTranslator.java @@ -0,0 +1,16 @@ +package com.springboot.auth.authorization.exception; + +import org.springframework.http.ResponseEntity; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; +import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator; + +public class CustomWebResponseExceptionTranslator implements WebResponseExceptionTranslator { + + @Override + public ResponseEntity translate(Exception e) { + + OAuth2Exception oAuth2Exception = (OAuth2Exception) e; + return ResponseEntity.status(oAuth2Exception.getHttpErrorCode()) + .body(new CustomOauthException(oAuth2Exception)); + } +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/GlobalExceptionHandlerAdvice.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/GlobalExceptionHandlerAdvice.java new file mode 100644 index 0000000..200a09c --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/exception/GlobalExceptionHandlerAdvice.java @@ -0,0 +1,11 @@ +package com.springboot.auth.authorization.exception; + +import com.springboot.cloud.common.web.exception.DefaultGlobalExceptionHandlerAdvice; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandlerAdvice extends DefaultGlobalExceptionHandlerAdvice { + +} \ No newline at end of file diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/CustomUserDetailsService.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/CustomUserDetailsService.java new file mode 100644 index 0000000..1bb0744 --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/CustomUserDetailsService.java @@ -0,0 +1,49 @@ +package com.springboot.auth.authorization.oauth2; + +import com.springboot.auth.authorization.entity.Company; +import com.springboot.auth.authorization.entity.User; +import com.springboot.auth.authorization.oauth2.authority.CustomGrantedAuthority; +import com.springboot.auth.authorization.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Service("userDetailsService") +public class CustomUserDetailsService implements UserDetailsService { + + @Autowired + private UserService userService; + + @Override + public UserDetails loadUserByUsername(String payload) { + + User user = userService.getUserByUsernameOrMobile(payload); + log.info("load user by username :{}", user.toString()); + + return new org.springframework.security.core.userdetails.User( + user.getUsername(), + user.getPassword(), //加了密的密码 + user.getState() == 1, //账号是否可用 + user.getState() == 1, //账号未过期 + true, //密码未过期 + user.getState() == 1, //账户未锁定 + this.obtainGrantedCompany(user)); + } + + /** + * 获得登录者所有的公司信息 + * + * @return + */ + protected Set obtainGrantedCompany(User user) { + List companies = userService.getUserAllCompany(user.getId()); + return companies.stream().map(companyUser -> new CustomGrantedAuthority(companyUser.getCompanyId(), companyUser.getIsDefault() == 1)).collect(Collectors.toSet()); + } +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/MobileUserDetailsService.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/MobileUserDetailsService.java new file mode 100644 index 0000000..f21a38d --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/MobileUserDetailsService.java @@ -0,0 +1,42 @@ +package com.springboot.auth.authorization.oauth2; + +import com.springboot.auth.authorization.entity.User; +import com.springboot.auth.authorization.provider.SmsCodeProvider; +import com.springboot.auth.authorization.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; + +import java.util.Collections; + +/** + * 手机验证码登陆, 用户相关获取 + */ +@Slf4j +@Service("mobileUserDetailsService") +public class MobileUserDetailsService extends CustomUserDetailsService { + + @Autowired + private UserService userService; + @Autowired + private SmsCodeProvider smsCodeProvider; + + @Override + public UserDetails loadUserByUsername(String payload) { + User user = userService.getUserByUsernameOrMobile(payload); + log.info("load user by mobile:{}", user.toString()); + + // 如果为mobile模式,从短信服务中获取验证码(动态密码) + String credentials = smsCodeProvider.getSmsCode(payload, "LOGIN"); + + return new org.springframework.security.core.userdetails.User( + user.getUsername(), + credentials, + user.getState() == 1 ? true : false, + user.getState() == 1 ? true : false, + user.getState() == 1 ? true : false, + user.getState() == 1 ? true : false, + super.obtainGrantedCompany(user)); + } +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/authority/CustomGrantedAuthority.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/authority/CustomGrantedAuthority.java new file mode 100644 index 0000000..af55e48 --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/authority/CustomGrantedAuthority.java @@ -0,0 +1,36 @@ +package com.springboot.auth.authorization.oauth2.authority; + +/* + ********************************************** + * DATE PERSON REASON + * 2021-01-05 FXY Created + ********************************************** + */ + + +import lombok.AllArgsConstructor; +import org.springframework.security.core.GrantedAuthority; + +/** + * 根据getter方法进行序列化的 + */ +@AllArgsConstructor +public class CustomGrantedAuthority implements GrantedAuthority { + + private final String company; + private boolean isDefault; + + /** + * 后期可换为角色编号 + * + * @return + */ + @Override + public String getAuthority() { + return company; + } + + public boolean isDefault() { + return isDefault; + } +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/enhancer/CustomTokenEnhancer.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/enhancer/CustomTokenEnhancer.java new file mode 100644 index 0000000..4b54e3b --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/enhancer/CustomTokenEnhancer.java @@ -0,0 +1,25 @@ +package com.springboot.auth.authorization.oauth2.enhancer; + +import com.google.common.collect.Maps; +import com.springboot.auth.authorization.oauth2.authority.CustomGrantedAuthority; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.token.TokenEnhancer; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class CustomTokenEnhancer implements TokenEnhancer { + + @Override + public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { + Map additionalInfo = Maps.newHashMap(); + additionalInfo.put("companies", authentication.getAuthorities()); + ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); + return accessToken; + } +} \ No newline at end of file diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/granter/MobileAuthenticationProvider.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/granter/MobileAuthenticationProvider.java new file mode 100644 index 0000000..223fc2d --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/granter/MobileAuthenticationProvider.java @@ -0,0 +1,16 @@ +package com.springboot.auth.authorization.oauth2.granter; + +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.core.userdetails.UserDetailsService; + +public class MobileAuthenticationProvider extends DaoAuthenticationProvider { + + public MobileAuthenticationProvider(UserDetailsService userDetailsService) { + super.setUserDetailsService(userDetailsService); + } + + @Override + public boolean supports(Class authentication) { + return MobileAuthenticationToken.class.isAssignableFrom(authentication); + } +} \ No newline at end of file diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/granter/MobileAuthenticationToken.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/granter/MobileAuthenticationToken.java new file mode 100644 index 0000000..9d8439b --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/granter/MobileAuthenticationToken.java @@ -0,0 +1,11 @@ +package com.springboot.auth.authorization.oauth2.granter; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; + +public class MobileAuthenticationToken extends UsernamePasswordAuthenticationToken { + + public MobileAuthenticationToken(Authentication authenticationToken) { + super(authenticationToken.getPrincipal(), authenticationToken.getCredentials()); + } +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/granter/MobileTokenGranter.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/granter/MobileTokenGranter.java new file mode 100644 index 0000000..f1470e1 --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/oauth2/granter/MobileTokenGranter.java @@ -0,0 +1,53 @@ +package com.springboot.auth.authorization.oauth2.granter; + +import org.springframework.security.authentication.*; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; +import org.springframework.security.oauth2.provider.*; +import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter; +import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class MobileTokenGranter extends ResourceOwnerPasswordTokenGranter { + + private static final String GRANT_TYPE = "mobile"; + + private AuthenticationManager authenticationManager; + + public MobileTokenGranter(AuthenticationManager authenticationManager, + AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, + OAuth2RequestFactory requestFactory) { + super(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE); + this.authenticationManager = authenticationManager; + } + + @Override + protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) { + Map parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters()); + String username = parameters.get("no"); + String password = parameters.get("password"); + // Protect from downstream leaks of password + parameters.remove("no"); + + Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password); + MobileAuthenticationToken mobileAuthenticationToken = new MobileAuthenticationToken(userAuth); + ((AbstractAuthenticationToken) userAuth).setDetails(parameters); + try { + userAuth = this.authenticationManager.authenticate(mobileAuthenticationToken); + } catch (AccountStatusException ase) { + //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31) + throw new InvalidGrantException(ase.getMessage()); + } catch (BadCredentialsException e) { + // If the username/password are wrong the spec says we should send 400/invalid grant + throw new InvalidGrantException(e.getMessage()); + } + if (userAuth == null || !userAuth.isAuthenticated()) { + throw new InvalidGrantException("Could not authenticate user: " + username); + } + + OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); + return new OAuth2Authentication(storedOAuth2Request, mobileAuthenticationToken); + } +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/OrganizationProvider.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/OrganizationProvider.java new file mode 100644 index 0000000..15f366b --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/OrganizationProvider.java @@ -0,0 +1,21 @@ +package com.springboot.auth.authorization.provider; + +import com.springboot.auth.authorization.entity.Company; +import com.springboot.auth.authorization.entity.User; +import com.springboot.cloud.common.core.entity.vo.Result; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@FeignClient(name = "organization", fallback = OrganizationProviderFallback.class,path = "organization") +//@FeignClient(name = "organization", fallback = OrganizationProviderFallback.class) +public interface OrganizationProvider { + + @GetMapping(value = "/user/getUserByUsernameOrMobile") + Result getUserByUsernameOrMobile(@RequestParam("payload")String payload); + + @GetMapping(value = "/company/getUserAllCompany") + Result> getUserAllCompany(@RequestParam("userId")String userId); +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/OrganizationProviderFallback.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/OrganizationProviderFallback.java new file mode 100644 index 0000000..7b6cefe --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/OrganizationProviderFallback.java @@ -0,0 +1,23 @@ +package com.springboot.auth.authorization.provider; + +import com.springboot.auth.authorization.entity.Company; +import com.springboot.auth.authorization.entity.User; +import com.springboot.cloud.common.core.entity.vo.Result; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.List; + +@Component +public class OrganizationProviderFallback implements OrganizationProvider { + + @Override + public Result getUserByUsernameOrMobile(String payload) { + return Result.success(new User()); + } + + @Override + public Result> getUserAllCompany(String userId) { + return Result.success(new HashSet()); + } +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/SmsCodeProvider.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/SmsCodeProvider.java new file mode 100644 index 0000000..4baa2f5 --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/SmsCodeProvider.java @@ -0,0 +1,19 @@ +package com.springboot.auth.authorization.provider; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * todo 实现短信验证码的服务 + */ +//@FeignClient(name = "sms", fallback = OrganizationProviderFallback.class,path="sms") +public interface SmsCodeProvider { + + /** + * @param mobile + * @return + */ + @GetMapping(value = "/sms/{mobile}") + String getSmsCode(@PathVariable("mobile") String mobile, @RequestParam("businessType") String businessType); +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/SmsCodeProviderFallback.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/SmsCodeProviderFallback.java new file mode 100644 index 0000000..b6246dd --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/provider/SmsCodeProviderFallback.java @@ -0,0 +1,18 @@ +package com.springboot.auth.authorization.provider; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +@Component +public class SmsCodeProviderFallback implements SmsCodeProvider { + + @Autowired + PasswordEncoder passwordEncoder; + + @Override + public String getSmsCode(String mobile, String businessType) { + // 该类为mock, 目前暂时没有sms的服务 + return passwordEncoder.encode("123456"); + } +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/service/UserService.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/service/UserService.java new file mode 100644 index 0000000..7c9840c --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/service/UserService.java @@ -0,0 +1,22 @@ +package com.springboot.auth.authorization.service; + +import com.springboot.auth.authorization.entity.Company; +import com.springboot.auth.authorization.entity.User; + +import java.util.List; + +public interface UserService { + + /** + * 通过账号或者手机号得到用户信息 + * @param payload 账号或者手机号 + * @return + */ + User getUserByUsernameOrMobile(String payload); + + /** + * 通过用户编号得到所有所属公司 + */ + List getUserAllCompany(String userId); + +} diff --git a/auth/authorization-server/src/main/java/com/springboot/auth/authorization/service/impl/UserServiceImpl.java b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..7cdcc6d --- /dev/null +++ b/auth/authorization-server/src/main/java/com/springboot/auth/authorization/service/impl/UserServiceImpl.java @@ -0,0 +1,27 @@ +package com.springboot.auth.authorization.service.impl; + +import com.springboot.auth.authorization.entity.Company; +import com.springboot.auth.authorization.entity.User; +import com.springboot.auth.authorization.provider.OrganizationProvider; +import com.springboot.auth.authorization.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UserServiceImpl implements UserService { + + @Autowired + private OrganizationProvider organizationProvider; + + @Override + public User getUserByUsernameOrMobile(String payload) { + return organizationProvider.getUserByUsernameOrMobile(payload).getData(); + } + + @Override + public List getUserAllCompany(String userId) { + return organizationProvider.getUserAllCompany(userId).getData(); + } +} diff --git a/auth/authorization-server/src/test/java/com/springboot/auth/authorization/ApplicationTests.java b/auth/authorization-server/src/test/java/com/springboot/auth/authorization/ApplicationTests.java new file mode 100644 index 0000000..f561e25 --- /dev/null +++ b/auth/authorization-server/src/test/java/com/springboot/auth/authorization/ApplicationTests.java @@ -0,0 +1,15 @@ +package com.springboot.auth.authorization; + +import org.junit.Test; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + + +public class ApplicationTests { + + @Test + public void contextLoads() { + PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + System.out.println(passwordEncoder.encode("test_secret")); + } +} diff --git a/auth/pom.xml b/auth/pom.xml new file mode 100644 index 0000000..cdcddd7 --- /dev/null +++ b/auth/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + business.chaoran + auth + 0.0.1-SNAPSHOT + pom + + auth + Demo Auth project for Spring Boot + + + business.chaoran + xin-cloud + 1.0-SNAPSHOT + + + + authentication-server + authentication-client + authorization-server + + + + + org.springframework.security.oauth + spring-security-oauth2 + [2.2.4,) + + + org.springframework.security + spring-security-jwt + RELEASE + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + org.springframework.boot + spring-boot-starter-web + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 1.3.2 + + + com.alibaba + druid-spring-boot-starter + 1.1.9 + + + + mysql + mysql-connector-java + 8.0.18 + + + + org.springframework.boot + spring-boot-starter-data-redis + + + diff --git a/common/core/.gitignore b/common/core/.gitignore new file mode 100644 index 0000000..82eca33 --- /dev/null +++ b/common/core/.gitignore @@ -0,0 +1,25 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/common/core/pom.xml b/common/core/pom.xml new file mode 100644 index 0000000..73ac598 --- /dev/null +++ b/common/core/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + business.chaoran + core + 0.0.1-SNAPSHOT + jar + + core + Demo Core project for Spring Boot + + + UTF-8 + UTF-8 + 1.8 + 1.8 + + + + business.chaoran + common + 0.0.1-SNAPSHOT + + + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + diff --git a/common/core/src/main/java/com/springboot/cloud/common/core/entity/vo/Result.java b/common/core/src/main/java/com/springboot/cloud/common/core/entity/vo/Result.java new file mode 100644 index 0000000..fc7602e --- /dev/null +++ b/common/core/src/main/java/com/springboot/cloud/common/core/entity/vo/Result.java @@ -0,0 +1,167 @@ +package com.springboot.cloud.common.core.entity.vo; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.springboot.cloud.common.core.exception.BaseException; +import com.springboot.cloud.common.core.exception.ErrorType; +import com.springboot.cloud.common.core.exception.SystemErrorType; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; + +import java.time.Instant; +import java.time.ZonedDateTime; + +@ApiModel(description = "rest请求的返回模型,所有rest正常都返回该类的对象") +@Getter +public class Result { + + public static final String SUCCESSFUL_CODE = "000000"; + public static final String SUCCESSFUL_MESG = "处理成功"; + + @ApiModelProperty(value = "处理结果code", required = true) + private String code; + @ApiModelProperty(value = "处理结果描述信息") + private String msg; + @ApiModelProperty(value = "请求结果生成时间戳") + private Instant time; + @ApiModelProperty(value = "处理结果数据信息") + @JsonInclude(JsonInclude.Include.NON_NULL) + private T data; + + public Result() { + this.time = ZonedDateTime.now().toInstant(); + } + + /** + * @param errorType + */ + public Result(ErrorType errorType) { + this.code = errorType.getCode(); + this.msg = errorType.getMesg(); + this.time = ZonedDateTime.now().toInstant(); + } + + /** + * @param errorType + * @param data + */ + public Result(ErrorType errorType, T data) { + this(errorType); + this.data = data; + } + + /** + * 内部使用,用于构造成功的结果 + * + * @param code + * @param msg + * @param data + */ + private Result(String code, String msg, T data) { + this.code = code; + this.msg = msg; + this.data = data; + this.time = ZonedDateTime.now().toInstant(); + } + + /** + * 快速创建成功结果并返回结果数据 + * + * @param data + * @return Result + */ + public static Result success(Object data) { + return new Result<>(SUCCESSFUL_CODE, SUCCESSFUL_MESG, data); + } + + /** + * 快速创建成功结果 + * + * @return Result + */ + public static Result success() { + return success(null); + } + + /** + * 系统异常类没有返回数据 + * + * @return Result + */ + public static Result fail() { + return new Result(SystemErrorType.SYSTEM_ERROR); + } + + /** + * 系统异常类没有返回数据 + * + * @param baseException + * @return Result + */ + public static Result fail(BaseException baseException) { + return fail(baseException, null); + } + + /** + * 系统异常类并返回结果数据 + * + * @param data + * @return Result + */ + public static Result fail(BaseException baseException, Object data) { + return new Result<>(baseException.getErrorType(), data); + } + + /** + * 系统异常类并返回结果数据 + * + * @param errorType + * @param data + * @return Result + */ + public static Result fail(ErrorType errorType, Object data) { + return new Result<>(errorType, data); + } + + /** + * 系统异常类并返回结果数据 + * + * @param errorType + * @return Result + */ + public static Result fail(ErrorType errorType) { + return Result.fail(errorType, null); + } + + /** + * 系统异常类并返回结果数据 + * + * @param data + * @return Result + */ + public static Result fail(Object data) { + return new Result<>(SystemErrorType.SYSTEM_ERROR, data); + } + + + /** + * 成功code=000000 + * + * @return true/false + */ + @JsonIgnore + public boolean isSuccess() { + return SUCCESSFUL_CODE.equals(this.code); + } + + /** + * 失败 + * + * @return true/false + */ + @JsonIgnore + public boolean isFail() { + return !isSuccess(); + } +} diff --git a/common/core/src/main/java/com/springboot/cloud/common/core/exception/BaseException.java b/common/core/src/main/java/com/springboot/cloud/common/core/exception/BaseException.java new file mode 100644 index 0000000..020e6ed --- /dev/null +++ b/common/core/src/main/java/com/springboot/cloud/common/core/exception/BaseException.java @@ -0,0 +1,32 @@ +package com.springboot.cloud.common.core.exception; + +import lombok.Getter; + +@Getter +public class BaseException extends RuntimeException { + /** + * 异常对应的错误类型 + */ + private final ErrorType errorType; + + /** + * 默认是系统异常 + */ + public BaseException() { + this.errorType = SystemErrorType.SYSTEM_ERROR; + } + + public BaseException(ErrorType errorType) { + this.errorType = errorType; + } + + public BaseException(ErrorType errorType, String message) { + super(message); + this.errorType = errorType; + } + + public BaseException(ErrorType errorType, String message, Throwable cause) { + super(message, cause); + this.errorType = errorType; + } +} diff --git a/common/core/src/main/java/com/springboot/cloud/common/core/exception/ErrorType.java b/common/core/src/main/java/com/springboot/cloud/common/core/exception/ErrorType.java new file mode 100644 index 0000000..ba712eb --- /dev/null +++ b/common/core/src/main/java/com/springboot/cloud/common/core/exception/ErrorType.java @@ -0,0 +1,17 @@ +package com.springboot.cloud.common.core.exception; + +public interface ErrorType { + /** + * 返回code + * + * @return + */ + String getCode(); + + /** + * 返回mesg + * + * @return + */ + String getMesg(); +} diff --git a/common/core/src/main/java/com/springboot/cloud/common/core/exception/ServiceException.java b/common/core/src/main/java/com/springboot/cloud/common/core/exception/ServiceException.java new file mode 100644 index 0000000..0742efb --- /dev/null +++ b/common/core/src/main/java/com/springboot/cloud/common/core/exception/ServiceException.java @@ -0,0 +1,11 @@ +package com.springboot.cloud.common.core.exception; + +/** + * Created by zhoutaoo on 2018/6/2. + */ +public class ServiceException extends BaseException { + + //TODO 对业务异常的返回码进行校验,规范到一定范围内 + + +} diff --git a/common/core/src/main/java/com/springboot/cloud/common/core/exception/SystemErrorType.java b/common/core/src/main/java/com/springboot/cloud/common/core/exception/SystemErrorType.java new file mode 100644 index 0000000..5e4bce1 --- /dev/null +++ b/common/core/src/main/java/com/springboot/cloud/common/core/exception/SystemErrorType.java @@ -0,0 +1,34 @@ +package com.springboot.cloud.common.core.exception; + +import lombok.Getter; + +@Getter +public enum SystemErrorType implements ErrorType { + + SYSTEM_ERROR("-1", "系统异常"), + SYSTEM_BUSY("000001", "系统繁忙,请稍候再试"), + + GATEWAY_NOT_FOUND_SERVICE("010404", "服务未找到"), + GATEWAY_ERROR("010500", "网关异常"), + GATEWAY_CONNECT_TIME_OUT("010002", "网关超时"), + + ARGUMENT_NOT_VALID("020000", "请求参数校验不通过"), + INVALID_TOKEN("020001", "无效token"), + UPLOAD_FILE_SIZE_LIMIT("020010", "上传文件大小超过限制"), + + DUPLICATE_PRIMARY_KEY("030000","唯一键冲突"); + + /** + * 错误类型码 + */ + private String code; + /** + * 错误类型描述信息 + */ + private String mesg; + + SystemErrorType(String code, String mesg) { + this.code = code; + this.mesg = mesg; + } +} diff --git a/common/core/src/main/java/com/springboot/cloud/common/core/util/UserContextHolder.java b/common/core/src/main/java/com/springboot/cloud/common/core/util/UserContextHolder.java new file mode 100644 index 0000000..7ba5ace --- /dev/null +++ b/common/core/src/main/java/com/springboot/cloud/common/core/util/UserContextHolder.java @@ -0,0 +1,84 @@ +package com.springboot.cloud.common.core.util; + +import com.google.common.collect.Maps; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * {"companies":[{"default":true,"authority":"1"},{"default":false,"authority":"2"}],"user_name":"admin","scope":["read"],"exp":1610100088,"authorities":["1","2"],"jti":"nt9bTYbUe8IzuEgfAz70nwaMveI","client_id":"test_client"} + */ + +/** + * 用户上下文 + */ +public class UserContextHolder { + + private ThreadLocal> threadLocal; + + private UserContextHolder() { + this.threadLocal = new ThreadLocal<>(); + } + + /** + * 创建实例 + * + * @return + */ + public static UserContextHolder getInstance() { + return SingletonHolder.sInstance; + } + + /** + * 静态内部类单例模式 + * 单例初使化 + */ + private static class SingletonHolder { + private static final UserContextHolder sInstance = new UserContextHolder(); + } + + /** + * 用户上下文中放入信息 + * + * @param map + */ + public void setContext(Map map) { + threadLocal.set(map); + } + + /** + * 获取上下文中的信息 + * + * @return + */ + public Map getContext() { + return threadLocal.get(); + } + + /** + * 获取上下文中的用户名 + * + * @return + */ + public String getUsername() { + return Optional.ofNullable(threadLocal.get()).orElse(Maps.newHashMap()).get("user_name"); + } + + /** + * 获取上下文中用户登录的公司 + * + * @return + */ + public String getCurrentCompany() { + return Optional.ofNullable(threadLocal.get()).orElse(Maps.newHashMap()).get("company"); + } + + /** + * 清空上下文 + */ + public void clear() { + threadLocal.remove(); + } + +} diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 0000000..a65479c --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + business.chaoran + common + 0.0.1-SNAPSHOT + pom + + common + Demo Common project for Spring Boot + + + core + web + + + + + commons-lang + commons-lang + 2.6 + + + org.springframework + spring-core + 5.0.11.RELEASE + + + + org.projectlombok + lombok + 1.18.10 + provided + + + + junit + junit + 4.12 + test + + + + diff --git a/common/web/pom.xml b/common/web/pom.xml new file mode 100644 index 0000000..0b47901 --- /dev/null +++ b/common/web/pom.xml @@ -0,0 +1,102 @@ + + + 4.0.0 + + business.chaoran + web + 0.0.1-SNAPSHOT + jar + + web + Demo Web project for Spring Boot + + + UTF-8 + UTF-8 + 1.8 + 1.8 + + + + business.chaoran + common + 0.0.1-SNAPSHOT + + + + + business.chaoran + core + 0.0.1-SNAPSHOT + + + + org.springframework + spring-web + 5.0.4.RELEASE + + + org.springframework + spring-webmvc + 5.1.0.RELEASE + + + com.fasterxml.jackson.core + jackson-databind + 2.10.0.pr1 + + + + com.baomidou + mybatis-plus-boot-starter + 3.1.0 + + + org.mybatis + mybatis-spring + 2.0.0 + + + + org.springframework.boot + spring-boot-starter-data-redis + 2.1.4.RELEASE + + + org.apache.commons + commons-pool2 + 2.6.0 + + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + + org.springframework + spring-test + 5.1.6.RELEASE + + + org.springframework.boot + spring-boot-starter-test + test + RELEASE + + + org.mybatis + mybatis + 3.5.1 + compile + + + io.github.openfeign + feign-core + 10.1.0 + + + diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/entity/form/BaseForm.java b/common/web/src/main/java/com/springboot/cloud/common/web/entity/form/BaseForm.java new file mode 100644 index 0000000..758e73f --- /dev/null +++ b/common/web/src/main/java/com/springboot/cloud/common/web/entity/form/BaseForm.java @@ -0,0 +1,43 @@ +package com.springboot.cloud.common.web.entity.form; + +import com.springboot.cloud.common.web.entity.po.BasePo; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; + +@ApiModel +@Slf4j +@Data +public class BaseForm { + /** + * 用户名 + */ + private String username; + + /** + * Form转化为Po,进行后续业务处理 + * + * @param clazz + * @return + */ + public T toPo(Class clazz) { + T t = BeanUtils.instantiateClass(clazz); + BeanUtils.copyProperties(this, t); + return t; + } + + /** + * Form转化为Po,进行后续业务处理 + * + * @param id + * @param clazz + * @return + */ + public T toPo(String id, Class clazz) { + T t = BeanUtils.instantiateClass(clazz); + t.setId(id); + BeanUtils.copyProperties(this, t); + return t; + } +} diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/entity/form/BaseQueryForm.java b/common/web/src/main/java/com/springboot/cloud/common/web/entity/form/BaseQueryForm.java new file mode 100644 index 0000000..3bdaa5d --- /dev/null +++ b/common/web/src/main/java/com/springboot/cloud/common/web/entity/form/BaseQueryForm.java @@ -0,0 +1,44 @@ +package com.springboot.cloud.common.web.entity.form; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.springboot.cloud.common.web.entity.param.BaseParam; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; + +@ApiModel +@Slf4j +@Data +public class BaseQueryForm

extends BaseForm { + /** + * 分页查询的参数,当前页数 + */ + private long current = 1; + /** + * 分页查询的参数,当前页面每页显示的数量 + */ + private long size = 10; + + /** + * Form转化为Param + * + * @param clazz + * @return + */ + public P toParam(Class

clazz) { + P p = BeanUtils.instantiateClass(clazz); + BeanUtils.copyProperties(this, p); + return p; + } + + /** + * 从form中获取page参数,用于分页查询参数 + * + * @return + */ + public Page getPage() { + return new Page(this.getCurrent(), this.getSize()); + } + +} diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/entity/param/BaseParam.java b/common/web/src/main/java/com/springboot/cloud/common/web/entity/param/BaseParam.java new file mode 100644 index 0000000..a192322 --- /dev/null +++ b/common/web/src/main/java/com/springboot/cloud/common/web/entity/param/BaseParam.java @@ -0,0 +1,21 @@ +package com.springboot.cloud.common.web.entity.param; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.springboot.cloud.common.web.entity.po.BasePo; +import lombok.Data; + +import java.util.Date; + + +@Data +public class BaseParam { + private Date createdTimeStart; + private Date createdTimeEnd; + + public QueryWrapper build() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.ge(null != this.createdTimeStart, "created_time", this.createdTimeStart) + .le(null != this.createdTimeEnd, "created_time", this.createdTimeEnd); + return queryWrapper; + } +} diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/entity/po/BasePo.java b/common/web/src/main/java/com/springboot/cloud/common/web/entity/po/BasePo.java new file mode 100644 index 0000000..c21f2b4 --- /dev/null +++ b/common/web/src/main/java/com/springboot/cloud/common/web/entity/po/BasePo.java @@ -0,0 +1,29 @@ +package com.springboot.cloud.common.web.entity.po; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class BasePo implements Serializable { + public final static String DEFAULT_USERNAME = "system"; + @TableId(type = IdType.ID_WORKER_STR) + private String id; + + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @TableField(fill = FieldFill.INSERT) + private Date createdTime; + + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updatedTime; +} diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/entity/vo/BaseVo.java b/common/web/src/main/java/com/springboot/cloud/common/web/entity/vo/BaseVo.java new file mode 100644 index 0000000..226933f --- /dev/null +++ b/common/web/src/main/java/com/springboot/cloud/common/web/entity/vo/BaseVo.java @@ -0,0 +1,13 @@ +package com.springboot.cloud.common.web.entity.vo; + +import com.springboot.cloud.common.web.entity.po.BasePo; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@NoArgsConstructor +public class BaseVo implements Serializable { + private String id; +} diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/exception/DefaultGlobalExceptionHandlerAdvice.java b/common/web/src/main/java/com/springboot/cloud/common/web/exception/DefaultGlobalExceptionHandlerAdvice.java new file mode 100644 index 0000000..1184e36 --- /dev/null +++ b/common/web/src/main/java/com/springboot/cloud/common/web/exception/DefaultGlobalExceptionHandlerAdvice.java @@ -0,0 +1,59 @@ +package com.springboot.cloud.common.web.exception; + +import com.springboot.cloud.common.core.entity.vo.Result; +import com.springboot.cloud.common.core.exception.BaseException; +import com.springboot.cloud.common.core.exception.SystemErrorType; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.multipart.MultipartException; + +@Slf4j +public class DefaultGlobalExceptionHandlerAdvice { + + @ExceptionHandler(value = {MissingServletRequestParameterException.class}) + public Result missingServletRequestParameterException(MissingServletRequestParameterException ex) { + log.error("missing servlet request parameter exception:{}", ex.getMessage()); + return Result.fail(SystemErrorType.ARGUMENT_NOT_VALID); + } + + @ExceptionHandler(value = {MultipartException.class}) + public Result uploadFileLimitException(MultipartException ex) { + log.error("upload file size limit:{}", ex.getMessage()); + return Result.fail(SystemErrorType.UPLOAD_FILE_SIZE_LIMIT); + } + + @ExceptionHandler(value = {MethodArgumentNotValidException.class}) + public Result serviceException(MethodArgumentNotValidException ex) { + log.error("service exception:{}", ex.getMessage()); + return Result.fail(SystemErrorType.ARGUMENT_NOT_VALID, ex.getBindingResult().getFieldError().getDefaultMessage()); + } + + @ExceptionHandler(value = {DuplicateKeyException.class}) + public Result duplicateKeyException(DuplicateKeyException ex) { + log.error("primary key duplication exception:{}", ex.getMessage()); + return Result.fail(SystemErrorType.DUPLICATE_PRIMARY_KEY); + } + + @ExceptionHandler(value = {BaseException.class}) + public Result baseException(BaseException ex) { + log.error("base exception:{}", ex.getMessage()); + return Result.fail(ex.getErrorType()); + } + + @ExceptionHandler(value = {Exception.class}) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result exception() { + return Result.fail(); + } + + @ExceptionHandler(value = {Throwable.class}) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result throwable() { + return Result.fail(); + } +} \ No newline at end of file diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/handler/PoMetaObjectHandler.java b/common/web/src/main/java/com/springboot/cloud/common/web/handler/PoMetaObjectHandler.java new file mode 100644 index 0000000..eec4c41 --- /dev/null +++ b/common/web/src/main/java/com/springboot/cloud/common/web/handler/PoMetaObjectHandler.java @@ -0,0 +1,36 @@ +package com.springboot.cloud.common.web.handler; + +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.springboot.cloud.common.core.util.UserContextHolder; +import com.springboot.cloud.common.web.entity.po.BasePo; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.apache.ibatis.reflection.MetaObject; + +import java.time.ZonedDateTime; +import java.util.Date; + +@Slf4j +public class PoMetaObjectHandler implements MetaObjectHandler { + /** + * 获取当前访问用户,为空返回默认system + * + * @return + */ + private String getCurrentUsername() { + return StringUtils.defaultIfBlank(UserContextHolder.getInstance().getUsername(), BasePo.DEFAULT_USERNAME); + } + + @Override + public void insertFill(MetaObject metaObject) { + this.setInsertFieldValByName("createdBy", getCurrentUsername(), metaObject); + this.setInsertFieldValByName("createdTime", Date.from(ZonedDateTime.now().toInstant()), metaObject); + this.updateFill(metaObject); + } + + @Override + public void updateFill(MetaObject metaObject) { + this.setUpdateFieldValByName("updatedBy", getCurrentUsername(), metaObject); + this.setUpdateFieldValByName("updatedTime", Date.from(ZonedDateTime.now().toInstant()), metaObject); + } +} \ No newline at end of file diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/FeignBasicAuthRequestInterceptor.java b/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/FeignBasicAuthRequestInterceptor.java new file mode 100644 index 0000000..e8b3f47 --- /dev/null +++ b/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/FeignBasicAuthRequestInterceptor.java @@ -0,0 +1,46 @@ +package com.springboot.cloud.common.web.interceptor; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-04 FXY Created + ********************************************** + */ + + +import feign.RequestInterceptor; +import feign.RequestTemplate; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.DigestUtils; + +import java.util.Collection; +import java.util.Map; + + +@Slf4j +public class FeignBasicAuthRequestInterceptor implements RequestInterceptor { + + public FeignBasicAuthRequestInterceptor(){ + log.info("========================加载自定义拦截器========================="); + } + + //服务间调用头 + private static final String SERVER_CLIENT_TOKEN="server-client-token"; + //服务间调用秘钥 + private static final String SERVER_CLIENT_SECRET="server"; + //网关调用服务头 + private static final String X_CLIENT_TOKEN="x-client-token"; + + @Override + public void apply(RequestTemplate requestTemplate) { + String url = requestTemplate.path(); + Map> headers = requestTemplate.headers(); + if(!headers.containsKey(X_CLIENT_TOKEN)){ + String method = requestTemplate.method(); + String originStr = new StringBuilder().append(url).append(method).append(SERVER_CLIENT_TOKEN).append(SERVER_CLIENT_SECRET).toString(); + // 加入自定义头信息 + String md5Secret = DigestUtils.md5DigestAsHex(originStr.getBytes()); + requestTemplate.header(SERVER_CLIENT_TOKEN, md5Secret); + } + } +} \ No newline at end of file diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/UserInterceptor.java b/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/UserInterceptor.java new file mode 100644 index 0000000..261019f --- /dev/null +++ b/common/web/src/main/java/com/springboot/cloud/common/web/interceptor/UserInterceptor.java @@ -0,0 +1,87 @@ +package com.springboot.cloud.common.web.interceptor; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.springboot.cloud.common.core.util.UserContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.lang.Nullable; +import org.springframework.util.DigestUtils; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; +import java.util.Optional; + +/** + * 用户信息拦截器 + */ +@Slf4j +public class UserInterceptor implements HandlerInterceptor { + /** + * 服务间调用token用户信息,格式为json + * { + * "user_name":"必须有" + * "自定义key:"value" + * } + */ + //获取相关授权信息请求头 + private static final String X_CLIENT_TOKEN_USER = "x-client-token-user"; + + //网关调用服务请求头 + private static final String X_CLIENT_TOKEN = "x-client-token"; + + //网关调用服务秘钥 + private static final String X_CLIENT_SECRET = "gateway-web"; + + //服务间调用请求头 + private static final String SERVER_CLIENT_TOKEN = "server-client-token"; + + //服务间调用秘钥 + private static final String SERVER_CLIENT_SECRET = "server"; + + //当前用户登录公司 + private static final String USER_CURRENT_COMPANY = "company"; + + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + //从网关获取并校验,通过校验就可信任x-client-token-user中的信息 + boolean b = checkToken(request); + if (!b) { + //重定向到登录前端 + response.sendRedirect("https://www.baidu.com"); + return b; + } + + //放入上下文数据 + String userInfoString = StringUtils.defaultIfBlank(request.getHeader(X_CLIENT_TOKEN_USER), "{}"); + Map context = new ObjectMapper().readValue(userInfoString, Map.class); + context.put("company", request.getHeader(USER_CURRENT_COMPANY)); + UserContextHolder.getInstance().setContext(context); + return true; + } + + private boolean checkToken(HttpServletRequest request) { + String method = request.getMethod(); + String url = request.getServletPath(); + Optional serverToken = Optional.ofNullable(request.getHeader(SERVER_CLIENT_TOKEN)); + Optional clientToken = Optional.ofNullable(request.getHeader(X_CLIENT_TOKEN)); + if (serverToken.isPresent()) { + //如果是服务间相互调用不需要加contextPath,因为feign拦截器中加密是根据servletPath来加密的,此处也是根据servletPath解密的 + String originStr = new StringBuilder().append(url).append(method).append(SERVER_CLIENT_TOKEN).append(SERVER_CLIENT_SECRET).toString(); + return DigestUtils.md5DigestAsHex(originStr.getBytes()).equals(serverToken.get()); + } else if (clientToken.isPresent()) { + //如果是网关调用服务,网关服务需要加上contextPath + String originStr = new StringBuilder().append(request.getContextPath().concat(url)).append(method).append(X_CLIENT_TOKEN).append(X_CLIENT_SECRET).toString(); + return DigestUtils.md5DigestAsHex(originStr.getBytes()).equals(clientToken.get()); + } else { + return false; + } + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { + UserContextHolder.getInstance().clear(); + } +} diff --git a/common/web/src/main/java/com/springboot/cloud/common/web/redis/RedisConfig.java b/common/web/src/main/java/com/springboot/cloud/common/web/redis/RedisConfig.java new file mode 100644 index 0000000..2d0257a --- /dev/null +++ b/common/web/src/main/java/com/springboot/cloud/common/web/redis/RedisConfig.java @@ -0,0 +1,48 @@ +package com.springboot.cloud.common.web.redis; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.CachingConfigurerSupport; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.cache.RedisCacheWriter; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; + +import java.time.Duration; + +@Configuration +public class RedisConfig extends CachingConfigurerSupport { + + @Bean + public CacheManager cacheManager(RedisConnectionFactory factory) { + //对象的序列化 + RedisSerializationContext.SerializationPair valueSerializationPair + = RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer()); + //全局redis缓存过期时间 + RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofDays(1)) +// .serializeKeysWith() + .serializeValuesWith(valueSerializationPair); + + return new RedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory), redisCacheConfiguration); + } + + private Jackson2JsonRedisSerializer jackson2JsonRedisSerializer() { + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); + jackson2JsonRedisSerializer.setObjectMapper(objectMapper()); + return jackson2JsonRedisSerializer; + } + + private ObjectMapper objectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); + return objectMapper; + } +} \ No newline at end of file diff --git a/common/web/src/test/java/com/springboot/cloud/common/web/exception/DefaultGlobalExceptionHandlerAdviceTest.java b/common/web/src/test/java/com/springboot/cloud/common/web/exception/DefaultGlobalExceptionHandlerAdviceTest.java new file mode 100644 index 0000000..b6043f4 --- /dev/null +++ b/common/web/src/test/java/com/springboot/cloud/common/web/exception/DefaultGlobalExceptionHandlerAdviceTest.java @@ -0,0 +1,12 @@ +package com.springboot.cloud.common.web.exception; + +import org.junit.Test; + +public class DefaultGlobalExceptionHandlerAdviceTest { + + @Test + public void testMethod() { + + } + +} \ No newline at end of file diff --git a/common/web/src/test/java/com/springboot/cloud/common/web/interceptor/UserInterceptorTest.java b/common/web/src/test/java/com/springboot/cloud/common/web/interceptor/UserInterceptorTest.java new file mode 100644 index 0000000..8d761a1 --- /dev/null +++ b/common/web/src/test/java/com/springboot/cloud/common/web/interceptor/UserInterceptorTest.java @@ -0,0 +1,27 @@ +package com.springboot.cloud.common.web.interceptor; + +import com.springboot.cloud.common.core.util.UserContextHolder; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +public class UserInterceptorTest { + @Test + public void preHandle_当未设置token_user_那么正常处理下一个handle() throws Exception { + UserInterceptor userInterceptor = new UserInterceptor(); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + userInterceptor.preHandle(request, response, new Object()); + } + + @Test + public void preHandle_当设置token的username_那么username可以在线程中拿出来用() throws Exception { + UserInterceptor userInterceptor = new UserInterceptor(); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("x-client-token-user", "{\"user_name\":\"zhangsan\"}"); + MockHttpServletResponse response = new MockHttpServletResponse(); + userInterceptor.preHandle(request, response, new Object()); + Assert.assertEquals(UserContextHolder.getInstance().getUsername(), "zhangsan"); + } +} \ No newline at end of file diff --git a/doc/连锁ERP架构.xmind b/doc/连锁ERP架构.xmind new file mode 100644 index 0000000..33fb79d Binary files /dev/null and b/doc/连锁ERP架构.xmind differ diff --git a/doc/连锁ERP架构说明书.docx b/doc/连锁ERP架构说明书.docx new file mode 100644 index 0000000..9ae05c6 Binary files /dev/null and b/doc/连锁ERP架构说明书.docx differ diff --git a/gateway/gateway-admin/.gitignore b/gateway/gateway-admin/.gitignore new file mode 100644 index 0000000..3a05198 --- /dev/null +++ b/gateway/gateway-admin/.gitignore @@ -0,0 +1,16 @@ +target/ +logs/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr diff --git a/gateway/gateway-admin/pom.xml b/gateway/gateway-admin/pom.xml new file mode 100644 index 0000000..14d7244 --- /dev/null +++ b/gateway/gateway-admin/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + gateway-admin + 0.0.1-SNAPSHOT + jar + + gateway-admin + Demo Gateway Admin project for Spring Cloud + + + webapp-parent + business.chaoran + 0.0.1-SNAPSHOT + ../../webapps/webapp-parent/pom.xml + + + + + com.alicp.jetcache + jetcache-starter-redis + 2.5.14 + + + org.springframework.cloud + spring-cloud-gateway-core + 2.1.0.RELEASE + compile + + + diff --git a/gateway/gateway-admin/src/main/db/db.sql b/gateway/gateway-admin/src/main/db/db.sql new file mode 100644 index 0000000..63810ae --- /dev/null +++ b/gateway/gateway-admin/src/main/db/db.sql @@ -0,0 +1,66 @@ +SET NAMES utf8; + +DROP DATABASE IF EXISTS sc_gateway; +CREATE DATABASE sc_gateway DEFAULT CHARSET utf8mb4; + +USE sc_gateway; + +-- 网关路由表 +DROP TABLE IF EXISTS gateway_route; +CREATE TABLE gateway_route +( + id VARCHAR(20) PRIMARY KEY COMMENT 'id', + route_id VARCHAR(100) NOT NULL COMMENT '路由id', + uri VARCHAR(100) NOT NULL COMMENT 'uri路径', + predicates TEXT NOT NULL COMMENT '判定器', + filters TEXT COMMENT '过滤器', + orders INT COMMENT '排序', + description VARCHAR(500) COMMENT '描述', + status VARCHAR(1) DEFAULT 'Y' COMMENT '状态:Y-有效,N-无效', + created_time DATETIME NOT NULL DEFAULT now() COMMENT '创建时间', + updated_time DATETIME NOT NULL DEFAULT now() COMMENT '更新时间', + created_by VARCHAR(100) NOT NULL COMMENT '创建人', + updated_by VARCHAR(100) NOT NULL COMMENT '更新人' +) COMMENT '网关路由表'; + +CREATE UNIQUE INDEX ux_gateway_routes_uri ON gateway_route (uri); + + +-- DML初始数据 +-- 路由数据 +INSERT INTO gateway_route (id, route_id, uri, predicates, filters, orders, description, status, created_time, updated_time, created_by, updated_by) +VALUES +(101, + 'authorization-server', + 'lb://authorization-server:8000', + '[{"name":"Path","args":{"pattern":"/authorization-server/**"}}]', + '[{"name":"StripPrefix","args":{"parts":"1"}}]', + 100, + '授权认证服务网关注册', + 'Y', now(), now(), 'system', 'system'), +(102, + 'authentication-server', + 'lb://authentication-server:8001', + '[{"name":"Path","args":{"pattern":"/authentication-server/**"}}]', + '[{"name":"StripPrefix","args":{"parts":"1"}}]', + 100, + '签权服务网关注册', + 'Y', now(), now(), 'system', 'system'), +(103, + 'organization', + 'lb://organization:8010', + '[{"name":"Path","args":{"pattern":"/organization/**"}}]', + '[{"name":"StripPrefix","args":{"parts":"1"}}]', + 100, + '系统管理相关接口', + 'Y', now(), now(), 'system', 'system'), +(104, + 'gateway-admin', + 'lb://gateway-admin:8445', + '[{"name":"Path","args":{"pattern":"/gateway-admin/**"}}]', + '[{"name":"StripPrefix","args":{"parts":"1"}}]', + 100, + '网关管理相关接口', + 'Y', now(), now(), 'system', 'system') + + diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/GatewayAdminApplication.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/GatewayAdminApplication.java new file mode 100644 index 0000000..ab3378d --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/GatewayAdminApplication.java @@ -0,0 +1,20 @@ +package com.springboot.cloud.gateway.admin; + +import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation; +import com.alicp.jetcache.anno.config.EnableMethodCache; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration; + +@SpringBootApplication(exclude = GatewayClassPathWarningAutoConfiguration.class) +@EnableDiscoveryClient +@EnableCircuitBreaker +@EnableMethodCache(basePackages = "com.springboot.cloud") +@EnableCreateCacheAnnotation +public class GatewayAdminApplication { + public static void main(String[] args) { + SpringApplication.run(GatewayAdminApplication.class, args); + } +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/BusConfig.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/BusConfig.java new file mode 100644 index 0000000..eec5208 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/BusConfig.java @@ -0,0 +1,50 @@ +package com.springboot.cloud.gateway.admin.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.Binding; +import org.springframework.amqp.core.BindingBuilder; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.core.TopicExchange; +import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Slf4j +public class BusConfig { + + public static final String QUEUE_NAME = "event-gateway"; + public static final String EXCHANGE_NAME = "spring-boot-exchange"; + public static final String ROUTING_KEY = "gateway-route"; + + @Bean + Queue queue() { + log.info("queue name:{}", QUEUE_NAME); + return new Queue(QUEUE_NAME, false); + } + + @Bean + TopicExchange exchange() { + log.info("exchange:{}", EXCHANGE_NAME); + return new TopicExchange(EXCHANGE_NAME); + } + + @Bean + Binding binding(Queue queue, TopicExchange exchange) { + log.info("binding {} to {} with {}", queue, exchange, ROUTING_KEY); + return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY); + } + + @Bean + public MessageConverter messageConverter() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + return new ContentTypeDelegatingMessageConverter(new Jackson2JsonMessageConverter(objectMapper)); + } + +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/MyMetaObjectHandler.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/MyMetaObjectHandler.java new file mode 100644 index 0000000..79c3e2d --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/MyMetaObjectHandler.java @@ -0,0 +1,9 @@ +package com.springboot.cloud.gateway.admin.config; + +import com.springboot.cloud.common.web.handler.PoMetaObjectHandler; +import org.springframework.stereotype.Component; + +@Component +public class MyMetaObjectHandler extends PoMetaObjectHandler { + +} \ No newline at end of file diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/MyRedisConfig.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/MyRedisConfig.java new file mode 100644 index 0000000..b36f9aa --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/MyRedisConfig.java @@ -0,0 +1,10 @@ +package com.springboot.cloud.gateway.admin.config; + +import com.springboot.cloud.common.web.redis.RedisConfig; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableCaching +public class MyRedisConfig extends RedisConfig { +} \ No newline at end of file diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/MybatisConfig.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/MybatisConfig.java new file mode 100644 index 0000000..74b3366 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/MybatisConfig.java @@ -0,0 +1,21 @@ +package com.springboot.cloud.gateway.admin.config; + +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * 初使化Mybatis审计字段自动赋值的interceptor + */ +@EnableTransactionManagement +@Configuration +public class MybatisConfig { + /** + * 分页插件 + */ + @Bean + public PaginationInterceptor paginationInterceptor() { + return new PaginationInterceptor(); + } +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/SwaggerConfig.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/SwaggerConfig.java new file mode 100644 index 0000000..9d9a559 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/SwaggerConfig.java @@ -0,0 +1,35 @@ +package com.springboot.cloud.gateway.admin.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + @Bean + public Docket createRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.springboot.cloud.gateway.admin")) + .paths(PathSelectors.any()) + .build(); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("网关管理api") + .description("网关管理") + .termsOfServiceUrl("https://github.com/zhoutaoo/SpringCloud") + .version("2.0") + .build(); + } + +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/WebServerMvcConfigurerAdapter.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/WebServerMvcConfigurerAdapter.java new file mode 100644 index 0000000..99fb658 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/config/WebServerMvcConfigurerAdapter.java @@ -0,0 +1,22 @@ +package com.springboot.cloud.gateway.admin.config; + +import com.springboot.cloud.common.web.interceptor.UserInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebServerMvcConfigurerAdapter implements WebMvcConfigurer { + + @Bean + public HandlerInterceptor userInterceptor() { + return new UserInterceptor(); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(userInterceptor()); + } +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/dao/GatewayRouteMapper.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/dao/GatewayRouteMapper.java new file mode 100644 index 0000000..492d9c4 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/dao/GatewayRouteMapper.java @@ -0,0 +1,11 @@ +package com.springboot.cloud.gateway.admin.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.gateway.admin.entity.po.GatewayRoute; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Mapper +@Repository +public interface GatewayRouteMapper extends BaseMapper { +} \ No newline at end of file diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/form/GatewayRouteForm.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/form/GatewayRouteForm.java new file mode 100644 index 0000000..a989593 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/form/GatewayRouteForm.java @@ -0,0 +1,61 @@ +package com.springboot.cloud.gateway.admin.entity.form; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.springboot.cloud.common.web.entity.form.BaseForm; +import com.springboot.cloud.gateway.admin.entity.po.FilterDefinition; +import com.springboot.cloud.gateway.admin.entity.po.GatewayRoute; +import com.springboot.cloud.gateway.admin.entity.po.PredicateDefinition; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import java.util.ArrayList; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@ApiModel +@Data +@Slf4j +public class GatewayRouteForm extends BaseForm { + + @NotEmpty(message = "网关断言不能为空") + @ApiModelProperty(value = "网关断言") + private List predicates = new ArrayList<>(); + + @ApiModelProperty(value = "网关过滤器信息") + private List filters = new ArrayList<>(); + + @NotBlank(message = "uri不能为空") + @ApiModelProperty(value = "网关uri") + private String uri; + + @NotBlank(message = "路由id不能为空") + @ApiModelProperty(value = "网关路由id") + private String routeId; + + @ApiModelProperty(value = "排序") + private Integer orders = 0; + + @ApiModelProperty(value = "网关路由描述信息") + private String description; + + @Override + public GatewayRoute toPo(Class clazz) { + GatewayRoute gatewayRoute = new GatewayRoute(); + BeanUtils.copyProperties(this, gatewayRoute); + try { + ObjectMapper objectMapper = new ObjectMapper(); + gatewayRoute.setFilters(objectMapper.writeValueAsString(this.getFilters())); + gatewayRoute.setPredicates(objectMapper.writeValueAsString(this.getPredicates())); + } catch (JsonProcessingException e) { + log.error("网关filter或predicates配置转换异常", e); + } + return gatewayRoute; + } +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/form/GatewayRouteQueryForm.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/form/GatewayRouteQueryForm.java new file mode 100644 index 0000000..6b2a733 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/form/GatewayRouteQueryForm.java @@ -0,0 +1,31 @@ +package com.springboot.cloud.gateway.admin.entity.form; + +import com.springboot.cloud.common.web.entity.form.BaseQueryForm; +import com.springboot.cloud.gateway.admin.entity.param.GatewayRouteQueryParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.Past; +import java.util.Date; + +@EqualsAndHashCode(callSuper = true) +@ApiModel +@Data +public class GatewayRouteQueryForm extends BaseQueryForm { + + @ApiModelProperty(value = "uri路径", required = true) + private String uri; + + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + @Past(message = "查询开始时间必须小于当前日期") + @ApiModelProperty(value = "查询开始时间") + private Date createdTimeStart; + + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + @Past(message = "查询结束时间必须小于当前日期") + @ApiModelProperty(value = "查询结束时间") + private Date createdTimeEnd; +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/ov/GatewayRouteVo.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/ov/GatewayRouteVo.java new file mode 100644 index 0000000..80bbcb3 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/ov/GatewayRouteVo.java @@ -0,0 +1,56 @@ +package com.springboot.cloud.gateway.admin.entity.ov; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.springboot.cloud.common.web.entity.vo.BaseVo; +import com.springboot.cloud.gateway.admin.entity.po.FilterDefinition; +import com.springboot.cloud.gateway.admin.entity.po.GatewayRoute; +import com.springboot.cloud.gateway.admin.entity.po.PredicateDefinition; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@Slf4j +public class GatewayRouteVo extends BaseVo { + private String id; + private String routeId; + private String description; + private String status; + private String uri; + private Integer orders; + private String createdBy; + private Date createdTime; + private String updatedBy; + private Date updatedTime; + private List filters = new ArrayList<>(); + private List predicates = new ArrayList<>(); + + public GatewayRouteVo(GatewayRoute gatewayRoute) { + this.id = gatewayRoute.getId(); + this.routeId = gatewayRoute.getRouteId(); + this.uri = gatewayRoute.getUri(); + this.description = gatewayRoute.getDescription(); + this.status = gatewayRoute.getStatus(); + this.orders = gatewayRoute.getOrders(); + this.createdBy = gatewayRoute.getCreatedBy(); + this.createdTime = gatewayRoute.getCreatedTime(); + this.updatedBy = gatewayRoute.getUpdatedBy(); + this.updatedTime = gatewayRoute.getUpdatedTime(); + ObjectMapper objectMapper = new ObjectMapper(); + try { + this.filters = objectMapper.readValue(gatewayRoute.getFilters(), new TypeReference>() { + }); + this.predicates = objectMapper.readValue(gatewayRoute.getPredicates(), new TypeReference>() { + }); + } catch (IOException e) { + log.error("网关路由对象转换失败", e); + } + } +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/param/GatewayRouteQueryParam.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/param/GatewayRouteQueryParam.java new file mode 100644 index 0000000..78a863f --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/param/GatewayRouteQueryParam.java @@ -0,0 +1,16 @@ +package com.springboot.cloud.gateway.admin.entity.param; + +import com.springboot.cloud.common.web.entity.param.BaseParam; +import com.springboot.cloud.gateway.admin.entity.po.GatewayRoute; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +public class GatewayRouteQueryParam extends BaseParam { + private String uri; +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/po/FilterDefinition.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/po/FilterDefinition.java new file mode 100644 index 0000000..298dea6 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/po/FilterDefinition.java @@ -0,0 +1,16 @@ +package com.springboot.cloud.gateway.admin.entity.po; + +import lombok.*; + +import java.util.LinkedHashMap; +import java.util.Map; + +@EqualsAndHashCode +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FilterDefinition { + private String name; + private Map args = new LinkedHashMap<>(); +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/po/GatewayRoute.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/po/GatewayRoute.java new file mode 100644 index 0000000..8e85508 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/po/GatewayRoute.java @@ -0,0 +1,19 @@ +package com.springboot.cloud.gateway.admin.entity.po; + +import com.springboot.cloud.common.web.entity.po.BasePo; +import lombok.*; + +@EqualsAndHashCode(callSuper = true) +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class GatewayRoute extends BasePo { + private String uri; + private String routeId; + private String predicates; + private String filters; + private String description; + private Integer orders = 0; + private String status = "Y"; +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/po/PredicateDefinition.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/po/PredicateDefinition.java new file mode 100644 index 0000000..aa00b75 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/entity/po/PredicateDefinition.java @@ -0,0 +1,16 @@ +package com.springboot.cloud.gateway.admin.entity.po; + +import lombok.*; + +import java.util.LinkedHashMap; +import java.util.Map; + +@EqualsAndHashCode +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PredicateDefinition { + private String name; + private Map args = new LinkedHashMap<>(); +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/events/EventSender.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/events/EventSender.java new file mode 100644 index 0000000..b5271d1 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/events/EventSender.java @@ -0,0 +1,31 @@ +package com.springboot.cloud.gateway.admin.events; + +import com.springboot.cloud.gateway.admin.config.BusConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +@Slf4j +public class EventSender { + + @Autowired + private RabbitTemplate rabbitTemplate; + + @Autowired + private MessageConverter messageConverter; + + @PostConstruct + public void init() { + rabbitTemplate.setMessageConverter(messageConverter); + } + + public void send(String routingKey, Object object) { + log.info("routingKey:{}=>message:{}", routingKey, object); + rabbitTemplate.convertAndSend(BusConfig.EXCHANGE_NAME, routingKey, object); + } +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/exception/GlobalExceptionHandlerAdvice.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/exception/GlobalExceptionHandlerAdvice.java new file mode 100644 index 0000000..27637f4 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/exception/GlobalExceptionHandlerAdvice.java @@ -0,0 +1,10 @@ +package com.springboot.cloud.gateway.admin.exception; + +import com.springboot.cloud.common.web.exception.DefaultGlobalExceptionHandlerAdvice; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandlerAdvice extends DefaultGlobalExceptionHandlerAdvice { +} \ No newline at end of file diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/rest/GatewayRouteController.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/rest/GatewayRouteController.java new file mode 100644 index 0000000..e1f5726 --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/rest/GatewayRouteController.java @@ -0,0 +1,91 @@ +package com.springboot.cloud.gateway.admin.rest; + +import com.springboot.cloud.common.core.entity.vo.Result; +import com.springboot.cloud.gateway.admin.entity.form.GatewayRouteForm; +import com.springboot.cloud.gateway.admin.entity.form.GatewayRouteQueryForm; +import com.springboot.cloud.gateway.admin.entity.ov.GatewayRouteVo; +import com.springboot.cloud.gateway.admin.entity.param.GatewayRouteQueryParam; +import com.springboot.cloud.gateway.admin.entity.po.GatewayRoute; +import com.springboot.cloud.gateway.admin.service.IGatewayRouteService; +import io.swagger.annotations.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +@RestController +@RequestMapping("/gateway/routes") +@Api("gateway routes") +@Slf4j +public class GatewayRouteController { + + @Autowired + private IGatewayRouteService gatewayRoutService; + + @ApiOperation(value = "新增网关路由", notes = "新增一个网关路由") + @ApiImplicitParam(name = "gatewayRoutForm", value = "新增网关路由form表单", required = true, dataType = "GatewayRouteForm") + @PostMapping + public Result add(@Valid @RequestBody GatewayRouteForm gatewayRoutForm) { + log.info("name:", gatewayRoutForm); + GatewayRoute gatewayRout = gatewayRoutForm.toPo(GatewayRoute.class); + return Result.success(gatewayRoutService.add(gatewayRout)); + } + + @ApiOperation(value = "删除网关路由", notes = "根据url的id来指定删除对象") + @ApiImplicitParam(paramType = "path", name = "id", value = "网关路由ID", required = true, dataType = "string") + @DeleteMapping(value = "/{id}") + public Result delete(@PathVariable String id) { + return Result.success(gatewayRoutService.delete(id)); + } + + @ApiOperation(value = "修改网关路由", notes = "修改指定网关路由信息") + @ApiImplicitParams({ + @ApiImplicitParam(name = "id", value = "网关路由ID", required = true, dataType = "string"), + @ApiImplicitParam(name = "gatewayRoutForm", value = "网关路由实体", required = true, dataType = "GatewayRouteForm") + }) + @PutMapping(value = "/{id}") + public Result update(@PathVariable String id, @Valid @RequestBody GatewayRouteForm gatewayRoutForm) { + GatewayRoute gatewayRout = gatewayRoutForm.toPo(GatewayRoute.class); + gatewayRout.setId(id); + return Result.success(gatewayRoutService.update(gatewayRout)); + } + + @ApiOperation(value = "获取网关路由", notes = "根据id获取指定网关路由信息") + @ApiImplicitParam(paramType = "path", name = "id", value = "网关路由ID", required = true, dataType = "string") + @GetMapping(value = "/{id}") + public Result get(@PathVariable String id) { + log.info("get with id:{}", id); + return Result.success(new GatewayRouteVo(gatewayRoutService.get(id))); + } + + @ApiOperation(value = "根据uri获取网关路由", notes = "根据uri获取网关路由信息,简单查询") + @ApiImplicitParam(paramType = "query", name = "name", value = "网关路由路径", required = true, dataType = "string") + @ApiResponses( + @ApiResponse(code = 200, message = "处理成功", response = Result.class) + ) + @GetMapping + public Result getByUri(@RequestParam String uri) { + return Result.success(gatewayRoutService.query(new GatewayRouteQueryParam(uri)).stream().findFirst()); + } + + @ApiOperation(value = "搜索网关路由", notes = "根据条件查询网关路由信息") + @ApiImplicitParam(name = "gatewayRoutQueryForm", value = "网关路由查询参数", required = true, dataType = "GatewayRouteQueryForm") + @ApiResponses( + @ApiResponse(code = 200, message = "处理成功", response = Result.class) + ) + @PostMapping(value = "/conditions") + public Result search(@Valid @RequestBody GatewayRouteQueryForm gatewayRouteQueryForm) { + return Result.success(gatewayRoutService.query(gatewayRouteQueryForm.toParam(GatewayRouteQueryParam.class))); + } + + @ApiOperation(value = "重载网关路由", notes = "将所以网关的路由全部重载到redis中") + @ApiResponses( + @ApiResponse(code = 200, message = "处理成功", response = Result.class) + ) + @PostMapping(value = "/overload") + public Result overload() { + return Result.success(gatewayRoutService.overload()); + } + +} \ No newline at end of file diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/service/IGatewayRouteService.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/service/IGatewayRouteService.java new file mode 100644 index 0000000..35f490a --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/service/IGatewayRouteService.java @@ -0,0 +1,53 @@ +package com.springboot.cloud.gateway.admin.service; + +import com.springboot.cloud.gateway.admin.entity.ov.GatewayRouteVo; +import com.springboot.cloud.gateway.admin.entity.param.GatewayRouteQueryParam; +import com.springboot.cloud.gateway.admin.entity.po.GatewayRoute; + +import java.util.List; + +public interface IGatewayRouteService { + /** + * 获取网关路由 + * + * @param id + * @return + */ + GatewayRoute get(String id); + + /** + * 新增网关路由 + * + * @param gatewayRoute + * @return + */ + boolean add(GatewayRoute gatewayRoute); + + /** + * 查询网关路由 + * + * @return + */ + List query(GatewayRouteQueryParam gatewayRouteQueryParam); + + /** + * 更新网关路由信息 + * + * @param gatewayRoute + */ + boolean update(GatewayRoute gatewayRoute); + + /** + * 根据id删除网关路由 + * + * @param id + */ + boolean delete(String id); + + /** + * 重新加载网关路由配置到redis + * + * @return 成功返回true + */ + boolean overload(); +} diff --git a/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/service/impl/GatewayRouteService.java b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/service/impl/GatewayRouteService.java new file mode 100644 index 0000000..bfc18dc --- /dev/null +++ b/gateway/gateway-admin/src/main/java/com/springboot/cloud/gateway/admin/service/impl/GatewayRouteService.java @@ -0,0 +1,117 @@ +package com.springboot.cloud.gateway.admin.service.impl; + +import com.alicp.jetcache.Cache; +import com.alicp.jetcache.anno.CacheType; +import com.alicp.jetcache.anno.CreateCache; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.springboot.cloud.gateway.admin.config.BusConfig; +import com.springboot.cloud.gateway.admin.dao.GatewayRouteMapper; +import com.springboot.cloud.gateway.admin.entity.ov.GatewayRouteVo; +import com.springboot.cloud.gateway.admin.entity.param.GatewayRouteQueryParam; +import com.springboot.cloud.gateway.admin.entity.po.GatewayRoute; +import com.springboot.cloud.gateway.admin.events.EventSender; +import com.springboot.cloud.gateway.admin.service.IGatewayRouteService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.filter.FilterDefinition; +import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.net.URI; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class GatewayRouteService extends ServiceImpl implements IGatewayRouteService { + + private static final String GATEWAY_ROUTES = "gateway_routes::"; + + @CreateCache(name = GATEWAY_ROUTES, cacheType = CacheType.REMOTE) + private Cache gatewayRouteCache; + + @Autowired + private EventSender eventSender; + + @Override + public boolean add(GatewayRoute gatewayRoute) { + boolean isSuccess = this.save(gatewayRoute); + // 转化为gateway需要的类型,缓存到redis, 并事件通知各网关应用 + RouteDefinition routeDefinition = gatewayRouteToRouteDefinition(gatewayRoute); + gatewayRouteCache.put(gatewayRoute.getRouteId(), routeDefinition); + eventSender.send(BusConfig.ROUTING_KEY, routeDefinition); + return isSuccess; + } + + @Override + public boolean delete(String id) { + GatewayRoute gatewayRoute = this.getById(id); + // 删除redis缓存, 并事件通知各网关应用 + gatewayRouteCache.remove(gatewayRoute.getRouteId()); + eventSender.send(BusConfig.ROUTING_KEY, gatewayRouteToRouteDefinition(gatewayRoute)); + return this.removeById(id); + } + + @Override + public boolean update(GatewayRoute gatewayRoute) { + boolean isSuccess = this.updateById(gatewayRoute); + // 转化为gateway需要的类型,缓存到redis, 并事件通知各网关应用 + RouteDefinition routeDefinition = gatewayRouteToRouteDefinition(gatewayRoute); + gatewayRouteCache.put(gatewayRoute.getRouteId(), routeDefinition); + eventSender.send(BusConfig.ROUTING_KEY, routeDefinition); + return isSuccess; + } + + /** + * 将数据库中json对象转换为网关需要的RouteDefinition对象 + * + * @param gatewayRoute + * @return RouteDefinition + */ + private RouteDefinition gatewayRouteToRouteDefinition(GatewayRoute gatewayRoute) { + RouteDefinition routeDefinition = new RouteDefinition(); + routeDefinition.setId(gatewayRoute.getRouteId()); + routeDefinition.setOrder(gatewayRoute.getOrders()); + routeDefinition.setUri(URI.create(gatewayRoute.getUri())); + ObjectMapper objectMapper = new ObjectMapper(); + try { + routeDefinition.setFilters(objectMapper.readValue(gatewayRoute.getFilters(), new TypeReference>() { + })); + routeDefinition.setPredicates(objectMapper.readValue(gatewayRoute.getPredicates(), new TypeReference>() { + })); + } catch (IOException e) { + log.error("网关路由对象转换失败", e); + } + return routeDefinition; + } + + @Override + public GatewayRoute get(String id) { + return this.getById(id); + } + + @Override + public List query(GatewayRouteQueryParam gatewayRouteQueryParam) { + QueryWrapper queryWrapper = gatewayRouteQueryParam.build(); + queryWrapper.eq(StringUtils.isNotBlank(gatewayRouteQueryParam.getUri()), "uri", gatewayRouteQueryParam.getUri()); + return this.list(queryWrapper).stream().map(GatewayRouteVo::new).collect(Collectors.toList()); + } + + @Override + @PostConstruct + public boolean overload() { + List gatewayRoutes = this.list(new QueryWrapper<>()); + gatewayRoutes.forEach(gatewayRoute -> + gatewayRouteCache.put(gatewayRoute.getRouteId(), gatewayRouteToRouteDefinition(gatewayRoute)) + ); + log.info("全局初使化网关路由成功!"); + return true; + } +} diff --git a/gateway/gateway-admin/src/test/java/com/springboot/cloud/gateway/admin/GatewayAdminApplicationTests.java b/gateway/gateway-admin/src/test/java/com/springboot/cloud/gateway/admin/GatewayAdminApplicationTests.java new file mode 100644 index 0000000..c82cb51 --- /dev/null +++ b/gateway/gateway-admin/src/test/java/com/springboot/cloud/gateway/admin/GatewayAdminApplicationTests.java @@ -0,0 +1,16 @@ +package com.springboot.cloud.gateway.admin; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class GatewayAdminApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/gateway/gateway-web/.gitignore b/gateway/gateway-web/.gitignore new file mode 100644 index 0000000..82eca33 --- /dev/null +++ b/gateway/gateway-web/.gitignore @@ -0,0 +1,25 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/gateway/gateway-web/pom.xml b/gateway/gateway-web/pom.xml new file mode 100644 index 0000000..baaf78b --- /dev/null +++ b/gateway/gateway-web/pom.xml @@ -0,0 +1,79 @@ + + + 4.0.0 + + business.chaoran + gateway-web + 0.0.1-SNAPSHOT + jar + + gateway-web + Demo Gateway Api project for Spring Boot + + + business.chaoran + gateway + 0.0.1-SNAPSHOT + + + + + + business.chaoran + core + 0.0.1-SNAPSHOT + + + + org.springframework.cloud + spring-cloud-starter-gateway + + + + org.springframework.boot + spring-boot-starter-data-redis-reactive + + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + io.springfox + springfox-swagger2 + 2.9.2 + + + + business.chaoran + authentication-client + 0.0.1-SNAPSHOT + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.1.4.RELEASE + + + + build-info + repackage + + + + + + gateway-web + + diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/GatewayApplication.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/GatewayApplication.java new file mode 100644 index 0000000..f1bde13 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/GatewayApplication.java @@ -0,0 +1,23 @@ +package com.springboot.cloud.gateway; + +import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation; +import com.alicp.jetcache.anno.config.EnableMethodCache; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; + +@SpringBootApplication +@EnableDiscoveryClient +@EnableFeignClients(basePackages = "com.springboot.cloud.auth.client") +@EnableCircuitBreaker +@EnableMethodCache(basePackages = "com.springboot.cloud") +@EnableCreateCacheAnnotation +public class GatewayApplication { + public static void main(String[] args) { + SpringApplication.run(GatewayApplication.class, args); + } +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/BusConfig.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/BusConfig.java new file mode 100644 index 0000000..e94b91a --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/BusConfig.java @@ -0,0 +1,69 @@ +package com.springboot.cloud.gateway.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.springboot.cloud.gateway.events.BusReceiver; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.*; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; +import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Slf4j +public class BusConfig { + + private static final String EXCHANGE_NAME = "spring-boot-exchange"; + private static final String ROUTING_KEY = "gateway-route"; + + @Value("${spring.application.name}") + private String appName; + + @Bean + Queue queue() { + String queueName = new Base64UrlNamingStrategy(appName + ".").generateName(); + log.info("queue name:{}", queueName); + return new Queue(queueName, false); + } + + @Bean + TopicExchange exchange() { + log.info("exchange:{}", EXCHANGE_NAME); + return new TopicExchange(EXCHANGE_NAME); + } + + @Bean + Binding binding(Queue queue, TopicExchange exchange) { + log.info("binding {} to {} with {}", queue, exchange, ROUTING_KEY); + return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY); + } + + @Bean + SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory, MessageListenerAdapter messageListenerAdapter, Queue queue) { + log.info("init simpleMessageListenerContainer: {}", queue.getName()); + SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); + container.setQueueNames(queue.getName()); + container.setMessageListener(messageListenerAdapter); + return container; + } + + @Bean + MessageListenerAdapter messageListenerAdapter(BusReceiver busReceiver, MessageConverter messageConverter) { + log.info("new listener"); + return new MessageListenerAdapter(busReceiver, messageConverter); + } + + @Bean + public MessageConverter messageConverter() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + return new ContentTypeDelegatingMessageConverter(new Jackson2JsonMessageConverter(objectMapper)); + } +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/DefaultRedisRateLimiter.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/DefaultRedisRateLimiter.java new file mode 100644 index 0000000..8f086a4 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/DefaultRedisRateLimiter.java @@ -0,0 +1,32 @@ +package com.springboot.cloud.gateway.config; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.ReactiveRedisTemplate; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.validation.Validator; +import reactor.core.publisher.Mono; + +import java.util.List; + +@Configuration +public class DefaultRedisRateLimiter extends RedisRateLimiter { + + Config getDefaultConfig() { + return super.getConfig().get("defaultFilters"); + } + + public DefaultRedisRateLimiter(ReactiveRedisTemplate redisTemplate, + RedisScript> script, + @Qualifier("defaultValidator") Validator validator) { + super(redisTemplate, script, validator); + } + + @Override + public Mono isAllowed(String routeId, String id) { + if (null == super.getConfig().get(routeId)) + getConfig().put(routeId, getDefaultConfig()); + return super.isAllowed(routeId, id); + } +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/RequestRateLimiterConfig.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/RequestRateLimiterConfig.java new file mode 100644 index 0000000..e155632 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/RequestRateLimiterConfig.java @@ -0,0 +1,46 @@ +package com.springboot.cloud.gateway.config; + +import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; + +/** + * 自定义限流标志的key,多个维度可以从这里入手 + * exchange对象中获取服务ID、请求信息,用户信息等 + */ +@Component +public class RequestRateLimiterConfig { + + /** + * ip地址限流 + * + * @return 限流key + */ + @Bean + @Primary + public KeyResolver remoteAddressKeyResolver() { + return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); + } + + /** + * 请求路径限流 + * + * @return 限流key + */ + @Bean + public KeyResolver apiKeyResolver() { + return exchange -> Mono.just(exchange.getRequest().getPath().value()); + } + + /** + * username限流 + * + * @return 限流key + */ + @Bean + public KeyResolver userKeyResolver() { + return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username")); + } +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/SwaggerHandler.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/SwaggerHandler.java new file mode 100644 index 0000000..5a41835 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/SwaggerHandler.java @@ -0,0 +1,48 @@ +package com.springboot.cloud.gateway.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; +import springfox.documentation.swagger.web.*; + +import java.util.Optional; + +@RestController +@RequestMapping("/swagger-resources") +public class SwaggerHandler { + + @Autowired(required = false) + private SecurityConfiguration securityConfiguration; + + @Autowired(required = false) + private UiConfiguration uiConfiguration; + + private final SwaggerResourcesProvider swaggerResources; + + @Autowired + public SwaggerHandler(SwaggerResourcesProvider swaggerResources) { + this.swaggerResources = swaggerResources; + } + + + @GetMapping("/configuration/security") + public Mono> securityConfiguration() { + return Mono.just(new ResponseEntity<>( + Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK)); + } + + @GetMapping("/configuration/ui") + public Mono> uiConfiguration() { + return Mono.just(new ResponseEntity<>( + Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); + } + + @GetMapping("") + public Mono swaggerResources() { + return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); + } +} \ No newline at end of file diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/SwaggerProvider.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/SwaggerProvider.java new file mode 100644 index 0000000..14e1b7d --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/config/SwaggerProvider.java @@ -0,0 +1,45 @@ +package com.springboot.cloud.gateway.config; + +import com.springboot.cloud.gateway.service.RouteService; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; +import springfox.documentation.swagger.web.SwaggerResource; +import springfox.documentation.swagger.web.SwaggerResourcesProvider; + +import java.util.ArrayList; +import java.util.List; + +@Component +@Primary +@AllArgsConstructor +@Slf4j +public class SwaggerProvider implements SwaggerResourcesProvider { + public static final String API_URI = "/v2/api-docs"; + + @Autowired + private final RouteService routeService; + + @Override + public List get() { + List resources = new ArrayList<>(); + routeService.getRouteDefinitions().stream() + .forEach(routeDefinition -> routeDefinition.getPredicates().stream() + .filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName())) + .peek(predicateDefinition -> log.debug("路由配置参数:{}", predicateDefinition.getArgs())) + .forEach(predicateDefinition -> resources.add(swaggerResource(routeDefinition.getId(), + predicateDefinition.getArgs().get("pattern").replace("/**", API_URI))))); + log.debug("resources:{}", resources); + return resources; + } + + private SwaggerResource swaggerResource(String name, String location) { + SwaggerResource swaggerResource = new SwaggerResource(); + swaggerResource.setName(name); + swaggerResource.setSwaggerVersion("2.0"); + swaggerResource.setUrl(location); + return swaggerResource; + } +} \ No newline at end of file diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/events/BusReceiver.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/events/BusReceiver.java new file mode 100644 index 0000000..cc4cc2a --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/events/BusReceiver.java @@ -0,0 +1,22 @@ +package com.springboot.cloud.gateway.events; + +import com.springboot.cloud.gateway.service.RouteService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.stereotype.Component; + + +//TODO 待实现删除,更新操作 +@Component +@Slf4j +public class BusReceiver { + + @Autowired + private RouteService routeService; + + public void handleMessage(RouteDefinition routeDefinition) { + log.info("Received Message:<{}>", routeDefinition); + routeService.save(routeDefinition); + } +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/exception/CustomErrorWebExceptionHandler.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/exception/CustomErrorWebExceptionHandler.java new file mode 100644 index 0000000..faa67a7 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/exception/CustomErrorWebExceptionHandler.java @@ -0,0 +1,52 @@ +package com.springboot.cloud.gateway.exception; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.web.ErrorProperties; +import org.springframework.boot.autoconfigure.web.ResourceProperties; +import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler; +import org.springframework.boot.web.reactive.error.ErrorAttributes; +import org.springframework.context.ApplicationContext; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.*; +import reactor.core.publisher.Mono; + +import java.util.Map; + +@Slf4j +public class CustomErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler { + + @Autowired + private GateWayExceptionHandlerAdvice gateWayExceptionHandlerAdvice; + + /** + * Create a new {@code DefaultErrorWebExceptionHandler} instance. + * + * @param errorAttributes the error attributes + * @param resourceProperties the resources configuration properties + * @param errorProperties the error configuration properties + * @param applicationContext the current application context + */ + public CustomErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, + ErrorProperties errorProperties, ApplicationContext applicationContext) { + super(errorAttributes, resourceProperties, errorProperties, applicationContext); + } + + @Override + protected RouterFunction getRoutingFunction(ErrorAttributes errorAttributes) { + return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse); + } + + @Override + protected Mono renderErrorResponse(ServerRequest request) { + Map error = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); + HttpStatus errorStatus = getHttpStatus(error); + Throwable throwable = getError(request); + return ServerResponse.status(errorStatus) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .body(BodyInserters.fromObject(gateWayExceptionHandlerAdvice.handle(throwable))); + //.doOnNext((resp) -> logError(request, errorStatus)); + } +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/exception/ExceptionAutoConfiguration.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/exception/ExceptionAutoConfiguration.java new file mode 100644 index 0000000..d8a27d4 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/exception/ExceptionAutoConfiguration.java @@ -0,0 +1,64 @@ +package com.springboot.cloud.gateway.exception; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.web.ResourceProperties; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration; +import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.reactive.error.ErrorAttributes; +import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.web.reactive.config.WebFluxConfigurer; +import org.springframework.web.reactive.result.view.ViewResolver; + +import java.util.Collections; +import java.util.List; + +@Configuration +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) +@ConditionalOnClass(WebFluxConfigurer.class) +@AutoConfigureBefore(WebFluxAutoConfiguration.class) +@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class}) +public class ExceptionAutoConfiguration { + + private ServerProperties serverProperties; + + private ApplicationContext applicationContext; + + private ResourceProperties resourceProperties; + + private List viewResolvers; + + private ServerCodecConfigurer serverCodecConfigurer; + + public ExceptionAutoConfiguration(ServerProperties serverProperties, + ResourceProperties resourceProperties, + ObjectProvider> viewResolversProvider, + ServerCodecConfigurer serverCodecConfigurer, + ApplicationContext applicationContext) { + this.serverProperties = serverProperties; + this.applicationContext = applicationContext; + this.resourceProperties = resourceProperties; + this.viewResolvers = viewResolversProvider + .getIfAvailable(() -> Collections.emptyList()); + this.serverCodecConfigurer = serverCodecConfigurer; + } + + @Bean + public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) { + DefaultErrorWebExceptionHandler exceptionHandler = new CustomErrorWebExceptionHandler( + errorAttributes, this.resourceProperties, + this.serverProperties.getError(), this.applicationContext); + exceptionHandler.setViewResolvers(this.viewResolvers); + exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters()); + exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders()); + return exceptionHandler; + } +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/exception/GateWayExceptionHandlerAdvice.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/exception/GateWayExceptionHandlerAdvice.java new file mode 100644 index 0000000..f49a550 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/exception/GateWayExceptionHandlerAdvice.java @@ -0,0 +1,92 @@ +package com.springboot.cloud.gateway.exception; + +import com.springboot.cloud.common.core.entity.vo.Result; +import com.springboot.cloud.common.core.exception.SystemErrorType; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.SignatureException; +import io.netty.channel.ConnectTimeoutException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.support.NotFoundException; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.server.ResponseStatusException; + +@Slf4j +@Component +public class GateWayExceptionHandlerAdvice { + + @ExceptionHandler(value = {ResponseStatusException.class}) + public Result handle(ResponseStatusException ex) { + log.error("response status exception:{}", ex.getMessage()); + return Result.fail(SystemErrorType.GATEWAY_ERROR); + } + + @ExceptionHandler(value = {ConnectTimeoutException.class}) + public Result handle(ConnectTimeoutException ex) { + log.error("connect timeout exception:{}", ex.getMessage()); + return Result.fail(SystemErrorType.GATEWAY_CONNECT_TIME_OUT); + } + + @ExceptionHandler(value = {NotFoundException.class}) + @ResponseStatus(HttpStatus.NOT_FOUND) + public Result handle(NotFoundException ex) { + log.error("not found exception:{}", ex.getMessage()); + return Result.fail(SystemErrorType.GATEWAY_NOT_FOUND_SERVICE); + } + + @ExceptionHandler(value = {ExpiredJwtException.class}) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Result handle(ExpiredJwtException ex) { + log.error("ExpiredJwtException:{}", ex.getMessage()); + return Result.fail(SystemErrorType.INVALID_TOKEN); + } + + @ExceptionHandler(value = {SignatureException.class}) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Result handle(SignatureException ex) { + log.error("SignatureException:{}", ex.getMessage()); + return Result.fail(SystemErrorType.INVALID_TOKEN); + } + + @ExceptionHandler(value = {MalformedJwtException.class}) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Result handle(MalformedJwtException ex) { + log.error("MalformedJwtException:{}", ex.getMessage()); + return Result.fail(SystemErrorType.INVALID_TOKEN); + } + + @ExceptionHandler(value = {RuntimeException.class}) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handle(RuntimeException ex) { + log.error("runtime exception:{}", ex.getMessage()); + return Result.fail(); + } + + @ExceptionHandler(value = {Exception.class}) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handle(Exception ex) { + log.error("exception:{}", ex.getMessage()); + return Result.fail(); + } + + @ExceptionHandler(value = {Throwable.class}) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handle(Throwable throwable) { + Result result = Result.fail(); + if (throwable instanceof ResponseStatusException) { + result = handle((ResponseStatusException) throwable); + } else if (throwable instanceof ConnectTimeoutException) { + result = handle((ConnectTimeoutException) throwable); + } else if (throwable instanceof NotFoundException) { + result = handle((NotFoundException) throwable); + } else if (throwable instanceof RuntimeException) { + result = handle((RuntimeException) throwable); + } else if (throwable instanceof Exception) { + result = handle((Exception) throwable); + } + return result; + } +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/filter/AccessGatewayFilter.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/filter/AccessGatewayFilter.java new file mode 100644 index 0000000..ff4cfd8 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/filter/AccessGatewayFilter.java @@ -0,0 +1,110 @@ +package com.springboot.cloud.gateway.filter; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.springboot.cloud.auth.client.service.IAuthService; +import com.springboot.cloud.gateway.service.PermissionService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.util.DigestUtils; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Optional; + +/** + * 请求url权限校验 + */ +@Configuration +@ComponentScan(basePackages = "com.springboot.cloud.auth.client") +@Slf4j +public class AccessGatewayFilter implements GlobalFilter { + + private static final String X_CLIENT_TOKEN_USER = "x-client-token-user"; + private static final String X_CLIENT_TOKEN = "x-client-token"; + private static final String X_CLIENT_SECRET = "gateway-web"; + private static final String USER_CURRENT_COMPANY="company"; + + /** + * 由authentication-client模块提供签权的feign客户端 + */ + @Autowired + private IAuthService authService; + + @Autowired + private PermissionService permissionService; + + /** + * 1.首先网关检查token是否有效,无效直接返回401,不调用签权服务 + * 2.调用签权服务器看是否对该请求有权限,有权限进入下一个filter,没有权限返回401 + * + * @param exchange + * @param chain + * @return + */ + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + ServerHttpRequest request = exchange.getRequest(); + String authentication = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION); + String url = request.getPath().value(); + String method = request.getMethod().name(); + //后端识别companyId + String companyId = Optional.ofNullable(request.getQueryParams().toSingleValueMap().get("companyId")).orElseGet(String::new); + log.debug("url:{},headers:{}", url, request.getHeaders()); + //不需要网关签权的url + if (authService.ignoreAuthentication(url)) { + return chain.filter(exchange); + } + //调用签权服务看用户是否有权限,若有权限进入下一个filter + if (permissionService.permission(companyId, authentication, url)) { + //设置服务间调用请求头 + ServerHttpRequest.Builder builder = request.mutate(); + String originStr = new StringBuilder().append(url).append(method).append(X_CLIENT_TOKEN).append(X_CLIENT_SECRET).toString(); + String md5Secret = DigestUtils.md5DigestAsHex(originStr.getBytes()); + builder.header(X_CLIENT_TOKEN, md5Secret); + builder.header(USER_CURRENT_COMPANY,companyId); + //将jwt token中的用户信息传给服务 + builder.header(X_CLIENT_TOKEN_USER, getUserToken(authentication)); + return chain.filter(exchange.mutate().request(builder.build()).build()); + } + return unauthorized(exchange); + } + + /** + * 提取jwt token中的数据,转为json + * + * @param authentication + * @return + */ + private String getUserToken(String authentication) { + String token = "{}"; + try { + token = new ObjectMapper().writeValueAsString(authService.getJwt(authentication).getBody()); + return token; + } catch (JsonProcessingException e) { + log.error("token json error:{}", e.getMessage()); + } + return token; + } + + /** + * 网关拒绝,返回401 + * + * @param + */ + private Mono unauthorized(ServerWebExchange serverWebExchange) { + serverWebExchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); + DataBuffer buffer = serverWebExchange.getResponse() + .bufferFactory().wrap(HttpStatus.UNAUTHORIZED.getReasonPhrase().getBytes()); + return serverWebExchange.getResponse().writeWith(Flux.just(buffer)); + } +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/filter/SwaggerHeaderFilter.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/filter/SwaggerHeaderFilter.java new file mode 100644 index 0000000..5913706 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/filter/SwaggerHeaderFilter.java @@ -0,0 +1,37 @@ +package com.springboot.cloud.gateway.filter; + +import com.springboot.cloud.gateway.config.SwaggerProvider; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +//@Component +@Slf4j +public class SwaggerHeaderFilter implements GlobalFilter, Ordered { + + private static final String HEADER_NAME = "X-Forwarded-Prefix"; + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + ServerHttpRequest request = exchange.getRequest(); + String path = request.getURI().getPath(); + if (!StringUtils.endsWithIgnoreCase(path, SwaggerProvider.API_URI)) { + return chain.filter(exchange); + } + String basePath = path.substring(0, path.lastIndexOf(SwaggerProvider.API_URI)); + log.info("basePath: {}", basePath); + ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build(); + ServerWebExchange newExchange = exchange.mutate().request(newRequest).build(); + return chain.filter(newExchange); + } + + @Override + public int getOrder() { + return -200; + } +} \ No newline at end of file diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/routes/RedisRouteDefinitionRepository.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/routes/RedisRouteDefinitionRepository.java new file mode 100644 index 0000000..a8e1239 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/routes/RedisRouteDefinitionRepository.java @@ -0,0 +1,39 @@ +package com.springboot.cloud.gateway.routes; + +import com.springboot.cloud.gateway.service.RouteService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.cloud.gateway.route.RouteDefinitionRepository; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Component +@Slf4j +public class RedisRouteDefinitionRepository implements RouteDefinitionRepository { + + @Autowired + private RouteService routeService; + + @Override + public Flux getRouteDefinitions() { + return Flux.fromIterable(routeService.getRouteDefinitions()); + } + + @Override + public Mono save(Mono route) { + return route.flatMap(routeDefinition -> { + routeService.save(routeDefinition); + return Mono.empty(); + }); + } + + @Override + public Mono delete(Mono routeId) { + return routeId.flatMap(id -> { + routeService.delete(id); + return Mono.empty(); + }); + } +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/PermissionService.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/PermissionService.java new file mode 100644 index 0000000..f401d52 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/PermissionService.java @@ -0,0 +1,12 @@ +package com.springboot.cloud.gateway.service; + +public interface PermissionService { + /** + * + * @param companyId + * @param authentication + * @param url + * @return + */ + boolean permission(String companyId,String authentication, String url); +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/RouteService.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/RouteService.java new file mode 100644 index 0000000..b1c308b --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/RouteService.java @@ -0,0 +1,13 @@ +package com.springboot.cloud.gateway.service; + +import org.springframework.cloud.gateway.route.RouteDefinition; + +import java.util.Collection; + +public interface RouteService { + Collection getRouteDefinitions(); + + boolean save(RouteDefinition routeDefinition); + + boolean delete(String routeId); +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/impl/PermissionServiceImpl.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/impl/PermissionServiceImpl.java new file mode 100644 index 0000000..988d247 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/impl/PermissionServiceImpl.java @@ -0,0 +1,21 @@ +package com.springboot.cloud.gateway.service.impl; + +import com.springboot.cloud.auth.client.service.IAuthService; +import com.springboot.cloud.gateway.service.PermissionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class PermissionServiceImpl implements PermissionService { + + /** + * 由authentication-client模块提供签权的feign客户端 + */ + @Autowired + private IAuthService authService; + + @Override + public boolean permission(String companyId, String authentication, String url) { + return authService.hasPermission(companyId,authentication, url); + } +} diff --git a/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/impl/RouteServiceImpl.java b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/impl/RouteServiceImpl.java new file mode 100644 index 0000000..4213327 --- /dev/null +++ b/gateway/gateway-web/src/main/java/com/springboot/cloud/gateway/service/impl/RouteServiceImpl.java @@ -0,0 +1,82 @@ +package com.springboot.cloud.gateway.service.impl; + +import com.alicp.jetcache.Cache; +import com.alicp.jetcache.anno.CacheType; +import com.alicp.jetcache.anno.CreateCache; +import com.springboot.cloud.gateway.service.RouteService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.annotation.PostConstruct; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class RouteServiceImpl implements RouteService { + + private static final String GATEWAY_ROUTES = "gateway_routes::"; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @CreateCache(name = GATEWAY_ROUTES, cacheType = CacheType.REMOTE) + private Cache gatewayRouteCache; + + private Map routeDefinitionMaps = new HashMap<>(); + + @PostConstruct + private void loadRouteDefinition() { + log.info("loadRouteDefinition, 开始初使化路由"); + Set gatewayKeys = stringRedisTemplate.keys(GATEWAY_ROUTES + "*"); + if (CollectionUtils.isEmpty(gatewayKeys)) { + return; + } + log.info("预计初使化路由, gatewayKeys:{}", gatewayKeys); + // 去掉key的前缀 + Set gatewayKeyIds = gatewayKeys.stream().map(key -> { + return key.replace(GATEWAY_ROUTES, StringUtils.EMPTY); + }).collect(Collectors.toSet()); + Map allRoutes = gatewayRouteCache.getAll(gatewayKeyIds); + log.info("gatewayKeys:{}", allRoutes); + // 以下代码原因是,jetcache将RouteDefinition返序列化后,uri发生变化,未初使化,导致路由异常,以下代码是重新初使化uri + allRoutes.values().forEach(routeDefinition -> { + try { + routeDefinition.setUri(new URI(routeDefinition.getUri().toASCIIString())); + } catch (URISyntaxException e) { + log.error("网关加载RouteDefinition异常:", e); + } + }); + routeDefinitionMaps.putAll(allRoutes); + log.info("共初使化路由信息:{}", routeDefinitionMaps.size()); + } + + @Override + public Collection getRouteDefinitions() { + return routeDefinitionMaps.values(); + } + + @Override + public boolean save(RouteDefinition routeDefinition) { + routeDefinitionMaps.put(routeDefinition.getId(), routeDefinition); + log.info("新增路由1条:{},目前路由共{}条", routeDefinition, routeDefinitionMaps.size()); + return true; + } + + @Override + public boolean delete(String routeId) { + routeDefinitionMaps.remove(routeId); + log.info("删除路由1条:{},目前路由共{}条", routeId, routeDefinitionMaps.size()); + return true; + } +} diff --git a/gateway/gateway-web/src/test/java/com/springboot/cloud/gateway/GatewayApplicationTests.java b/gateway/gateway-web/src/test/java/com/springboot/cloud/gateway/GatewayApplicationTests.java new file mode 100644 index 0000000..2f351f2 --- /dev/null +++ b/gateway/gateway-web/src/test/java/com/springboot/cloud/gateway/GatewayApplicationTests.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.gateway; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class GatewayApplicationTests { + + @Test + public void contextLoads() { + + } +} diff --git a/gateway/pom.xml b/gateway/pom.xml new file mode 100644 index 0000000..3c1ea41 --- /dev/null +++ b/gateway/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + + business.chaoran + xin-cloud + 1.0-SNAPSHOT + + + business.chaoran + gateway + 0.0.1-SNAPSHOT + pom + + gateway + Demo Gateway project for Spring Cloud + + + gateway-web + gateway-admin + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + com.alicp.jetcache + jetcache-starter-redis + 2.5.14 + + + org.apache.commons + commons-pool2 + 2.6.0 + + + diff --git a/monitor/admin/.gitignore b/monitor/admin/.gitignore new file mode 100644 index 0000000..3a05198 --- /dev/null +++ b/monitor/admin/.gitignore @@ -0,0 +1,16 @@ +target/ +logs/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr diff --git a/monitor/admin/pom.xml b/monitor/admin/pom.xml new file mode 100644 index 0000000..ed49693 --- /dev/null +++ b/monitor/admin/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + business.chaoran + admin + 0.0.1-SNAPSHOT + jar + + admin + Demo project for Spring Cloud Admin + + + business.chaoran + monitor + 0.0.1-SNAPSHOT + + + + 2.1.6 + + + + + de.codecentric + spring-boot-admin-starter-server + ${admin-server.version} + + + org.springframework.boot + spring-boot-starter-security + + + diff --git a/monitor/admin/src/main/java/com/springboot/admin/AdminApplication.java b/monitor/admin/src/main/java/com/springboot/admin/AdminApplication.java new file mode 100644 index 0000000..75958a3 --- /dev/null +++ b/monitor/admin/src/main/java/com/springboot/admin/AdminApplication.java @@ -0,0 +1,15 @@ +package com.springboot.admin; + +import de.codecentric.boot.admin.server.config.EnableAdminServer; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +@SpringBootApplication +@EnableDiscoveryClient +@EnableAdminServer +public class AdminApplication { + public static void main(String[] args) { + SpringApplication.run(AdminApplication.class, args); + } +} diff --git a/monitor/admin/src/main/java/com/springboot/admin/SecurityConfig.java b/monitor/admin/src/main/java/com/springboot/admin/SecurityConfig.java new file mode 100644 index 0000000..de63a79 --- /dev/null +++ b/monitor/admin/src/main/java/com/springboot/admin/SecurityConfig.java @@ -0,0 +1,37 @@ +package com.springboot.admin; + +import de.codecentric.boot.admin.server.config.AdminServerProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; + +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + private final String adminContextPath; + + public SecurityConfig(AdminServerProperties adminServerProperties) { + this.adminContextPath = adminServerProperties.getContextPath(); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); + successHandler.setTargetUrlParameter("redirectTo"); + + http.authorizeRequests() + .antMatchers(adminContextPath + "/assets/**").permitAll() + .antMatchers(adminContextPath + "/actuator/**").permitAll() + .antMatchers(adminContextPath + "/login").permitAll() + .anyRequest().authenticated() + .and() + .formLogin().loginPage(adminContextPath + "/login") + .successHandler(successHandler).and() + .logout().logoutUrl(adminContextPath + "/logout") + .and() + .httpBasic().and() + .csrf().disable(); + // @formatter:on + } +} \ No newline at end of file diff --git a/monitor/admin/src/test/java/com/springboot/admin/ConsumerApplicationTests.java b/monitor/admin/src/test/java/com/springboot/admin/ConsumerApplicationTests.java new file mode 100644 index 0000000..d6647d0 --- /dev/null +++ b/monitor/admin/src/test/java/com/springboot/admin/ConsumerApplicationTests.java @@ -0,0 +1,16 @@ +package com.springboot.admin; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class ConsumerApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/monitor/pom.xml b/monitor/pom.xml new file mode 100644 index 0000000..0e29eff --- /dev/null +++ b/monitor/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + business.chaoran + monitor + 0.0.1-SNAPSHOT + pom + + monitor + Demo Monitor project for Spring Boot + + + business.chaoran + xin-cloud + 1.0-SNAPSHOT + + + + admin + + + + + org.springframework.boot + spring-boot-starter-web + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..3e87ba0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,144 @@ + + + 4.0.0 + + business.chaoran + xin-cloud + 1.0-SNAPSHOT + pom + + cloud + + auth + common + gateway + monitor + sysadmin + webapps + + + + + + + + org.springframework.boot + spring-boot-dependencies + 2.1.10.RELEASE + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + Greenwich.RELEASE + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + 2.1.0.RELEASE + pom + import + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + + com.alicp.jetcache + jetcache-starter-redis + 2.5.14 + + + + + + UTF-8 + UTF-8 + 1.8 + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + com.alibaba.cloud + spring-cloud-alibaba-nacos-discovery + + + + com.alibaba.cloud + spring-cloud-alibaba-nacos-config + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + + + + org.springframework.cloud + spring-cloud-starter-zipkin + + + + org.springframework.cloud + spring-cloud-starter-bus-amqp + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + org.projectlombok + lombok + 1.18.10 + compile + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.1.4.RELEASE + + + + build-info + repackage + + + + + + + diff --git a/sysadmin/organization/pom.xml b/sysadmin/organization/pom.xml new file mode 100644 index 0000000..20a7cb2 --- /dev/null +++ b/sysadmin/organization/pom.xml @@ -0,0 +1,85 @@ + + + 4.0.0 + + organization + 0.0.1-SNAPSHOT + war + + + organization + Demo Organization project for Spring Boot + + + sysadmin + business.chaoran + 0.0.1-SNAPSHOT + + + + + com.alicp.jetcache + jetcache-starter-redis + 2.5.14 + + + org.springframework.cloud + spring-cloud-gateway-core + compile + + + + + org.slf4j + slf4j-simple + compile + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + org.springframework.boot + spring-boot-starter-logging + + + + + javax.servlet + javax.servlet-api + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.1.4.RELEASE + + + + build-info + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.0.0 + + + organization + + diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/OrganizationApplication.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/OrganizationApplication.java new file mode 100644 index 0000000..e4b93cf --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/OrganizationApplication.java @@ -0,0 +1,27 @@ +package com.springboot.cloud.sysadmin.organization; + +import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation; +import com.alicp.jetcache.anno.config.EnableMethodCache; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration; + +@SpringBootApplication(exclude = GatewayClassPathWarningAutoConfiguration.class) +@EnableDiscoveryClient +@EnableCircuitBreaker +@EnableMethodCache(basePackages = "com.springboot.cloud") +@EnableCreateCacheAnnotation +public class OrganizationApplication extends SpringBootServletInitializer { + public static void main(String[] args) { + SpringApplication.run(OrganizationApplication.class, args); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { + return builder.sources(OrganizationApplication.class); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/BusConfig.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/BusConfig.java new file mode 100644 index 0000000..2f1df72 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/BusConfig.java @@ -0,0 +1,76 @@ +package com.springboot.cloud.sysadmin.organization.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.Binding; +import org.springframework.amqp.core.BindingBuilder; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.core.TopicExchange; +import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 消息设置 + * 监听 company_application_popedom表的操作 + */ +@Configuration +@Slf4j +public class BusConfig { + + public static final String QUEUE_NAME = "event-organization"; + public static final String EXCHANGE_NAME = "spring-boot-exchange"; + public static final String ROUTING_KEY = "organization-popedom"; + + /** + * 设置消息队列 + * + * @return + */ + @Bean + Queue queue() { + log.info("queue name:{}", QUEUE_NAME); + return new Queue(QUEUE_NAME, false); + } + + /** + * 设置主题交换机 + * + * @return + */ + @Bean + TopicExchange exchange() { + log.info("exchange:{}", EXCHANGE_NAME); + return new TopicExchange(EXCHANGE_NAME); + } + + /** + * 绑定队列到主题交换机,并设置关联键 + * + * @param queue + * @param exchange + * @return + */ + @Bean + Binding binding(Queue queue, TopicExchange exchange) { + log.info("binding {} to {} with {}", queue, exchange, ROUTING_KEY); + return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY); + } + + /** + * 设置消息体用jackson序列化 + * + * @return + */ + @Bean + public MessageConverter messageConverter() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + return new ContentTypeDelegatingMessageConverter(new Jackson2JsonMessageConverter(objectMapper)); + } + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/MyMetaObjectHandler.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/MyMetaObjectHandler.java new file mode 100644 index 0000000..83b2619 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/MyMetaObjectHandler.java @@ -0,0 +1,9 @@ +package com.springboot.cloud.sysadmin.organization.config; + +import com.springboot.cloud.common.web.handler.PoMetaObjectHandler; +import org.springframework.stereotype.Component; + +@Component +public class MyMetaObjectHandler extends PoMetaObjectHandler { + +} \ No newline at end of file diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/MyRedisConfig.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/MyRedisConfig.java new file mode 100644 index 0000000..97f2529 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/MyRedisConfig.java @@ -0,0 +1,11 @@ +package com.springboot.cloud.sysadmin.organization.config; + +import com.springboot.cloud.common.web.redis.RedisConfig; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableCaching +public class MyRedisConfig extends RedisConfig { + +} \ No newline at end of file diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/MybatisConfig.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/MybatisConfig.java new file mode 100644 index 0000000..ce05428 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/MybatisConfig.java @@ -0,0 +1,29 @@ +package com.springboot.cloud.sysadmin.organization.config; + +import com.baomidou.mybatisplus.core.injector.ISqlInjector; +import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector; +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + + +@EnableTransactionManagement +@Configuration +public class MybatisConfig { + /** + * 初使化Mybatis审计字段自动赋值的interceptor + */ + @Bean + public ISqlInjector sqlInjector() { + return new LogicSqlInjector(); + } + + /** + * 分页插件 + */ + @Bean + public PaginationInterceptor paginationInterceptor() { + return new PaginationInterceptor(); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/NacosRegisterConfig.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/NacosRegisterConfig.java new file mode 100644 index 0000000..0b4e243 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/NacosRegisterConfig.java @@ -0,0 +1,56 @@ +package com.springboot.cloud.sysadmin.organization.config; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-24 FXY Created + ********************************************** + */ + +import com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.annotation.Configuration; + +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.Query; +import java.lang.management.ManagementFactory; +import java.util.Set; + +@Configuration +@Slf4j +public class NacosRegisterConfig implements ApplicationRunner { + + @Autowired(required = false) + private NacosAutoServiceRegistration registration; + + private Integer port; + + public NacosRegisterConfig() { + try { + this.port = Integer.parseInt(getTomcatPort()); + } catch (Exception e) { + log.error("获取tomcat端口出错了,原因:{}", e.toString()); + } + } + + @Override + public void run(ApplicationArguments args) { + if (registration != null && port != null) { + registration.setPort(port); + registration.start(); + } + } + + //获取tomcat端口 + private String getTomcatPort() throws Exception { + MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer(); + Set objectNames = beanServer.queryNames(new ObjectName("*:type=Connector,*"), Query.match(Query.attr("protocol"), Query.value("HTTP/1.1"))); + String port = objectNames.iterator().next().getKeyProperty("port"); + return port; + } + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/SwaggerConfig.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/SwaggerConfig.java new file mode 100644 index 0000000..20f19d4 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/SwaggerConfig.java @@ -0,0 +1,35 @@ +package com.springboot.cloud.sysadmin.organization.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + @Bean + public Docket createRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.springboot.cloud.sysadmin.organization")) + .paths(PathSelectors.any()) + .build(); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("系统管理API") + .description("系统管理,组织人员管理、角色权限管理、岗位管理") + .termsOfServiceUrl("https://github.com/zhoutaoo/SpringCloud") + .version("2.0") + .build(); + } + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/WebServerMvcConfigurerAdapter.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/WebServerMvcConfigurerAdapter.java new file mode 100644 index 0000000..acd71b5 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/config/WebServerMvcConfigurerAdapter.java @@ -0,0 +1,22 @@ +package com.springboot.cloud.sysadmin.organization.config; + +import com.springboot.cloud.common.web.interceptor.UserInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebServerMvcConfigurerAdapter implements WebMvcConfigurer { + + @Bean + public HandlerInterceptor userInterceptor() { + return new UserInterceptor(); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(userInterceptor()); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/GatewayRouteMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/GatewayRouteMapper.java new file mode 100644 index 0000000..cc657d5 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/GatewayRouteMapper.java @@ -0,0 +1,11 @@ +package com.springboot.cloud.sysadmin.organization.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.GatewayRoute; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Mapper +@Repository +public interface GatewayRouteMapper extends BaseMapper { +} \ No newline at end of file diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/UserMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/UserMapper.java new file mode 100644 index 0000000..9a33021 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/UserMapper.java @@ -0,0 +1,11 @@ +package com.springboot.cloud.sysadmin.organization.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.User; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface UserMapper extends BaseMapper { +} \ No newline at end of file diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationGradeMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationGradeMapper.java new file mode 100644 index 0000000..461a9e8 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationGradeMapper.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.sysadmin.organization.dao.application; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.application.ApplicationGrade; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface ApplicationGradeMapper extends BaseMapper{ +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationGradePopedomMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationGradePopedomMapper.java new file mode 100644 index 0000000..7c109d0 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationGradePopedomMapper.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.sysadmin.organization.dao.application; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.application.ApplicationGradePopedom; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface ApplicationGradePopedomMapper extends BaseMapper { +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationMapper.java new file mode 100644 index 0000000..e81d022 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationMapper.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.sysadmin.organization.dao.application; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.application.Application; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface ApplicationMapper extends BaseMapper { +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationPopedomMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationPopedomMapper.java new file mode 100644 index 0000000..2bb98ad --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/application/ApplicationPopedomMapper.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.sysadmin.organization.dao.application; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.application.ApplicationPopedom; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface ApplicationPopedomMapper extends BaseMapper { +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyApplicationLicenseMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyApplicationLicenseMapper.java new file mode 100644 index 0000000..a311c1c --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyApplicationLicenseMapper.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.sysadmin.organization.dao.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyApplicationLicense; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface CompanyApplicationLicenseMapper extends BaseMapper { +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyApplicationPopedomMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyApplicationPopedomMapper.java new file mode 100644 index 0000000..d0676d5 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyApplicationPopedomMapper.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.sysadmin.organization.dao.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyApplicationPopedom; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface CompanyApplicationPopedomMapper extends BaseMapper { +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyMapper.java new file mode 100644 index 0000000..dd9e4ac --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyMapper.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.sysadmin.organization.dao.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.company.Company; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface CompanyMapper extends BaseMapper { +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyRoleMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyRoleMapper.java new file mode 100644 index 0000000..2beeeb8 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyRoleMapper.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.sysadmin.organization.dao.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyRole; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface CompanyRoleMapper extends BaseMapper { +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyRolePopedomMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyRolePopedomMapper.java new file mode 100644 index 0000000..e5a3af7 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyRolePopedomMapper.java @@ -0,0 +1,19 @@ +package com.springboot.cloud.sysadmin.organization.dao.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyRolePopedom; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface CompanyRolePopedomMapper extends BaseMapper { + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyRoleUserMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyRoleUserMapper.java new file mode 100644 index 0000000..9271270 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyRoleUserMapper.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.sysadmin.organization.dao.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyRoleUser; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface CompanyRoleUserMapper extends BaseMapper { +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyUserMapper.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyUserMapper.java new file mode 100644 index 0000000..06dabb0 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/dao/company/CompanyUserMapper.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.sysadmin.organization.dao.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyUser; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Repository +@Mapper +public interface CompanyUserMapper extends BaseMapper { +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/GatewayRoute.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/GatewayRoute.java new file mode 100644 index 0000000..f28fe51 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/GatewayRoute.java @@ -0,0 +1,21 @@ +package com.springboot.cloud.sysadmin.organization.entity.po; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.springboot.cloud.common.web.entity.po.BasePo; +import lombok.*; + +@EqualsAndHashCode(callSuper = true) +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@TableName("gateway_route") +public class GatewayRoute extends BasePo { + private String uri; + private String routeId; + private String predicates; + private String filters; + private String description; + private Integer orders = 0; + private String status = "Y"; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/User.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/User.java new file mode 100644 index 0000000..37d16d9 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/User.java @@ -0,0 +1,35 @@ +package com.springboot.cloud.sysadmin.organization.entity.po; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@TableName("user") +public class User { + @TableId + private String id; + private String name; + private Date registryTime; + private String identity; + private String nickName; + private String photo; + private String lastModifier; + private Date lastModifyTime; + private String state; + private String mobile; + private String email; + private String introduce; + private String avatar; + private String signature; + private String password; + private String username; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/Application.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/Application.java new file mode 100644 index 0000000..ea4146e --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/Application.java @@ -0,0 +1,29 @@ +package com.springboot.cloud.sysadmin.organization.entity.po.application; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; + +import java.util.Date; + +@Builder +@Data +@TableName("application") +public class Application { + @TableId + private String code; + private String name; + private Integer type; + private String description; + private Date deployedTime; + private Integer orderNo; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/ApplicationGrade.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/ApplicationGrade.java new file mode 100644 index 0000000..62724b2 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/ApplicationGrade.java @@ -0,0 +1,23 @@ +package com.springboot.cloud.sysadmin.organization.entity.po.application; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +@TableName("application_grade") +public class ApplicationGrade { + private String applicationCode; + private Integer grade; + private String mame; + private String description; + private boolean isFree; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/ApplicationGradePopedom.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/ApplicationGradePopedom.java new file mode 100644 index 0000000..4365eab --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/ApplicationGradePopedom.java @@ -0,0 +1,21 @@ +package com.springboot.cloud.sysadmin.organization.entity.po.application; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +@TableName("application_grade_popedom") +public class ApplicationGradePopedom { + private String applicationCode; + private Integer grade; + private Integer popedomId; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/ApplicationPopedom.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/ApplicationPopedom.java new file mode 100644 index 0000000..ea86edb --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/application/ApplicationPopedom.java @@ -0,0 +1,34 @@ +package com.springboot.cloud.sysadmin.organization.entity.po.application; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@TableName("application_popedom") +@NoArgsConstructor +public class ApplicationPopedom { + private String applicationCode; + private String id; + private String name; + private String parentId; + private String url; + private String icon; + private String isMenu; + private String description; + private String path; + private String redirect; + private String component; + private String title; + private boolean alwaysShow; + private boolean hidden; + private Integer orderNo; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/Company.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/Company.java new file mode 100644 index 0000000..ea30ce2 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/Company.java @@ -0,0 +1,55 @@ +package com.springboot.cloud.sysadmin.organization.entity.po.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; + +import java.util.Date; + +@Data +@Builder +@TableName("company") +public class Company { + @TableId + private String id; + private String name; + private String registerId; + private String ownerId; + private Date registerTime; + private String businessLicense; + private String address; + private String description; + private String photo; + private String lastModifier; + private Date lastModifyTime; + private String province; + private String city; + private String county; + private String street; + private Double longitude; + private double latitude; + private Double state; + private String grade; + private String contacter; + private String mobile; + private String tel; + private String email; + private String weixin; + private boolean isFranchiser; + private boolean isIsv; + private String serviceTime; + private String hotlinePhone; + private String logo; + private String logW; + private String icpNo; + private String shortName; + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyApplicationLicense.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyApplicationLicense.java new file mode 100644 index 0000000..dfde132 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyApplicationLicense.java @@ -0,0 +1,28 @@ +package com.springboot.cloud.sysadmin.organization.entity.po.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; + +import java.util.Date; + +@Data +@Builder +@TableName("company_application_license") +public class CompanyApplicationLicense { + private String companyId; + private String franchiserId; + private String applicationCode; + private String grade; + private Date expireDate; + private boolean isForever; + private String state; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyApplicationPopedom.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyApplicationPopedom.java new file mode 100644 index 0000000..b3f9be5 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyApplicationPopedom.java @@ -0,0 +1,21 @@ +package com.springboot.cloud.sysadmin.organization.entity.po.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +@TableName("company_application_popedom") +public class CompanyApplicationPopedom { + private String companyId; + private String applicationCode; + private String popedomId; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyRole.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyRole.java new file mode 100644 index 0000000..ca55f6d --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyRole.java @@ -0,0 +1,22 @@ +package com.springboot.cloud.sysadmin.organization.entity.po.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +@TableName("company_role") +public class CompanyRole { + private String companyId; + private String id; + private String name; + private String remark; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyRolePopedom.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyRolePopedom.java new file mode 100644 index 0000000..7bc3068 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyRolePopedom.java @@ -0,0 +1,22 @@ +package com.springboot.cloud.sysadmin.organization.entity.po.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +@TableName("company_role_popedom") +public class CompanyRolePopedom { + private String companyId; + private String roleId; + private String applicationCode; + private String popedomId; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyRoleUser.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyRoleUser.java new file mode 100644 index 0000000..1ce35f6 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyRoleUser.java @@ -0,0 +1,22 @@ +package com.springboot.cloud.sysadmin.organization.entity.po.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +@TableName("company_role_user") +public class CompanyRoleUser { + private String companyId; + private String roleId; + private String userId; + private boolean isDefault; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyUser.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyUser.java new file mode 100644 index 0000000..9c80a1f --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/po/company/CompanyUser.java @@ -0,0 +1,27 @@ +package com.springboot.cloud.sysadmin.organization.entity.po.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@TableName("company_user") +@NoArgsConstructor +public class CompanyUser { + private String companyId; + private String userId; + private String organizationId; + private String empNo; + private String position; + private Integer isDefault; + private Integer state; + private String mobile; +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/vo/Menu.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/vo/Menu.java new file mode 100644 index 0000000..0415fc5 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/vo/Menu.java @@ -0,0 +1,66 @@ +package com.springboot.cloud.sysadmin.organization.entity.vo; + +/* + ********************************************** + * DATE PERSON REASON + * 2021-01-05 FXY Created + ********************************************** + */ + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.springboot.cloud.sysadmin.organization.entity.po.application.ApplicationPopedom; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Data +@JsonInclude(value = JsonInclude.Include.NON_NULL) +public class Menu { + + @JsonIgnore + private String parentId; + + @JsonIgnore + private String id; + + private String redirect; + private String path; + private String component; + private List children; + private String name; + private boolean hidden; + private boolean alwaysShow; + private Meta meta; + + public Menu(String path, String redirect, boolean hidden) { + this.path = path; + this.redirect = redirect.equals("") ? null : redirect; + this.hidden = hidden; + } + + public Menu(ApplicationPopedom applicationPopedom) { + this.meta = new Meta(); + this.meta.title = applicationPopedom.getTitle(); + this.meta.icon = applicationPopedom.getIcon(); + String s = Optional.ofNullable(applicationPopedom.getRedirect()).orElseGet(String::new); + this.redirect = s.equals("") ? null : s; + this.path = applicationPopedom.getPath(); + this.component = applicationPopedom.getComponent(); + this.name = applicationPopedom.getName(); + this.hidden = applicationPopedom.isHidden(); + this.alwaysShow = applicationPopedom.isAlwaysShow(); + this.id = applicationPopedom.getId(); + this.parentId = applicationPopedom.getParentId(); + this.children = new ArrayList<>(); + } + + @Data + @JsonInclude(value = JsonInclude.Include.NON_NULL) + class Meta { + private String icon; + private String title; + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/vo/Popedom.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/vo/Popedom.java new file mode 100644 index 0000000..6e53039 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/entity/vo/Popedom.java @@ -0,0 +1,47 @@ +package com.springboot.cloud.sysadmin.organization.entity.vo; + +/* + ********************************************** + * DATE PERSON REASON + * 2021-01-04 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.application.ApplicationPopedom; +import lombok.Data; +import org.springframework.beans.BeanUtils; + +import java.util.Objects; + +@Data +public class Popedom extends ApplicationPopedom { + private String companyId; + + public Popedom(ApplicationPopedom applicationPopedom, String companyId) { + this.companyId = companyId; + BeanUtils.copyProperties(applicationPopedom, this); + } + + public Popedom(ApplicationPopedom applicationPopedom) { + BeanUtils.copyProperties(applicationPopedom, this); + } + + public Popedom(String companyId){ + this.companyId=companyId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Popedom)) return false; + if (!super.equals(o)) return false; + Popedom popedom = (Popedom) o; + return Objects.equals(companyId, popedom.companyId); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), companyId); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/events/EventSender.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/events/EventSender.java new file mode 100644 index 0000000..19d961e --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/events/EventSender.java @@ -0,0 +1,31 @@ +package com.springboot.cloud.sysadmin.organization.events; + +import com.springboot.cloud.sysadmin.organization.config.BusConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +@Slf4j +public class EventSender { + + @Autowired + private RabbitTemplate rabbitTemplate; + + @Autowired + private MessageConverter messageConverter; + + @PostConstruct + public void init() { + rabbitTemplate.setMessageConverter(messageConverter); + } + + public void send(String routingKey, Object object) { + log.info("routingKey:{}=>message:{}", routingKey, object); + rabbitTemplate.convertAndSend(BusConfig.EXCHANGE_NAME, routingKey, object); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/GlobalExceptionHandlerAdvice.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/GlobalExceptionHandlerAdvice.java new file mode 100644 index 0000000..1c5563e --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/GlobalExceptionHandlerAdvice.java @@ -0,0 +1,18 @@ +package com.springboot.cloud.sysadmin.organization.exception; + +import com.springboot.cloud.common.core.entity.vo.Result; +import com.springboot.cloud.common.web.exception.DefaultGlobalExceptionHandlerAdvice; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandlerAdvice extends DefaultGlobalExceptionHandlerAdvice { + + @ExceptionHandler(value = {UserNotFoundException.class}) + public Result userNotFound(UserNotFoundException ex) { + log.error(ex.getMessage()); + return Result.fail(ex.getErrorType()); + } +} \ No newline at end of file diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/OrganizationErrorType.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/OrganizationErrorType.java new file mode 100644 index 0000000..c244235 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/OrganizationErrorType.java @@ -0,0 +1,25 @@ +package com.springboot.cloud.sysadmin.organization.exception; + +import com.springboot.cloud.common.core.exception.ErrorType; +import lombok.Getter; + +@Getter +public enum OrganizationErrorType implements ErrorType { + + USER_NOT_FOUND("030100", "用户未找到!"), + ROLE_NOT_FOUND("030200", "角色未找到!"); + + /** + * 错误类型码 + */ + private String code; + /** + * 错误类型描述信息 + */ + private String mesg; + + OrganizationErrorType(String code, String mesg) { + this.code = code; + this.mesg = mesg; + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/RoleNotFoundException.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/RoleNotFoundException.java new file mode 100644 index 0000000..f48b159 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/RoleNotFoundException.java @@ -0,0 +1,13 @@ +package com.springboot.cloud.sysadmin.organization.exception; + +import com.springboot.cloud.common.core.exception.BaseException; + +public class RoleNotFoundException extends BaseException { + public RoleNotFoundException() { + super(OrganizationErrorType.ROLE_NOT_FOUND); + } + + public RoleNotFoundException(String message) { + super(OrganizationErrorType.ROLE_NOT_FOUND, message); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/UserNotFoundException.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/UserNotFoundException.java new file mode 100644 index 0000000..b6cdb7f --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/exception/UserNotFoundException.java @@ -0,0 +1,13 @@ +package com.springboot.cloud.sysadmin.organization.exception; + +import com.springboot.cloud.common.core.exception.BaseException; + +public class UserNotFoundException extends BaseException { + public UserNotFoundException() { + super(OrganizationErrorType.USER_NOT_FOUND); + } + + public UserNotFoundException(String message) { + super(OrganizationErrorType.USER_NOT_FOUND, message); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/CompanyController.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/CompanyController.java new file mode 100644 index 0000000..6a966b3 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/CompanyController.java @@ -0,0 +1,92 @@ +package com.springboot.cloud.sysadmin.organization.rest; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + +import com.springboot.cloud.common.core.entity.vo.Result; +import com.springboot.cloud.sysadmin.organization.exception.UserNotFoundException; +import com.springboot.cloud.sysadmin.organization.service.ApplicationService; +import com.springboot.cloud.sysadmin.organization.service.CompanyService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Optional; + +@RestController +@RequestMapping("/company") +@Slf4j +public class CompanyController { + + @Autowired + CompanyService companyService; + + @Autowired + ApplicationService applicationService; + + @GetMapping("/getPopedom") + public Result getCompanyRoleUserPopedom(@RequestParam("companyId") String companyId, @RequestParam("username") String username) { + Optional.ofNullable(companyId).orElseThrow(UserNotFoundException::new); + Optional.ofNullable(username).orElseThrow(UserNotFoundException::new); + return Result.success(companyService.getCompanyUserPopedom(companyId, username)); + } + + @GetMapping("/getCompanyAllPopedom") + public Result getCompanyAllPopedom(@RequestParam("companyId") String companyId) { + Optional.ofNullable(companyId).orElseThrow(UserNotFoundException::new); + return Result.success(companyService.getCompanyAllPopedom(companyId)); + } + + @RequestMapping("/license") + public Result license(@RequestParam("companyId") String companyId, @RequestParam("applicationCode") String applicationCode) { + Optional.ofNullable(companyId).orElseThrow(UserNotFoundException::new); + Optional.ofNullable(applicationCode).orElseThrow(UserNotFoundException::new); + return Result.success(applicationService.license(companyId, applicationCode)); + } + + @GetMapping("/getAllPopedom") + public Result getAllPopedom() { + return Result.success(companyService.getAllPopedom()); + } + + @GetMapping("/getUserAllCompany") + public Result getUserAllCompany(@RequestParam("userId") String userId){ + Optional.ofNullable(userId).orElseThrow(UserNotFoundException::new); + return Result.success(companyService.getUserAllCompany(userId)); + } + + +// @GetMapping("/getPopedom") +// public Result getCompanyRoleUserPopedom() { +// return Result.success(companyService.getCompanyUserPopedom(UserContextHolder.getInstance().getCurrentCompany(), UserContextHolder.getInstance().getUsername())); +// } +// +// @GetMapping("/getCompanyAllPopedom") +// public Result getCompanyAllPopedom() { +// return Result.success(companyService.getCompanyAllPopedom(UserContextHolder.getInstance().getCurrentCompany())); +// } +// +// @RequestMapping("/license") +// public Result license(@RequestParam("applicationCode") String applicationCode) { +// return Result.success(applicationService.license(UserContextHolder.getInstance().getCurrentCompany(), applicationCode)); +// } +// +// @GetMapping("/getAllPopedom") +// public Result getAllPopedom() { +// return Result.success(companyService.getAllPopedom()); +// } +// +// @GetMapping("/getUserAllCompany") +// public Result getUserAllCompany(@RequestParam("userId") String userId) { +// Optional.ofNullable(userId).orElseThrow(UserNotFoundException::new); +// return Result.success(companyService.getUserAllCompany(userId)); +// } + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/HrDemo.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/HrDemo.java new file mode 100644 index 0000000..5c4f129 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/HrDemo.java @@ -0,0 +1,35 @@ +package com.springboot.cloud.sysadmin.organization.rest; + +/* + ********************************************** + * DATE PERSON REASON + * 2021-01-04 FXY Created + ********************************************** + */ + +import com.springboot.cloud.common.core.entity.vo.Result; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/hr") +@Slf4j +public class HrDemo { + + @GetMapping("/list") + public Result list(){ + return Result.success("list访问成功!"); + } + + @GetMapping("/delete") + public Result delete(){ + return Result.success("delete访问成功!"); + } + + @GetMapping("/update") + public Result update(){ + return Result.success("update访问成功!"); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/MenuController.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/MenuController.java new file mode 100644 index 0000000..337ced4 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/MenuController.java @@ -0,0 +1,34 @@ +package com.springboot.cloud.sysadmin.organization.rest; + +/* + ********************************************** + * DATE PERSON REASON + * 2021-01-05 FXY Created + ********************************************** + */ + +import com.springboot.cloud.common.core.entity.vo.Result; +import com.springboot.cloud.sysadmin.organization.exception.UserNotFoundException; +import com.springboot.cloud.sysadmin.organization.service.MenuService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Optional; + +@RestController +@RequestMapping("/menu") +public class MenuController { + + @Autowired + MenuService menuService; + + @GetMapping("/index") + public Result index(@RequestParam("companyId")String companyId){ + Optional.ofNullable(companyId).orElseThrow(UserNotFoundException::new); + return Result.success(menuService.index(companyId)); + } + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/RoleController.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/RoleController.java new file mode 100644 index 0000000..409b793 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/RoleController.java @@ -0,0 +1,29 @@ +package com.springboot.cloud.sysadmin.organization.rest; + +import com.springboot.cloud.common.core.entity.vo.Result; +import com.springboot.cloud.sysadmin.organization.exception.UserNotFoundException; +import com.springboot.cloud.sysadmin.organization.service.CompanyService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Optional; + +@RestController +@RequestMapping("/role") +@Slf4j +public class RoleController { + + @Autowired + CompanyService companyService; + + @GetMapping("/getRoleUser") + public Result getUserByUsername(@RequestParam("userId")String userId){ + Optional.ofNullable(userId).orElseThrow(UserNotFoundException::new); + return Result.success(companyService.getCompanyRoleUser(userId)); + } + +} \ No newline at end of file diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/UserController.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/UserController.java new file mode 100644 index 0000000..9bd8e44 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/rest/UserController.java @@ -0,0 +1,29 @@ +package com.springboot.cloud.sysadmin.organization.rest; + +import com.springboot.cloud.common.core.entity.vo.Result; +import com.springboot.cloud.sysadmin.organization.exception.UserNotFoundException; +import com.springboot.cloud.sysadmin.organization.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Optional; + +@RestController +@RequestMapping("/user") +@Slf4j +public class UserController { + + @Autowired + UserService userService; + + @GetMapping("/getUserByUsernameOrMobile") + public Result getUserByUsername(@RequestParam("payload")String payload){ + Optional.ofNullable(payload).orElseThrow(UserNotFoundException::new); + return Result.success(userService.getUserByUsernameOrMobile(payload)); + } + +} \ No newline at end of file diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/ApplicationService.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/ApplicationService.java new file mode 100644 index 0000000..e264d78 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/ApplicationService.java @@ -0,0 +1,22 @@ +package com.springboot.cloud.sysadmin.organization.service; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-31 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyApplicationLicense; + +public interface ApplicationService { + + /** + * 取得公司应用许可信息 + * @param companyId 公司编号 + * @param applicationCode 应用编码 + * @return + */ + public CompanyApplicationLicense license(String companyId,String applicationCode); +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/CompanyService.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/CompanyService.java new file mode 100644 index 0000000..1b8d71f --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/CompanyService.java @@ -0,0 +1,72 @@ +package com.springboot.cloud.sysadmin.organization.service; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.application.ApplicationPopedom; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyRolePopedom; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyRoleUser; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyUser; +import com.springboot.cloud.sysadmin.organization.entity.vo.Popedom; + +import java.util.List; + +public interface CompanyService { + /** + * 得到用户所有的角色 + * @param companyId + * @param userId + * @return + */ + public List getCompanyRoleUser(String companyId, String userId); + + /** + * 得到用户所有的角色 + */ + public List getCompanyRoleUser(String userId); + + /** + * 得到角色资源 + * @param companyId + * @param roleId + * @return + */ + public List getCompanyRolePopedom(String companyId, String roleId); + + /** + * 得到角色资源 + * @param companyId + * @param roleIds + * @return + */ + public List getCompanyRolePopedom(String companyId,List roleIds); + + + /** + * 得到用户资源 + * @return + */ + public List getCompanyUserPopedom(String companyId,String userId); + + /** + * 得到公司所有资源 + * @param companyId + * @return + */ + public List getCompanyAllPopedom(String companyId); + + /** + * 得到所有公司资源 + */ + public List getAllPopedom(); + + /** + * 得到用户对应的所有公司 + */ + public List getUserAllCompany(String userId); +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/GatewayService.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/GatewayService.java new file mode 100644 index 0000000..06c52eb --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/GatewayService.java @@ -0,0 +1,11 @@ +package com.springboot.cloud.sysadmin.organization.service; + +public interface GatewayService { + + /** + * 重新加载网关路由配置到redis + * + * @return 成功返回true + */ + void overload(); +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/MenuService.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/MenuService.java new file mode 100644 index 0000000..37e003e --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/MenuService.java @@ -0,0 +1,24 @@ +package com.springboot.cloud.sysadmin.organization.service; + +/* + ********************************************** + * DATE PERSON REASON + * 2021-01-05 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.vo.Menu; + +import java.util.List; + +public interface MenuService { + + /** + * 公司编号得到菜单信息 + * @param companyId 公司编号 + * @return + */ + public List index(String companyId); + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/UserService.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/UserService.java new file mode 100644 index 0000000..419c40a --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/UserService.java @@ -0,0 +1,14 @@ +package com.springboot.cloud.sysadmin.organization.service; + +import com.springboot.cloud.sysadmin.organization.entity.po.User; + +public interface UserService { + + /** + * 账户或者手机号获取用户信息 + * @param payload + * @return + */ + public User getUserByUsernameOrMobile(String payload); + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/application/ApplicationPopedomService.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/application/ApplicationPopedomService.java new file mode 100644 index 0000000..aad438b --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/application/ApplicationPopedomService.java @@ -0,0 +1,23 @@ +package com.springboot.cloud.sysadmin.organization.service.application; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.application.ApplicationPopedom; + +import java.util.List; + +public interface ApplicationPopedomService { + + /** + * 根据资源编号获取资源信息 + * @param ids 资源编号 + * @return + */ + public List getApplicationPopedom(List ids); +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/application/impl/ApplicationPopedomServiceImpl.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/application/impl/ApplicationPopedomServiceImpl.java new file mode 100644 index 0000000..4ea80cd --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/application/impl/ApplicationPopedomServiceImpl.java @@ -0,0 +1,31 @@ +package com.springboot.cloud.sysadmin.organization.service.application.impl; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.springboot.cloud.sysadmin.organization.dao.application.ApplicationPopedomMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.application.ApplicationPopedom; +import com.springboot.cloud.sysadmin.organization.service.application.ApplicationPopedomService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Slf4j +public class ApplicationPopedomServiceImpl extends ServiceImpl implements ApplicationPopedomService { + + @Override + public List getApplicationPopedom(List ids) { + QueryWrapper queryWrapper=new QueryWrapper<>(); + queryWrapper.in("id",ids); + return this.list(queryWrapper); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyApplicationLicenseService.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyApplicationLicenseService.java new file mode 100644 index 0000000..82939e1 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyApplicationLicenseService.java @@ -0,0 +1,23 @@ +package com.springboot.cloud.sysadmin.organization.service.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyApplicationLicense; + +public interface CompanyApplicationLicenseService { + + /** + * 查询公司应用许可 + * @param companyId 公司编号 + * @param applicationCode 应用代码 + * @return + */ + public CompanyApplicationLicense license(String companyId,String applicationCode); + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyApplicationPopedomService.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyApplicationPopedomService.java new file mode 100644 index 0000000..e35c417 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyApplicationPopedomService.java @@ -0,0 +1,29 @@ +package com.springboot.cloud.sysadmin.organization.service.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyApplicationPopedom; + +import java.util.List; + +public interface CompanyApplicationPopedomService { + + /** + * 得到公司所有应用资源 + * @param companyId 公司编号 + * @return + */ + public List getApplicationPopedom(String companyId); + + /** + * 得到所有公司资源 + */ + public List getApplicationPopedom(); + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyRolePopedomService.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyRolePopedomService.java new file mode 100644 index 0000000..c5666eb --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyRolePopedomService.java @@ -0,0 +1,33 @@ +package com.springboot.cloud.sysadmin.organization.service.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyRolePopedom; + +import java.util.List; + +public interface CompanyRolePopedomService { + /** + * 得到公司角色资源 + * @param companyId 公司编号 + * @param roleId 角色编号 + * @return + */ + public List getCompanyRolePopedom(String companyId, String roleId); + + + /** + * 得到公司角色资源 + * @param companyId 公司编号 + * @param roleIds 角色编号集合 + * @return + */ + public List getCompanyRolePopedom(String companyId,List roleIds); + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyRoleUserService.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyRoleUserService.java new file mode 100644 index 0000000..44aef6b --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyRoleUserService.java @@ -0,0 +1,25 @@ +package com.springboot.cloud.sysadmin.organization.service.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyRoleUser; + +import java.util.List; + +public interface CompanyRoleUserService { + + /** + * 根据公司编号和用户编号得到角色信息 + * @param companyId 公司编号 + * @param userId 用户账号 + * @return + */ + public List getRoleByCompanyIdAndUserId(String companyId, String userId); + +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyUserService.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyUserService.java new file mode 100644 index 0000000..3fa339c --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/CompanyUserService.java @@ -0,0 +1,33 @@ +package com.springboot.cloud.sysadmin.organization.service.company; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyUser; + +import java.util.List; + +public interface CompanyUserService { + + /** + * 根据公司编号和用户编号取得用户信息 + * + * @param companyId 公司编号 + * @param userId 用户编号 + * @return + */ + public CompanyUser getUserByCompanyIdAndUserId(String companyId, String userId); + + + /** + * 根据用户编号得到公司信息 + * @param userId 用户编号 + * @return + */ + public List getCompanyByUserId(String userId); +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyApplicationLicenseServiceImpl.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyApplicationLicenseServiceImpl.java new file mode 100644 index 0000000..b3c2752 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyApplicationLicenseServiceImpl.java @@ -0,0 +1,28 @@ +package com.springboot.cloud.sysadmin.organization.service.company.impl; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.springboot.cloud.sysadmin.organization.dao.company.CompanyApplicationLicenseMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyApplicationLicense; +import com.springboot.cloud.sysadmin.organization.service.company.CompanyApplicationLicenseService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class CompanyApplicationLicenseServiceImpl extends ServiceImpl implements CompanyApplicationLicenseService { + @Override + public CompanyApplicationLicense license(String companyId, String applicationCode) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("company_id",companyId).eq("application_code",applicationCode); + return getOne(queryWrapper); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyApplicationPopedomServiceImpl.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyApplicationPopedomServiceImpl.java new file mode 100644 index 0000000..ac0709c --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyApplicationPopedomServiceImpl.java @@ -0,0 +1,38 @@ +package com.springboot.cloud.sysadmin.organization.service.company.impl; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.springboot.cloud.sysadmin.organization.dao.company.CompanyApplicationPopedomMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.application.ApplicationPopedom; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyApplicationPopedom; +import com.springboot.cloud.sysadmin.organization.service.company.CompanyApplicationPopedomService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class CompanyApplicationPopedomServiceImpl extends ServiceImpl implements CompanyApplicationPopedomService { + + @Override + public List getApplicationPopedom(String companyId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("company_id",companyId); + return list(queryWrapper); + } + + @Override + public List getApplicationPopedom() { + return list(); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyRolePopedomServiceImpl.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyRolePopedomServiceImpl.java new file mode 100644 index 0000000..60c6cbd --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyRolePopedomServiceImpl.java @@ -0,0 +1,38 @@ +package com.springboot.cloud.sysadmin.organization.service.company.impl; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.springboot.cloud.sysadmin.organization.dao.company.CompanyRolePopedomMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyRolePopedom; +import com.springboot.cloud.sysadmin.organization.service.company.CompanyRolePopedomService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Slf4j +public class CompanyRolePopedomServiceImpl extends ServiceImpl implements CompanyRolePopedomService { + + @Override + public List getCompanyRolePopedom(String companyId, String roleId) { + QueryWrapper companyRolePopedomQueryWrapper = new QueryWrapper<>(); + companyRolePopedomQueryWrapper.eq("company_id", companyId).eq("role_id", roleId); + return this.list(companyRolePopedomQueryWrapper); + } + + @Override + public List getCompanyRolePopedom(String companyId, List roleIds) { + QueryWrapper companyRolePopedomQueryWrapper = new QueryWrapper<>(); + companyRolePopedomQueryWrapper.eq("company_id", companyId).in("role_id", roleIds); + return this.list(companyRolePopedomQueryWrapper); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyRoleUserServiceImpl.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyRoleUserServiceImpl.java new file mode 100644 index 0000000..c3a0a27 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyRoleUserServiceImpl.java @@ -0,0 +1,33 @@ +package com.springboot.cloud.sysadmin.organization.service.company.impl; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.springboot.cloud.sysadmin.organization.dao.company.CompanyRoleUserMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyRoleUser; +import com.springboot.cloud.sysadmin.organization.exception.UserNotFoundException; +import com.springboot.cloud.sysadmin.organization.service.company.CompanyRoleUserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +@Slf4j +public class CompanyRoleUserServiceImpl extends ServiceImpl implements CompanyRoleUserService { + + @Override + public List getRoleByCompanyIdAndUserId(String companyId, String userId) { + QueryWrapper companyRoleUserQueryWrapper = new QueryWrapper<>(); + companyRoleUserQueryWrapper.eq("company_id", companyId).eq("user_id", userId); + return this.list(companyRoleUserQueryWrapper); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyUserServiceImpl.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyUserServiceImpl.java new file mode 100644 index 0000000..810cdb2 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/company/impl/CompanyUserServiceImpl.java @@ -0,0 +1,42 @@ +package com.springboot.cloud.sysadmin.organization.service.company.impl; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.springboot.cloud.sysadmin.organization.dao.company.CompanyUserMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyUser; +import com.springboot.cloud.sysadmin.organization.exception.UserNotFoundException; +import com.springboot.cloud.sysadmin.organization.service.company.CompanyRoleUserService; +import com.springboot.cloud.sysadmin.organization.service.company.CompanyUserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +@Slf4j +public class CompanyUserServiceImpl extends ServiceImpl implements CompanyUserService { + + @Override + public CompanyUser getUserByCompanyIdAndUserId(String companyId, String userId) { + QueryWrapper userQueryWrapper=new QueryWrapper<>(); + userQueryWrapper.eq("company_id",companyId).eq("user_id",userId); + return this.getOne(userQueryWrapper); + } + + @Override + public List getCompanyByUserId(String userId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("user_id",userId); + return this.list(queryWrapper); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/ApplicationServiceImpl.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/ApplicationServiceImpl.java new file mode 100644 index 0000000..1a2a805 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/ApplicationServiceImpl.java @@ -0,0 +1,27 @@ +package com.springboot.cloud.sysadmin.organization.service.impl; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-31 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyApplicationLicense; +import com.springboot.cloud.sysadmin.organization.service.ApplicationService; +import com.springboot.cloud.sysadmin.organization.service.company.CompanyApplicationLicenseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ApplicationServiceImpl implements ApplicationService { + + @Autowired + CompanyApplicationLicenseService companyApplicationLicenseService; + + @Override + public CompanyApplicationLicense license(String companyId, String applicationCode) { + return companyApplicationLicenseService.license(companyId,applicationCode); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/CompanyServiceImpl.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/CompanyServiceImpl.java new file mode 100644 index 0000000..b08d7f7 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/CompanyServiceImpl.java @@ -0,0 +1,112 @@ +package com.springboot.cloud.sysadmin.organization.service.impl; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-29 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.User; +import com.springboot.cloud.sysadmin.organization.entity.po.application.ApplicationPopedom; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyApplicationPopedom; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyRolePopedom; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyRoleUser; +import com.springboot.cloud.sysadmin.organization.entity.po.company.CompanyUser; +import com.springboot.cloud.sysadmin.organization.entity.vo.Popedom; +import com.springboot.cloud.sysadmin.organization.service.CompanyService; +import com.springboot.cloud.sysadmin.organization.service.UserService; +import com.springboot.cloud.sysadmin.organization.service.application.ApplicationPopedomService; +import com.springboot.cloud.sysadmin.organization.service.company.CompanyApplicationPopedomService; +import com.springboot.cloud.sysadmin.organization.service.company.CompanyRolePopedomService; +import com.springboot.cloud.sysadmin.organization.service.company.CompanyRoleUserService; +import com.springboot.cloud.sysadmin.organization.service.company.CompanyUserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Service +@Slf4j +public class CompanyServiceImpl implements CompanyService { + + @Autowired + UserService userService; + + @Autowired + CompanyUserService companyUserService; + + @Autowired + CompanyRoleUserService companyRoleUserService; + + @Autowired + CompanyRolePopedomService companyRolePopedomService; + + @Autowired + ApplicationPopedomService applicationPopedomService; + + @Autowired + CompanyApplicationPopedomService companyApplicationPopedomService; + + @Override + public List getCompanyRoleUser(String companyId, String userId) { + return companyRoleUserService.getRoleByCompanyIdAndUserId(companyId, userId); + } + + @Override + public List getCompanyRoleUser(String userId) { + //找到用户对应的所有公司 + List companyUsers = companyUserService.getCompanyByUserId(userId); + //找到用户默认的公司 + CompanyUser companyUser = companyUsers.stream().filter(a -> a.getIsDefault() == 1).findAny().orElseGet(CompanyUser::new); + + //找到用户的所有角色 + return companyRoleUserService.getRoleByCompanyIdAndUserId(companyUser.getCompanyId(), userId); + } + + @Override + public List getCompanyRolePopedom(String companyId, String roleId) { + return companyRolePopedomService.getCompanyRolePopedom(companyId, roleId); + } + + @Override + public List getCompanyRolePopedom(String companyId, List roleIds) { + return companyRolePopedomService.getCompanyRolePopedom(companyId, roleIds); + } + + @Override + public List getCompanyUserPopedom(String companyId, String username) { + User user = userService.getUserByUsernameOrMobile(username); + List companyRoleUsers = getCompanyRoleUser(companyId, user.getId()); + List roleIds = companyRoleUsers.stream().map(CompanyRoleUser::getRoleId).collect(Collectors.toList()); + List companyRolePopedoms = getCompanyRolePopedom(companyId, roleIds); + List popedomIds = companyRolePopedoms.stream().map(CompanyRolePopedom::getPopedomId).collect(Collectors.toList()); + return applicationPopedomService.getApplicationPopedom(popedomIds); + } + + @Override + public List getCompanyAllPopedom(String companyId) { + List companyApplicationPopedoms = companyApplicationPopedomService.getApplicationPopedom(companyId); + List popedomIds = companyApplicationPopedoms.stream().map(CompanyApplicationPopedom::getPopedomId).collect(Collectors.toList()); + return applicationPopedomService.getApplicationPopedom(popedomIds); + } + + @Override + public List getAllPopedom() { + //先获取所有公司的功能 + List companyApplicationPopedoms = companyApplicationPopedomService.getApplicationPopedom(); + Map> company2PopedomIds = companyApplicationPopedoms.stream().collect(Collectors.groupingBy(CompanyApplicationPopedom::getCompanyId, Collectors.mapping(CompanyApplicationPopedom::getPopedomId, Collectors.toList()))); + return company2PopedomIds.keySet().stream().flatMap(a -> applicationPopedomService.getApplicationPopedom(company2PopedomIds.get(a)).stream().map(b -> new Popedom(b, a))).collect(Collectors.toList()); + } + + @Override + public List getUserAllCompany(String userId) { + return companyUserService.getCompanyByUserId(userId); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/GatewayServiceImpl.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/GatewayServiceImpl.java new file mode 100644 index 0000000..4c10b1d --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/GatewayServiceImpl.java @@ -0,0 +1,73 @@ +package com.springboot.cloud.sysadmin.organization.service.impl; + +import com.alicp.jetcache.Cache; +import com.alicp.jetcache.anno.CacheType; +import com.alicp.jetcache.anno.CreateCache; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.springboot.cloud.sysadmin.organization.dao.GatewayRouteMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.GatewayRoute; +import com.springboot.cloud.sysadmin.organization.service.GatewayService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.filter.FilterDefinition; +import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.net.URI; +import java.util.List; + +@Service +@Slf4j +public class GatewayServiceImpl extends ServiceImpl implements GatewayService { + + private static final String GATEWAY_ROUTES = "gateway_routes::"; + + /** + * 将路由信息存入redis + */ + @CreateCache(name = GATEWAY_ROUTES, cacheType = CacheType.REMOTE) + private Cache gatewayRouteCache; + + /** + * 将数据库中json对象转换为网关需要的RouteDefinition对象 + * + * @param gatewayRoute + * @return RouteDefinition + */ + private RouteDefinition gatewayRouteToRouteDefinition(GatewayRoute gatewayRoute) { + RouteDefinition routeDefinition = new RouteDefinition(); + routeDefinition.setId(gatewayRoute.getRouteId()); + routeDefinition.setOrder(gatewayRoute.getOrders()); + routeDefinition.setUri(URI.create(gatewayRoute.getUri())); + ObjectMapper objectMapper = new ObjectMapper(); + try { + routeDefinition.setFilters(objectMapper.readValue(gatewayRoute.getFilters(), new TypeReference>() { + })); + routeDefinition.setPredicates(objectMapper.readValue(gatewayRoute.getPredicates(), new TypeReference>() { + })); + } catch (IOException e) { + log.error("网关路由对象转换失败", e); + } + return routeDefinition; + } + + /** + * 初始化加载进redis + * + * @return + */ + @Override + @PostConstruct + public void overload() { + List gatewayRoutes = this.list(new QueryWrapper<>()); + gatewayRoutes.forEach(gatewayRoute -> + gatewayRouteCache.put(gatewayRoute.getRouteId(), gatewayRouteToRouteDefinition(gatewayRoute)) + ); + log.info("全局初使化网关路由成功!"); + } +} diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/MenuServiceImpl.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/MenuServiceImpl.java new file mode 100644 index 0000000..435b3ab --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/MenuServiceImpl.java @@ -0,0 +1,63 @@ +package com.springboot.cloud.sysadmin.organization.service.impl; + +/* + ********************************************** + * DATE PERSON REASON + * 2021-01-05 FXY Created + ********************************************** + */ + + +import com.springboot.cloud.sysadmin.organization.entity.po.application.ApplicationPopedom; +import com.springboot.cloud.sysadmin.organization.entity.vo.Menu; +import com.springboot.cloud.sysadmin.organization.service.CompanyService; +import com.springboot.cloud.sysadmin.organization.service.MenuService; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class MenuServiceImpl implements MenuService { + + + @Autowired + CompanyService companyService; + + @Override + public List index(String companyId) { + + //得到公司对应的所有权限 + List allPopedoms = companyService.getCompanyAllPopedom(companyId); + + //先选出菜单 + List popedoms = allPopedoms.stream().filter(a -> a.getIsMenu().equals("1") || a.getIsMenu().equals("2")).collect(Collectors.toList()); + + //转换节点到菜单 + List menuList = popedoms.stream().map(a -> new Menu(a)).collect(Collectors.toList()); + + //构建菜单树 + List result = buildMenuTree(menuList, null); + + //添加默认显示 + result.add(new Menu("*", "/404", true)); + + return result; + } + + + //递归生成树 + private List buildMenuTree(List menuList, String pid) { + List treeList = new ArrayList<>(); + menuList.stream().forEach(menu -> { + if (StringUtils.equals(pid, menu.getParentId())) { + menu.setChildren(buildMenuTree(menuList, menu.getId())); + treeList.add(menu); + } + }); + return treeList; + } +} \ No newline at end of file diff --git a/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/UserServiceImpl.java b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..ed69081 --- /dev/null +++ b/sysadmin/organization/src/main/java/com/springboot/cloud/sysadmin/organization/service/impl/UserServiceImpl.java @@ -0,0 +1,36 @@ +package com.springboot.cloud.sysadmin.organization.service.impl; + +/* + ********************************************** + * DATE PERSON REASON + * 2020-12-30 FXY Created + ********************************************** + */ + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.springboot.cloud.sysadmin.organization.dao.UserMapper; +import com.springboot.cloud.sysadmin.organization.entity.po.User; +import com.springboot.cloud.sysadmin.organization.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class UserServiceImpl extends ServiceImpl implements UserService { + + /** + * username用户账户,唯一 + * mobile 用户手机号,唯一 + * + * @param payload + * @return + */ + @Override + public User getUserByUsernameOrMobile(String payload) { + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq("username", payload).or().eq("mobile", payload); + return getOne(queryWrapper); + } +} diff --git a/sysadmin/pom.xml b/sysadmin/pom.xml new file mode 100644 index 0000000..1b5abbe --- /dev/null +++ b/sysadmin/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + sysadmin + 0.0.1-SNAPSHOT + pom + + sysadmin + Demo Sysadmin project for Spring Boot + + + webapp-parent + business.chaoran + 0.0.1-SNAPSHOT + ../webapps/webapp-parent/pom.xml + + + + organization + + \ No newline at end of file diff --git a/webapps/pom.xml b/webapps/pom.xml new file mode 100644 index 0000000..9a64241 --- /dev/null +++ b/webapps/pom.xml @@ -0,0 +1,104 @@ + + + 4.0.0 + + webapps + pom + 0.0.1-SNAPSHOT + + webapps + Demo Webapps project for Spring Boot + + + xin-cloud + business.chaoran + 1.0-SNAPSHOT + + + + webapp-parent + + + + + org.springframework.boot + spring-boot-starter-web + + + + business.chaoran + web + 0.0.1-SNAPSHOT + + + + com.alibaba + druid-spring-boot-starter + 1.1.9 + + + + mysql + mysql-connector-java + 8.0.18 + + + org.flywaydb + flyway-core + test + 5.1.3 + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + + + + + io.github.swagger2markup + swagger2markup-maven-plugin + 1.3.4 + + http://localhost:8001/v2/api-docs + src/main/docs/asciidoc/generated + + ASCIIDOC + + + + + + org.asciidoctor + asciidoctor-maven-plugin + 1.5.6 + + src/main/docs/asciidoc/generated + src/main/gst/asciidoc/html + html + coderay + + book + left + 3 + + + + + + + + + + + \ No newline at end of file diff --git a/webapps/webapp-parent/pom.xml b/webapps/webapp-parent/pom.xml new file mode 100644 index 0000000..8d4dab6 --- /dev/null +++ b/webapps/webapp-parent/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + webapp-parent + pom + 0.0.1-SNAPSHOT + + + webapps + business.chaoran + 0.0.1-SNAPSHOT + + + + + + com.baomidou + mybatis-plus-boot-starter + 3.1.0 + + + org.mybatis + mybatis-spring + 2.0.0 + + + + \ No newline at end of file