From de6444c2331320a319c78643d5440aec7c29731b Mon Sep 17 00:00:00 2001 From: whq <460794335@qq.com> Date: Thu, 6 Apr 2023 09:36:50 +0800 Subject: [PATCH] =?UTF-8?q?=E9=89=B4=E6=9D=83=E4=BB=A5=E5=8F=8A=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/CommonConstant.java | 5 +- kn-sys-manager/Dockerfile | 15 + kn-sys-manager/pom.xml | 159 ++++++ .../auth/SystemManagerApplication.java | 24 + ...BladeAuthorizationServerConfiguration.java | 91 ++++ .../BladeResourceServerConfiguration.java | 63 +++ .../config/JwtTokenStoreConfiguration.java | 66 +++ .../auth/config/SecurityConfiguration.java | 56 ++ .../auth/constant/AuthConstant.java | 53 ++ .../auth/endpoint/BladeTokenEndPoint.java | 93 ++++ .../auth/granter/BladeTokenGranter.java | 33 ++ .../auth/granter/CaptchaTokenGranter.java | 82 +++ .../BladeClientDetailsServiceImpl.java | 54 ++ .../auth/service/BladeUserDetails.java | 93 ++++ .../service/BladeUserDetailsServiceImpl.java | 124 +++++ .../auth/support/BladeJwtTokenEnhancer.java | 60 +++ .../support/BladeNoOpPasswordEncoder.java | 50 ++ .../auth/support/BladePasswordEncoder.java | 39 ++ .../BladePasswordEncoderFactories.java | 66 +++ .../auth/system/cache/DictBizCache.java | 89 ++++ .../auth/system/cache/SysCache.java | 116 +++++ .../auth/system/cache/UserCache.java | 65 +++ .../system/controller/DictBizController.java | 171 +++++++ .../system/controller/MenuController.java | 206 ++++++++ .../system/controller/RoleController.java | 160 ++++++ .../system/controller/UserController.java | 216 ++++++++ .../springblade/auth/system/dto/MenuDTO.java | 17 + .../springblade/auth/system/dto/RoleDTO.java | 17 + .../auth/system/dto/RoleMenuDTO.java | 17 + .../auth/system/entity/DictBiz.java | 92 ++++ .../springblade/auth/system/entity/Menu.java | 159 ++++++ .../springblade/auth/system/entity/Role.java | 90 ++++ .../auth/system/entity/RoleMenu.java | 65 +++ .../springblade/auth/system/entity/User.java | 102 ++++ .../auth/system/entity/UserInfo.java | 68 +++ .../auth/system/enums/UserEnum.java | 69 +++ .../auth/system/mapper/DictBizMapper.java | 48 ++ .../auth/system/mapper/DictBizMapper.xml | 51 ++ .../auth/system/mapper/MenuMapper.java | 182 +++++++ .../auth/system/mapper/MenuMapper.xml | 478 ++++++++++++++++++ .../auth/system/mapper/RoleMapper.java | 51 ++ .../auth/system/mapper/RoleMapper.xml | 63 +++ .../auth/system/mapper/RoleMenuMapper.java | 25 + .../auth/system/mapper/RoleMenuMapper.xml | 16 + .../auth/system/mapper/UserMapper.java | 37 ++ .../auth/system/mapper/UserMapper.xml | 86 ++++ .../auth/system/service/IDictBizService.java | 85 ++++ .../auth/system/service/IMenuService.java | 101 ++++ .../auth/system/service/IRoleMenuService.java | 13 + .../auth/system/service/IRoleService.java | 76 +++ .../auth/system/service/IUserService.java | 125 +++++ .../service/impl/DictBizServiceImpl.java | 118 +++++ .../system/service/impl/MenuServiceImpl.java | 187 +++++++ .../service/impl/RoleMenuServiceImpl.java | 17 + .../system/service/impl/RoleServiceImpl.java | 152 ++++++ .../system/service/impl/UserServiceImpl.java | 159 ++++++ .../springblade/auth/system/vo/DictBizVO.java | 55 ++ .../springblade/auth/system/vo/MenuVO.java | 62 +++ .../auth/system/vo/RoleMenuVO.java | 19 + .../springblade/auth/system/vo/RoleVO.java | 72 +++ .../springblade/auth/system/vo/UserVO.java | 61 +++ .../auth/system/wrapper/DictBizWrapper.java | 45 ++ .../auth/system/wrapper/MenuWrapper.java | 64 +++ .../auth/system/wrapper/RoleWrapper.java | 45 ++ .../auth/system/wrapper/UserWrapper.java | 32 ++ .../org/springblade/auth/utils/TokenUtil.java | 153 ++++++ .../src/main/resources/application-dev.yml | 19 + .../src/main/resources/application-prod.yml | 18 + .../src/main/resources/application-test.yml | 18 + .../src/main/resources/application.yml | 34 ++ pom.xml | 6 + 71 files changed, 5717 insertions(+), 1 deletion(-) create mode 100644 kn-sys-manager/Dockerfile create mode 100644 kn-sys-manager/pom.xml create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/SystemManagerApplication.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/config/BladeAuthorizationServerConfiguration.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/config/BladeResourceServerConfiguration.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/config/JwtTokenStoreConfiguration.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/config/SecurityConfiguration.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/constant/AuthConstant.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/endpoint/BladeTokenEndPoint.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/granter/BladeTokenGranter.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/granter/CaptchaTokenGranter.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/service/BladeClientDetailsServiceImpl.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/service/BladeUserDetails.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/service/BladeUserDetailsServiceImpl.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/support/BladeJwtTokenEnhancer.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/support/BladeNoOpPasswordEncoder.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/support/BladePasswordEncoder.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/support/BladePasswordEncoderFactories.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/cache/DictBizCache.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/cache/SysCache.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/cache/UserCache.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/controller/DictBizController.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/controller/MenuController.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/controller/RoleController.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/controller/UserController.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/dto/MenuDTO.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/dto/RoleDTO.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/dto/RoleMenuDTO.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/entity/DictBiz.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/entity/Menu.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/entity/Role.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/entity/RoleMenu.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/entity/User.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/entity/UserInfo.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/enums/UserEnum.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/DictBizMapper.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/DictBizMapper.xml create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/MenuMapper.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/MenuMapper.xml create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMapper.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMapper.xml create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMenuMapper.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMenuMapper.xml create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/UserMapper.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/UserMapper.xml create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/service/IDictBizService.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/service/IMenuService.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/service/IRoleMenuService.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/service/IRoleService.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/service/IUserService.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/DictBizServiceImpl.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/MenuServiceImpl.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/RoleMenuServiceImpl.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/RoleServiceImpl.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/UserServiceImpl.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/vo/DictBizVO.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/vo/MenuVO.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/vo/RoleMenuVO.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/vo/RoleVO.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/vo/UserVO.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/DictBizWrapper.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/MenuWrapper.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/RoleWrapper.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/UserWrapper.java create mode 100644 kn-sys-manager/src/main/java/org/springblade/auth/utils/TokenUtil.java create mode 100644 kn-sys-manager/src/main/resources/application-dev.yml create mode 100644 kn-sys-manager/src/main/resources/application-prod.yml create mode 100644 kn-sys-manager/src/main/resources/application-test.yml create mode 100644 kn-sys-manager/src/main/resources/application.yml diff --git a/kn-common/src/main/java/org/springblade/common/constant/CommonConstant.java b/kn-common/src/main/java/org/springblade/common/constant/CommonConstant.java index a8c5697..fc583b4 100644 --- a/kn-common/src/main/java/org/springblade/common/constant/CommonConstant.java +++ b/kn-common/src/main/java/org/springblade/common/constant/CommonConstant.java @@ -52,5 +52,8 @@ public interface CommonConstant { */ String KN_VORDM_MODULE_NAME = "biz-vordm"; - + /** + * 系统管理模块 application name + */ + String KN_SYSTEM_MANAGER_MODULE_NAME = "system-manager"; } diff --git a/kn-sys-manager/Dockerfile b/kn-sys-manager/Dockerfile new file mode 100644 index 0000000..2dd5760 --- /dev/null +++ b/kn-sys-manager/Dockerfile @@ -0,0 +1,15 @@ +FROM bladex/alpine-java:openjdk8-openj9_cn_slim + +LABEL maintainer=whq<460794335@qq.com> + +RUN mkdir -p /kn/auth + +WORKDIR /kn/auth + +EXPOSE 8100 + +ADD ./target/kn-sys-manager.jar ./app.jar + +ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"] + +CMD ["--spring.profiles.active=test"] diff --git a/kn-sys-manager/pom.xml b/kn-sys-manager/pom.xml new file mode 100644 index 0000000..1461c52 --- /dev/null +++ b/kn-sys-manager/pom.xml @@ -0,0 +1,159 @@ + + + + 4.0.0 + + + com.kening.platform + kn-vordm + ${revision} + + + kn-sys-manager + ${project.artifactId} + ${revision} + jar + + + + com.alibaba + fastjson + 1.2.83 + + + com.kening.platform + kn-common + + + com.kening.platform + kn-launcher + + + org.springblade + blade-core-db + + + postgresql + org.postgresql + + + + + org.springblade + blade-starter-tenant + + + org.springblade + blade-starter-mybatis + + + org.javassist + javassist + 3.25.0-GA + + + + io.prometheus + simpleclient + 0.9.0 + + + org.springblade + blade-starter-cache + + + org.springblade + blade-core-cloud + + + HdrHistogram + org.hdrhistogram + + + javassist + org.javassist + + + simpleclient + io.prometheus + + + fastjson + com.alibaba + + + + + org.hdrhistogram + HdrHistogram + 2.1.12 + + + org.springblade + blade-starter-metrics + + + org.springblade + blade-starter-redis + + + javassist + org.javassist + + + + + org.springblade + blade-starter-swagger + + + org.springframework.cloud + spring-cloud-starter-security + + + org.springframework.security.oauth + spring-security-oauth2 + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.security + spring-security-jwt + + + + com.github.whvcse + easy-captcha + + + org.springblade + blade-core-boot + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + com.spotify + dockerfile-maven-plugin + + ${dockerfile.skip} + + + + + + diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/SystemManagerApplication.java b/kn-sys-manager/src/main/java/org/springblade/auth/SystemManagerApplication.java new file mode 100644 index 0000000..ec350bf --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/SystemManagerApplication.java @@ -0,0 +1,24 @@ +package org.springblade.auth; + + +import org.springblade.common.constant.CommonConstant; +import org.springblade.core.cloud.feign.EnableBladeFeign; +import org.springblade.core.launch.BladeApplication; +import org.springframework.cloud.client.SpringCloudApplication; +import org.springframework.context.annotation.ComponentScan; + +/** + * 用户认证服务器 + * + * @author Chill + */ +@EnableBladeFeign +@SpringCloudApplication +@ComponentScan({"org.springblade.auth"}) +public class SystemManagerApplication { + + public static void main(String[] args) { + BladeApplication.run(CommonConstant.KN_SYSTEM_MANAGER_MODULE_NAME, SystemManagerApplication.class, args); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/config/BladeAuthorizationServerConfiguration.java b/kn-sys-manager/src/main/java/org/springblade/auth/config/BladeAuthorizationServerConfiguration.java new file mode 100644 index 0000000..837d672 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/config/BladeAuthorizationServerConfiguration.java @@ -0,0 +1,91 @@ +package org.springblade.auth.config; + +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import org.springblade.auth.granter.BladeTokenGranter; +import org.springblade.auth.service.BladeClientDetailsServiceImpl; +import org.springblade.core.redis.cache.BladeRedis; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.core.userdetails.UserDetailsService; +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.TokenGranter; +import org.springframework.security.oauth2.provider.token.TokenEnhancer; +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 javax.sql.DataSource; +import java.util.ArrayList; +import java.util.List; + +/** + * 认证服务器配置 + * + * @author Chill + */ +@Order +@Configuration +@AllArgsConstructor +@EnableAuthorizationServer +public class BladeAuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { + + private final DataSource dataSource; + + private final AuthenticationManager authenticationManager; + + private final UserDetailsService userDetailsService; + + private final TokenStore tokenStore; + + private final TokenEnhancer jwtTokenEnhancer; + + private final JwtAccessTokenConverter jwtAccessTokenConverter; + + private final BladeRedis bladeRedis; + + @Override + public void configure(AuthorizationServerEndpointsConfigurer endpoints) { + //获取自定义tokenGranter + TokenGranter tokenGranter = BladeTokenGranter.getTokenGranter(authenticationManager, endpoints, bladeRedis); + + //配置端点 + endpoints.tokenStore(tokenStore) + .authenticationManager(authenticationManager) + .userDetailsService(userDetailsService) + .tokenGranter(tokenGranter); + + //扩展token返回结果 + if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) { + TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); + List enhancerList = new ArrayList<>(); + enhancerList.add(jwtTokenEnhancer); + enhancerList.add(jwtAccessTokenConverter); + tokenEnhancerChain.setTokenEnhancers(enhancerList); + //jwt增强 + endpoints.tokenEnhancer(tokenEnhancerChain).accessTokenConverter(jwtAccessTokenConverter); + } + } + + /** + * 配置客户端信息 + */ + @Override + @SneakyThrows + public void configure(ClientDetailsServiceConfigurer clients) { + clients.withClientDetails(new BladeClientDetailsServiceImpl(dataSource)); + } + + @Override + public void configure(AuthorizationServerSecurityConfigurer oauthServer) { + oauthServer + .allowFormAuthenticationForClients() + .tokenKeyAccess("permitAll()") + .checkTokenAccess("isAuthenticated()"); + } +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/config/BladeResourceServerConfiguration.java b/kn-sys-manager/src/main/java/org/springblade/auth/config/BladeResourceServerConfiguration.java new file mode 100644 index 0000000..d67ae82 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/config/BladeResourceServerConfiguration.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.config; + +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +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; + +/** + * 自定义登录成功配置 + * + * @author Chill + */ +@Configuration +@AllArgsConstructor +@EnableResourceServer +public class BladeResourceServerConfiguration extends ResourceServerConfigurerAdapter { + + @Override + @SneakyThrows + public void configure(HttpSecurity http) { + http.headers().frameOptions().disable(); + http.formLogin() + .and() + .authorizeRequests() + .antMatchers( + "/actuator/**", + "/oauth/captcha", + "/oauth/logout", + "/oauth/mobile", + "/oauth/clear-cache", + "/oauth/render/**", + "/oauth/callback/**", + "/oauth/revoke/**", + "/oauth/refresh/**", + "/token/**", + "/user/**", + "/role/**", + "/menu/**", + "/dict-biz", + "/v2/api-docs").permitAll() + .anyRequest().authenticated().and() + .csrf().disable(); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/config/JwtTokenStoreConfiguration.java b/kn-sys-manager/src/main/java/org/springblade/auth/config/JwtTokenStoreConfiguration.java new file mode 100644 index 0000000..f7a00a8 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/config/JwtTokenStoreConfiguration.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.config; + +import org.springblade.auth.support.BladeJwtTokenEnhancer; +import org.springblade.core.jwt.props.JwtProperties; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.provider.token.TokenEnhancer; +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; + +/** + * JwtTokenStore + * + * @author Chill + */ +@Configuration +@ConditionalOnProperty(prefix = "blade.security.oauth2", name = "storeType", havingValue = "jwt", matchIfMissing = true) +public class JwtTokenStoreConfiguration { + + /** + * 使用jwtTokenStore存储token + */ + @Bean + public TokenStore jwtTokenStore(JwtProperties jwtProperties) { + return new JwtTokenStore(jwtAccessTokenConverter(jwtProperties)); + } + + /** + * 用于生成jwt + */ + @Bean + public JwtAccessTokenConverter jwtAccessTokenConverter(JwtProperties jwtProperties) { + JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter(); + accessTokenConverter.setSigningKey(jwtProperties.getSignKey()); + return accessTokenConverter; + } + + /** + * 用于扩展jwt + */ + @Bean + @ConditionalOnMissingBean(name = "jwtTokenEnhancer") + public TokenEnhancer jwtTokenEnhancer(JwtAccessTokenConverter jwtAccessTokenConverter, JwtProperties jwtProperties) { + return new BladeJwtTokenEnhancer(jwtAccessTokenConverter, jwtProperties); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/config/SecurityConfiguration.java b/kn-sys-manager/src/main/java/org/springblade/auth/config/SecurityConfiguration.java new file mode 100644 index 0000000..41bfb46 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/config/SecurityConfiguration.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.config; + +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import org.springblade.auth.support.BladePasswordEncoderFactories; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * Security配置 + * + * @author Chill + */ +@Configuration +@AllArgsConstructor +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Bean + @Override + @SneakyThrows + public AuthenticationManager authenticationManagerBean() { + return super.authenticationManagerBean(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return BladePasswordEncoderFactories.createDelegatingPasswordEncoder(); + } + + @Override + @SneakyThrows + protected void configure(HttpSecurity http) { + http.httpBasic().and().csrf().disable().authorizeRequests().anyRequest().fullyAuthenticated(); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/constant/AuthConstant.java b/kn-sys-manager/src/main/java/org/springblade/auth/constant/AuthConstant.java new file mode 100644 index 0000000..3f5edae --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/constant/AuthConstant.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.constant; + +/** + * 授权校验常量 + * + * @author Chill + */ +public interface AuthConstant { + + /** + * 密码加密规则 + */ + String ENCRYPT = "{blade}"; + + /** + * blade_client表字段 + */ + String CLIENT_FIELDS = "client_id, CONCAT('{noop}',client_secret) as client_secret, resource_ids, scope, authorized_grant_types, " + + "web_server_redirect_uri, authorities, access_token_validity, " + + "refresh_token_validity, additional_information, autoapprove"; + + /** + * blade_client查询语句 + */ + String BASE_STATEMENT = "select " + CLIENT_FIELDS + " from blade_client"; + + /** + * blade_client查询排序 + */ + String DEFAULT_FIND_STATEMENT = BASE_STATEMENT + " order by client_id"; + + /** + * 查询client_id + */ + String DEFAULT_SELECT_STATEMENT = BASE_STATEMENT + " where client_id = ?"; + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/endpoint/BladeTokenEndPoint.java b/kn-sys-manager/src/main/java/org/springblade/auth/endpoint/BladeTokenEndPoint.java new file mode 100644 index 0000000..0b41aa8 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/endpoint/BladeTokenEndPoint.java @@ -0,0 +1,93 @@ +package org.springblade.auth.endpoint; + +import com.wf.captcha.SpecCaptcha; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springblade.common.cache.CacheNames; +import org.springblade.core.cache.utils.CacheUtil; +import org.springblade.core.jwt.JwtUtil; +import org.springblade.core.jwt.props.JwtProperties; +import org.springblade.core.launch.constant.TokenConstant; +import org.springblade.core.redis.cache.BladeRedis; +import org.springblade.core.secure.BladeUser; +import org.springblade.core.secure.utils.AuthUtil; +import org.springblade.core.tenant.annotation.NonDS; +import org.springblade.core.tool.api.R; +import org.springblade.core.tool.support.Kv; +import org.springblade.core.tool.utils.StringUtil; +import org.springblade.core.tool.utils.WebUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.Duration; + +import static org.springblade.core.cache.constant.CacheConstant.*; + +/** + * BladeEndPoint + * + * @author Chill + */ +@NonDS +@Slf4j +@RestController +@RequiredArgsConstructor +public class BladeTokenEndPoint { + + private final BladeRedis bladeRedis; + private final JwtProperties jwtProperties; + @Value("${captcha.image.width:130}") + private Integer imageWidth; + @Value("${captcha.image.height:48}") + private Integer imageHeight; + @Value("${captcha.image.code.length:5}") + private Integer codeLength; + @Value("${captcha.image.code.time:30}") + private Integer codeValidateTime; + + @GetMapping("/oauth/user-info") + public R currentUser(Authentication authentication) { + return R.data(authentication); + } + + @GetMapping("/oauth/captcha") + public Kv captcha() { + SpecCaptcha specCaptcha = new SpecCaptcha(imageWidth, imageHeight, codeLength); + String verCode = specCaptcha.text().toLowerCase(); + String key = StringUtil.randomUUID(); + // 存入redis并设置过期时间为30分钟 + bladeRedis.setEx(CacheNames.CAPTCHA_KEY + key, verCode, Duration.ofMinutes(codeValidateTime)); + // 将key和base64返回给前端 + return Kv.create().set("key", key).set("image", specCaptcha.toBase64()); + } + + @GetMapping("/oauth/logout") + public Kv logout() { + BladeUser user = AuthUtil.getUser(); + if (user != null && jwtProperties.getState()) { + String token = JwtUtil.getToken(WebUtil.getRequest().getHeader(TokenConstant.HEADER)); + JwtUtil.removeAccessToken(user.getTenantId(), String.valueOf(user.getUserId()), token); + } + return Kv.create().set("success", "true").set("msg", "success"); + } + + @GetMapping("/oauth/clear-cache") + public Kv clearCache() { + CacheUtil.clear(BIZ_CACHE); + CacheUtil.clear(USER_CACHE); + CacheUtil.clear(DICT_CACHE); + CacheUtil.clear(FLOW_CACHE); + CacheUtil.clear(SYS_CACHE); + CacheUtil.clear(PARAM_CACHE); + CacheUtil.clear(RESOURCE_CACHE); + CacheUtil.clear(MENU_CACHE); + CacheUtil.clear(DICT_CACHE, Boolean.FALSE); + CacheUtil.clear(MENU_CACHE, Boolean.FALSE); + CacheUtil.clear(SYS_CACHE, Boolean.FALSE); + CacheUtil.clear(PARAM_CACHE, Boolean.FALSE); + return Kv.create().set("success", "true").set("msg", "success"); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/granter/BladeTokenGranter.java b/kn-sys-manager/src/main/java/org/springblade/auth/granter/BladeTokenGranter.java new file mode 100644 index 0000000..8c1fa08 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/granter/BladeTokenGranter.java @@ -0,0 +1,33 @@ +package org.springblade.auth.granter; + +import org.springblade.core.redis.cache.BladeRedis; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; +import org.springframework.security.oauth2.provider.CompositeTokenGranter; +import org.springframework.security.oauth2.provider.TokenGranter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 自定义拓展TokenGranter + * + * @author Chill + */ +public class BladeTokenGranter { + + /** + * 自定义tokenGranter + */ + public static TokenGranter getTokenGranter(final AuthenticationManager authenticationManager, + final AuthorizationServerEndpointsConfigurer endpoints, + BladeRedis bladeRedis) { + // 默认tokenGranter集合 + List granters = new ArrayList<>(Collections.singletonList(endpoints.getTokenGranter())); + // 增加验证码模式 + granters.add(new CaptchaTokenGranter(authenticationManager, endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), bladeRedis)); + return new CompositeTokenGranter(granters); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/granter/CaptchaTokenGranter.java b/kn-sys-manager/src/main/java/org/springblade/auth/granter/CaptchaTokenGranter.java new file mode 100644 index 0000000..4f33384 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/granter/CaptchaTokenGranter.java @@ -0,0 +1,82 @@ +package org.springblade.auth.granter; + +import org.springblade.auth.utils.TokenUtil; +import org.springblade.common.cache.CacheNames; +import org.springblade.core.redis.cache.BladeRedis; +import org.springblade.core.tool.utils.StringUtil; +import org.springblade.core.tool.utils.WebUtil; +import org.springframework.security.authentication.*; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; +import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException; +import org.springframework.security.oauth2.provider.*; +import org.springframework.security.oauth2.provider.token.AbstractTokenGranter; +import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; + +import javax.servlet.http.HttpServletRequest; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 验证码TokenGranter + * + * @author Chill + */ +public class CaptchaTokenGranter extends AbstractTokenGranter { + + private static final String GRANT_TYPE = "captcha"; + + private final AuthenticationManager authenticationManager; + + private BladeRedis bladeRedis; + + public CaptchaTokenGranter(AuthenticationManager authenticationManager, + AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, BladeRedis bladeRedis) { + this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE); + this.bladeRedis = bladeRedis; + } + + protected CaptchaTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices, + ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) { + super(tokenServices, clientDetailsService, requestFactory, grantType); + this.authenticationManager = authenticationManager; + } + + @Override + protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) { + HttpServletRequest request = WebUtil.getRequest(); + // 增加验证码判断 + String key = request.getHeader(TokenUtil.CAPTCHA_HEADER_KEY); + String code = request.getHeader(TokenUtil.CAPTCHA_HEADER_CODE); + // 获取验证码 + String redisCode = bladeRedis.get(CacheNames.CAPTCHA_KEY + key); + // 判断验证码 + if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) { + throw new UserDeniedAuthorizationException(TokenUtil.CAPTCHA_NOT_CORRECT); + } + + Map parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters()); + String username = parameters.get("username"); + String password = parameters.get("password"); + // Protect from downstream leaks of password + parameters.remove("password"); + + Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password); + ((AbstractAuthenticationToken) userAuth).setDetails(parameters); + try { + userAuth = authenticationManager.authenticate(userAuth); + } + catch (AccountStatusException | BadCredentialsException ase) { + //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31) + throw new InvalidGrantException(ase.getMessage()); + } + // If the username/password are wrong the spec says we should send 400/invalid grant + + if (userAuth == null || !userAuth.isAuthenticated()) { + throw new InvalidGrantException("Could not authenticate user: " + username); + } + + OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); + return new OAuth2Authentication(storedOAuth2Request, userAuth); + } +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/service/BladeClientDetailsServiceImpl.java b/kn-sys-manager/src/main/java/org/springblade/auth/service/BladeClientDetailsServiceImpl.java new file mode 100644 index 0000000..7bc66f6 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/service/BladeClientDetailsServiceImpl.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.service; + +import org.springblade.auth.constant.AuthConstant; +import org.springframework.security.oauth2.provider.ClientDetails; +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; + +/** + * 客户端信息 + * + * @author Chill + */ +@Component +public class BladeClientDetailsServiceImpl extends JdbcClientDetailsService { + + public BladeClientDetailsServiceImpl(DataSource dataSource) { + super(dataSource); + setSelectClientDetailsSql(AuthConstant.DEFAULT_SELECT_STATEMENT); + setFindClientDetailsSql(AuthConstant.DEFAULT_FIND_STATEMENT); + } + + /** + * 缓存客户端信息 + * + * @param clientId 客户端id + */ + @Override + public ClientDetails loadClientByClientId(String clientId) { + try { + return super.loadClientByClientId(clientId); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/service/BladeUserDetails.java b/kn-sys-manager/src/main/java/org/springblade/auth/service/BladeUserDetails.java new file mode 100644 index 0000000..e4135e0 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/service/BladeUserDetails.java @@ -0,0 +1,93 @@ +package org.springblade.auth.service; + +import lombok.Getter; +import org.springblade.core.tool.support.Kv; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.User; + +import java.util.Collection; + +/** + * 用户信息拓展 + * + * @author whq + */ +@Getter +public class BladeUserDetails extends User { + + /** + * 用户id + */ + private final Long userId; + + private final String email; + + /** + * 租户ID + */ + private final String tenantId; + + /** + * 第三方认证ID + */ + private final String oauthId; + /** + * 昵称 + */ + private final String name; + /** + * 真名 + */ + private final String realName; + /** + * 账号 + */ + private final String account; + /** + * 部门id + */ + private final String deptId; + /** + * 岗位id + */ + private final String postId; + /** + * 角色id + */ + private final String roleId; + /** + * 角色名 + */ + private final String roleName; + /** + * 头像 + */ + private final String avatar; + /** + * 用户详情 + */ + private final Kv detail; + + public BladeUserDetails(Long userId, String email, + String tenantId, String oauthId, String name, + String realName, String deptId, String postId, String roleId, + String roleName, String avatar, String username, String password, Kv detail, + boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, + boolean accountNonLocked, Collection authorities) { + super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); + this.userId = userId; + this.email = email; + this.tenantId = tenantId; + this.oauthId = oauthId; + this.name = name; + this.realName = realName; + this.account = username; + this.deptId = deptId; + this.postId = postId; + this.roleId = roleId; + this.roleName = roleName; + this.avatar = avatar; + this.detail = detail; + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/service/BladeUserDetailsServiceImpl.java b/kn-sys-manager/src/main/java/org/springblade/auth/service/BladeUserDetailsServiceImpl.java new file mode 100644 index 0000000..459011e --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/service/BladeUserDetailsServiceImpl.java @@ -0,0 +1,124 @@ +package org.springblade.auth.service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import org.apache.commons.lang.StringUtils; +import org.springblade.auth.constant.AuthConstant; +import org.springblade.auth.system.cache.SysCache; +import org.springblade.auth.system.cache.UserCache; +import org.springblade.auth.system.entity.User; +import org.springblade.auth.system.entity.UserInfo; +import org.springblade.auth.utils.TokenUtil; +import org.springblade.common.cache.CacheNames; +import org.springblade.core.redis.cache.BladeRedis; +import org.springblade.core.tool.utils.DigestUtil; +import org.springblade.core.tool.utils.Func; +import org.springblade.core.tool.utils.StringPool; +import org.springblade.core.tool.utils.StringUtil; +import org.springblade.core.tool.utils.WebUtil; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.time.Duration; +import java.util.List; + +/** + * 用户信息 + * + * @author whq + */ +@Service +@AllArgsConstructor +public class BladeUserDetailsServiceImpl implements UserDetailsService { + + public static final Integer FAIL_COUNT = 5; + + private final BladeRedis bladeRedis; + + @Override + @SneakyThrows + public BladeUserDetails loadUserByUsername(String username) { + HttpServletRequest request = WebUtil.getRequest(); + // 获取用户绑定ID + String headerDept = request.getHeader(TokenUtil.DEPT_HEADER_KEY); + String headerRole = request.getHeader(TokenUtil.ROLE_HEADER_KEY); + // 获取租户ID + String headerTenant = request.getHeader(TokenUtil.TENANT_HEADER_KEY); + String paramTenant = request.getParameter(TokenUtil.TENANT_PARAM_KEY); + String password = request.getParameter(TokenUtil.PASSWORD_KEY); + String grantType = request.getParameter(TokenUtil.GRANT_TYPE_KEY); + if (StringUtil.isAllBlank(headerTenant, paramTenant)) { + throw new UserDeniedAuthorizationException(TokenUtil.TENANT_NOT_FOUND); + } + String tenantId = StringUtils.isBlank(headerTenant) ? paramTenant : headerTenant; + + // 判断登录是否锁定 + // 新版本将增加:1.参数管理读取配置 2.用户管理增加解封按钮 + int count = getFailCount(tenantId, username); + if (count >= FAIL_COUNT) { + throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_TOO_MANY_FAILS); + } + + // 获取用户类型 + String userType = Func.toStr(request.getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE); + + // 远程调用返回数据 + UserInfo userInfo = UserCache.getUser(tenantId, username); + User user = userInfo.getUser(); + // 判断返回信息 + // 用户不存在,但提示用户名与密码错误并锁定账号 + if (user == null || user.getId() == null) { + setFailCount(tenantId, username, count); + throw new UsernameNotFoundException(TokenUtil.USER_NOT_FOUND); + } + // 用户存在但密码错误,超过次数则锁定账号 + if (!grantType.equals(TokenUtil.REFRESH_TOKEN_KEY) && !user.getPassword().equals(DigestUtil.hex(password))) { + setFailCount(tenantId, username, count); + throw new UsernameNotFoundException(TokenUtil.USER_NOT_FOUND); + } + // 用户角色不存在 + if (Func.isEmpty(userInfo.getRoles())) { + throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_NO_ROLE); + } + // 多角色情况下指定单角色 + if (Func.isNotEmpty(headerRole) && user.getRoleId().contains(headerRole)) { + List roleResult = SysCache.getRoleAliases(headerRole); + userInfo.setRoles(roleResult); + user.setRoleId(headerRole); + } + return new BladeUserDetails(user.getId(), user.getEmail(), + user.getTenantId(), StringPool.EMPTY, user.getName(), user.getRealName(), user.getDeptId(), user.getPostId(), user.getRoleId(), Func.join(userInfo.getRoles()), Func.toStr(user.getAvatar(), TokenUtil.DEFAULT_AVATAR), + username, AuthConstant.ENCRYPT + user.getPassword(), userInfo.getDetail(), true, true, true, true, + AuthorityUtils.commaSeparatedStringToAuthorityList(Func.join(userInfo.getRoles()))); + } + + /** + * 获取账号错误次数 + * + * @param tenantId 租户id + * @param username 账号 + * @return int + */ + private int getFailCount(String tenantId, String username) { + return Func.toInt(bladeRedis.get(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username)), 0); + } + + /** + * 设置账号错误次数 + * + * @param tenantId 租户id + * @param username 账号 + * @param count 次数 + */ + private void setFailCount(String tenantId, String username, int count) { + bladeRedis.setEx(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username), count + 1, Duration.ofMinutes(30)); + } + + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/support/BladeJwtTokenEnhancer.java b/kn-sys-manager/src/main/java/org/springblade/auth/support/BladeJwtTokenEnhancer.java new file mode 100644 index 0000000..fa39f83 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/support/BladeJwtTokenEnhancer.java @@ -0,0 +1,60 @@ +package org.springblade.auth.support; + +import lombok.RequiredArgsConstructor; +import org.springblade.auth.service.BladeUserDetails; +import org.springblade.auth.utils.TokenUtil; +import org.springblade.core.jwt.JwtUtil; +import org.springblade.core.jwt.props.JwtProperties; +import org.springblade.core.tool.utils.Func; +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 org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; + +import java.util.HashMap; +import java.util.Map; + +/** + * jwt返回参数增强 + * + * @author Chill + */ +@RequiredArgsConstructor +public class BladeJwtTokenEnhancer implements TokenEnhancer { + + private final JwtAccessTokenConverter jwtAccessTokenConverter; + private final JwtProperties jwtProperties; + + @Override + public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { + BladeUserDetails principal = (BladeUserDetails) authentication.getUserAuthentication().getPrincipal(); + //token参数增强 + Map info = new HashMap<>(16); + info.put(TokenUtil.CLIENT_ID, TokenUtil.getClientIdFromHeader()); + info.put(TokenUtil.USER_ID, Func.toStr(principal.getUserId())); + info.put(TokenUtil.DEPT_ID, Func.toStr(principal.getDeptId())); + //info.put(TokenUtil.POST_ID, Func.toStr(principal.getPostId())); + info.put(TokenUtil.ROLE_ID, Func.toStr(principal.getRoleId())); + info.put(TokenUtil.TENANT_ID, principal.getTenantId()); + info.put(TokenUtil.EMAIL, principal.getEmail()); + //info.put(TokenUtil.OAUTH_ID, principal.getOauthId()); + info.put(TokenUtil.ACCOUNT, principal.getAccount()); + info.put(TokenUtil.USER_NAME, principal.getUsername()); + info.put(TokenUtil.NICK_NAME, principal.getName()); + info.put(TokenUtil.REAL_NAME, principal.getRealName()); + info.put(TokenUtil.ROLE_NAME, principal.getRoleName()); + info.put(TokenUtil.AVATAR, principal.getAvatar()); + info.put(TokenUtil.DETAIL, principal.getDetail()); + ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info); + //token状态设置, 有状态,默认无状态 + if (jwtProperties.getState()) { + OAuth2AccessToken oAuth2AccessToken = jwtAccessTokenConverter.enhance(accessToken, authentication); + String tokenValue = oAuth2AccessToken.getValue(); + String tenantId = principal.getTenantId(); + String userId = Func.toStr(principal.getUserId()); + JwtUtil.addAccessToken(tenantId, userId, tokenValue, accessToken.getExpiresIn()); + } + return accessToken; + } +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/support/BladeNoOpPasswordEncoder.java b/kn-sys-manager/src/main/java/org/springblade/auth/support/BladeNoOpPasswordEncoder.java new file mode 100644 index 0000000..9210fb8 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/support/BladeNoOpPasswordEncoder.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.support; + +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * 无密码加密 + * + * @author Chill + */ +public class BladeNoOpPasswordEncoder implements PasswordEncoder { + + @Override + public String encode(CharSequence rawPassword) { + return rawPassword.toString(); + } + + @Override + public boolean matches(CharSequence rawPassword, String encodedPassword) { + return rawPassword.toString().equals(encodedPassword); + } + + /** + * Get the singleton {@link BladeNoOpPasswordEncoder}. + */ + public static PasswordEncoder getInstance() { + return INSTANCE; + } + + private static final PasswordEncoder INSTANCE = new BladeNoOpPasswordEncoder(); + + private BladeNoOpPasswordEncoder() { + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/support/BladePasswordEncoder.java b/kn-sys-manager/src/main/java/org/springblade/auth/support/BladePasswordEncoder.java new file mode 100644 index 0000000..c226b93 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/support/BladePasswordEncoder.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.support; + +import org.springblade.core.tool.utils.DigestUtil; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * 自定义密码加密 + * + * @author Chill + */ +public class BladePasswordEncoder implements PasswordEncoder { + + @Override + public String encode(CharSequence rawPassword) { + return DigestUtil.hex((String) rawPassword); + } + + @Override + public boolean matches(CharSequence rawPassword, String encodedPassword) { + return encodedPassword.equals(encode(rawPassword)); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/support/BladePasswordEncoderFactories.java b/kn-sys-manager/src/main/java/org/springblade/auth/support/BladePasswordEncoderFactories.java new file mode 100644 index 0000000..664b0ba --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/support/BladePasswordEncoderFactories.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springblade.auth.support; + +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.DelegatingPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder; +import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder; + +import java.util.HashMap; +import java.util.Map; + +/** + * 自定义密码工厂 + * + * @author Rob Winch, Chill + * @since 5.0 + */ +public class BladePasswordEncoderFactories { + + /** + * Creates a {@link DelegatingPasswordEncoder} with default mappings. Additional + * mappings may be added and the encoding will be updated to conform with best + * practices. However, due to the nature of {@link DelegatingPasswordEncoder} the + * updates should not impact users. The mappings current are: + * + *
    + *
  • blade - {@link BladePasswordEncoder} (sha1(md5("password")))
  • + *
  • bcrypt - {@link BCryptPasswordEncoder} (Also used for encoding)
  • + *
  • noop - {@link BladeNoOpPasswordEncoder}
  • + *
  • pbkdf2 - {@link Pbkdf2PasswordEncoder}
  • + *
  • scrypt - {@link SCryptPasswordEncoder}
  • + *
+ * + * @return the {@link PasswordEncoder} to use + */ + public static PasswordEncoder createDelegatingPasswordEncoder() { + String encodingId = "blade"; + Map encoders = new HashMap<>(16); + encoders.put(encodingId, new BladePasswordEncoder()); + encoders.put("bcrypt", new BCryptPasswordEncoder()); + encoders.put("noop", BladeNoOpPasswordEncoder.getInstance()); + encoders.put("pbkdf2", new Pbkdf2PasswordEncoder()); + encoders.put("scrypt", new SCryptPasswordEncoder()); + + return new DelegatingPasswordEncoder(encodingId, encoders); + } + + private BladePasswordEncoderFactories() { + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/cache/DictBizCache.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/cache/DictBizCache.java new file mode 100644 index 0000000..3fc68b5 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/cache/DictBizCache.java @@ -0,0 +1,89 @@ +package org.springblade.auth.system.cache; + +import org.springblade.auth.system.service.IDictBizService; +import org.springblade.core.cache.utils.CacheUtil; +import org.springblade.core.secure.utils.AuthUtil; +import org.springblade.core.tool.utils.SpringUtil; +import org.springblade.core.tool.utils.StringPool; +import org.springblade.auth.system.entity.DictBiz; + +import java.util.List; + +import static org.springblade.core.cache.constant.CacheConstant.DICT_CACHE; + +/** + * 业务字典缓存工具类 + * + * @author Chill + */ +public class DictBizCache { + + private static final String DICT_ID = "dictBiz:id"; + private static final String DICT_VALUE = "dictBiz:value"; + private static final String DICT_LIST = "dictBiz:list"; + + private static IDictBizService dictClient; + + private static IDictBizService getDictClient() { + if (dictClient == null) { + dictClient = SpringUtil.getBean(IDictBizService.class); + } + return dictClient; + } + + /** + * 获取字典实体 + * + * @param id 主键 + * @return DictBiz + */ + public static DictBiz getById(Long id) { + String keyPrefix = DICT_ID.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON); + return CacheUtil.get(DICT_CACHE, keyPrefix, id, () -> { + return getDictClient().getById(id); + }); + } + + + /** + * 获取字典值 + * + * @param code 字典编号 + * @param dictKey Integer型字典键 + * @return String + */ + public static String getValue(String code, Integer dictKey) { + String keyPrefix = DICT_VALUE.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON); + return CacheUtil.get(DICT_CACHE, keyPrefix + code + StringPool.COLON, String.valueOf(dictKey), () -> { + return getDictClient().getValue(code, String.valueOf(dictKey)); + }); + } + + /** + * 获取字典值 + * + * @param code 字典编号 + * @param dictKey String型字典键 + * @return String + */ + public static String getValue(String code, String dictKey) { + String keyPrefix = DICT_VALUE.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON); + return CacheUtil.get(DICT_CACHE, keyPrefix + code + StringPool.COLON, dictKey, () -> { + return getDictClient().getValue(code, dictKey); + }); + } + + /** + * 获取字典集合 + * + * @param code 字典编号 + * @return List + */ + public static List getList(String code) { + String keyPrefix = DICT_LIST.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON); + return CacheUtil.get(DICT_CACHE, keyPrefix, code, () -> { + return getDictClient().getList(code); + }); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/cache/SysCache.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/cache/SysCache.java new file mode 100644 index 0000000..24b00ed --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/cache/SysCache.java @@ -0,0 +1,116 @@ +package org.springblade.auth.system.cache; + +import org.springblade.auth.system.entity.Menu; +import org.springblade.auth.system.entity.Role; +import org.springblade.auth.system.service.IMenuService; +import org.springblade.auth.system.service.IRoleService; +import org.springblade.core.cache.utils.CacheUtil; +import org.springblade.core.tool.utils.SpringUtil; +import org.springblade.core.tool.utils.StringPool; + +import java.util.List; + +import static org.springblade.core.cache.constant.CacheConstant.SYS_CACHE; + +/** + * 系统缓存 + * + * @author Chill + */ +public class SysCache { + private static final String MENU_ID = "menu:id:"; + private static final String ROLE_ID = "role:id:"; + private static final String ROLE_NAME = "role:name:"; + private static final String ROLE_NAME_ID = "roleName:id:"; + private static final String ROLE_NAMES_ID = "roleNames:id:"; + private static final String ROLE_ALIAS_ID = "roleAlias:id:"; + private static final String ROLE_ALIASES_ID = "roleAliases:id:"; + + private static IMenuService menuService; + private static IRoleService roleService; + + private static IMenuService getSysClient() { + if (menuService == null) { + menuService = SpringUtil.getBean(IMenuService.class); + } + return menuService; + } + + private static IRoleService getRoleClient() { + if (roleService == null) { + roleService = SpringUtil.getBean(IRoleService.class); + } + return roleService; + } + + /** + * 获取菜单 + * + * @param id 主键 + * @return 菜单 + */ + public static Menu getMenu(Long id) { + return CacheUtil.get(SYS_CACHE, MENU_ID, id, () -> getSysClient().getById(id)); + } + /** + * 获取角色 + * + * @param id 主键 + * @return Role + */ + public static Role getRole(Long id) { + return CacheUtil.get(SYS_CACHE, ROLE_ID, id, () -> getRoleClient().getById(id)); + } + + /** + * 获取角色id + * + * @param tenantId 租户id + * @param roleNames 角色名 + * @return + */ + public static String getRoleIds(String tenantId, String roleNames) { + return CacheUtil.get(SYS_CACHE, ROLE_NAME, tenantId + StringPool.DASH + roleNames, () -> getRoleClient().getRoleIds(tenantId, roleNames)); + } + + /** + * 获取角色名 + * + * @param id 主键 + * @return 角色名 + */ + public static String getRoleName(Long id) { + return CacheUtil.get(SYS_CACHE, ROLE_NAME_ID, id, () -> getRoleClient().getById(id).getRoleName()); + } + + /** + * 获取角色别名 + * + * @param id 主键 + * @return 角色别名 + */ + public static String getRoleAlias(Long id) { + return CacheUtil.get(SYS_CACHE, ROLE_ALIAS_ID, id, () -> getRoleClient().getById(id).getRoleAlias()); + } + + /** + * 获取角色名集合 + * + * @param roleIds 主键集合 + * @return 角色名 + */ + public static List getRoleNames(String roleIds) { + return CacheUtil.get(SYS_CACHE, ROLE_NAMES_ID, roleIds, () -> getRoleClient().getRoleNames(roleIds)); + } + + /** + * 获取角色别名集合 + * + * @param roleIds 主键集合 + * @return 角色别名 + */ + public static List getRoleAliases(String roleIds) { + return CacheUtil.get(SYS_CACHE, ROLE_ALIASES_ID, roleIds, () -> getRoleClient().getRoleAliases(roleIds)); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/cache/UserCache.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/cache/UserCache.java new file mode 100644 index 0000000..ac81ec6 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/cache/UserCache.java @@ -0,0 +1,65 @@ +package org.springblade.auth.system.cache; + +import org.springblade.auth.system.entity.User; +import org.springblade.auth.system.entity.UserInfo; +import org.springblade.auth.system.service.IUserService; +import org.springblade.core.cache.utils.CacheUtil; +import org.springblade.core.tool.utils.Func; +import org.springblade.core.tool.utils.SpringUtil; +import org.springblade.core.tool.utils.StringPool; +import org.springblade.core.tool.utils.StringUtil; + +import static org.springblade.core.cache.constant.CacheConstant.USER_CACHE; +import static org.springblade.core.launch.constant.FlowConstant.TASK_USR_PREFIX; + +/** + * 系统缓存 + * + * @author Chill + */ +public class UserCache { + private static final String USER_CACHE_ID = "user:id:"; + private static final String USER_CACHE_ACCOUNT = "user:account:"; + + private static IUserService userClient; + + private static IUserService getUserClient() { + if (userClient == null) { + userClient = SpringUtil.getBean(IUserService.class); + } + return userClient; + } + + /** + * 根据任务用户id获取用户信息 + * + * @param taskUserId 任务用户id + * @return + */ + public static User getUserByTaskUser(String taskUserId) { + Long userId = Func.toLong(StringUtil.removePrefix(taskUserId, TASK_USR_PREFIX)); + return getUser(userId); + } + + /** + * 获取用户 + * + * @param userId 用户id + * @return + */ + public static User getUser(Long userId) { + return CacheUtil.get(USER_CACHE, USER_CACHE_ID, userId, () -> getUserClient().getById(userId)); + } + + /** + * 获取用户 + * + * @param tenantId 租户id + * @param account 账号名 + * @return + */ + public static UserInfo getUser(String tenantId, String account) { + return CacheUtil.get(USER_CACHE, USER_CACHE_ACCOUNT, tenantId + StringPool.DASH + account, () -> getUserClient().userInfo(tenantId, account)); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/DictBizController.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/DictBizController.java new file mode 100644 index 0000000..2c40fbb --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/DictBizController.java @@ -0,0 +1,171 @@ +package org.springblade.auth.system.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.AllArgsConstructor; +import org.springblade.auth.system.entity.DictBiz; +import org.springblade.auth.system.service.IDictBizService; +import org.springblade.auth.system.vo.DictBizVO; +import org.springblade.auth.system.wrapper.DictBizWrapper; +import org.springblade.core.cache.utils.CacheUtil; +import org.springblade.core.mp.support.Condition; +import org.springblade.core.mp.support.Query; +import org.springblade.core.tenant.annotation.NonDS; +import org.springblade.core.tool.api.R; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import springfox.documentation.annotations.ApiIgnore; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +import static org.springblade.core.cache.constant.CacheConstant.DICT_CACHE; + +/** + * 控制器 + * + * @author Chill + */ +@NonDS +@RestController +@AllArgsConstructor +@RequestMapping("/dict-biz") +@Api(value = "业务字典", tags = "业务字典") +public class DictBizController { + + private final IDictBizService dictService; + + /** + * 详情 + */ + @GetMapping("/detail") + @ApiOperationSupport(order = 1) + @ApiOperation(value = "详情", notes = "传入dict") + public R detail(DictBiz dict) { + DictBiz detail = dictService.getOne(Condition.getQueryWrapper(dict)); + return R.data(DictBizWrapper.build().entityVO(detail)); + } + + /** + * 列表 + */ + @GetMapping("/list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "code", value = "字典编号", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "dictValue", value = "字典名称", paramType = "query", dataType = "string") + }) + @ApiOperationSupport(order = 2) + @ApiOperation(value = "列表", notes = "传入dict") + public R> list(@ApiIgnore @RequestParam Map dict) { + List list = dictService.list(Condition.getQueryWrapper(dict, DictBiz.class).lambda().orderByAsc(DictBiz::getSort)); + return R.data(DictBizWrapper.build().listNodeVO(list)); + } + + /** + * 顶级列表 + */ + @GetMapping("/parent-list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "code", value = "字典编号", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "dictValue", value = "字典名称", paramType = "query", dataType = "string") + }) + @ApiOperationSupport(order = 3) + @ApiOperation(value = "列表", notes = "传入dict") + public R> parentList(@ApiIgnore @RequestParam Map dict, Query query) { + return R.data(dictService.parentList(dict, query)); + } + + /** + * 子列表 + */ + @GetMapping("/child-list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "code", value = "字典编号", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "dictValue", value = "字典名称", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "parentId", value = "字典名称", paramType = "query", dataType = "string") + }) + @ApiOperationSupport(order = 4) + @ApiOperation(value = "列表", notes = "传入dict") + public R> childList(@ApiIgnore @RequestParam Map dict, @RequestParam(required = false, defaultValue = "-1") Long parentId) { + return R.data(dictService.childList(dict, parentId)); + } + + /** + * 获取字典树形结构 + */ + @GetMapping("/tree") + @ApiOperationSupport(order = 5) + @ApiOperation(value = "树形结构", notes = "树形结构") + public R> tree() { + List tree = dictService.tree(); + return R.data(tree); + } + + /** + * 获取字典树形结构 + */ + @GetMapping("/parent-tree") + @ApiOperationSupport(order = 5) + @ApiOperation(value = "树形结构", notes = "树形结构") + public R> parentTree() { + List tree = dictService.parentTree(); + return R.data(tree); + } + + /** + * 新增或修改 + */ + @PostMapping("/submit") + @ApiOperationSupport(order = 6) + @ApiOperation(value = "新增或修改", notes = "传入dict") + public R submit(@Valid @RequestBody DictBiz dict) { + CacheUtil.clear(DICT_CACHE); + return R.status(dictService.submit(dict)); + } + + + /** + * 删除 + */ + @PostMapping("/remove") + @ApiOperationSupport(order = 7) + @ApiOperation(value = "删除", notes = "传入ids") + public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) { + CacheUtil.clear(DICT_CACHE); + return R.status(dictService.removeDict(ids)); + } + + /** + * 获取字典 + */ + @GetMapping("/dictionary") + @ApiOperationSupport(order = 8) + @ApiOperation(value = "获取字典", notes = "获取字典") + public R> dictionary(String code) { + List tree = dictService.getList(code); + return R.data(tree); + } + + /** + * 获取字典树 + */ + @GetMapping("/dictionary-tree") + @ApiOperationSupport(order = 9) + @ApiOperation(value = "获取字典树", notes = "获取字典树") + public R> dictionaryTree(String code) { + List tree = dictService.getList(code); + return R.data(DictBizWrapper.build().listNodeVO(tree)); + } + + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/MenuController.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/MenuController.java new file mode 100644 index 0000000..f11a73b --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/MenuController.java @@ -0,0 +1,206 @@ +package org.springblade.auth.system.controller; + +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.AllArgsConstructor; +import org.springblade.auth.system.entity.Menu; +import org.springblade.auth.system.service.IMenuService; +import org.springblade.auth.system.vo.MenuVO; +import org.springblade.auth.system.wrapper.MenuWrapper; +import org.springblade.core.boot.ctrl.BladeController; +import org.springblade.core.cache.utils.CacheUtil; +import org.springblade.core.mp.support.Condition; +import org.springblade.core.secure.BladeUser; +import org.springblade.core.secure.annotation.PreAuth; +import org.springblade.core.tenant.annotation.NonDS; +import org.springblade.core.tool.api.R; +import org.springblade.core.tool.constant.RoleConstant; +import org.springblade.core.tool.support.Kv; +import org.springblade.core.tool.utils.Func; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import springfox.documentation.annotations.ApiIgnore; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +import static org.springblade.core.cache.constant.CacheConstant.MENU_CACHE; + + +/** + * 控制器 + * + * @author Chill + */ +@NonDS +@RestController +@AllArgsConstructor +@RequestMapping("/menu") +@Api(value = "菜单", tags = "菜单") +public class MenuController extends BladeController { + + private final IMenuService menuService; + + /** + * 详情 + */ + @GetMapping("/detail") + @PreAuth(RoleConstant.HAS_ROLE_ADMINISTRATOR) + @ApiOperationSupport(order = 1) + @ApiOperation(value = "详情", notes = "传入menu") + public R detail(Menu menu) { + Menu detail = menuService.getOne(Condition.getQueryWrapper(menu)); + return R.data(MenuWrapper.build().entityVO(detail)); + } + + /** + * 列表 + */ + @GetMapping("/list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "code", value = "菜单编号", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "name", value = "菜单名称", paramType = "query", dataType = "string") + }) + @PreAuth(RoleConstant.HAS_ROLE_ADMINISTRATOR) + @ApiOperationSupport(order = 2) + @ApiOperation(value = "列表", notes = "传入menu") + public R> list(@ApiIgnore @RequestParam Map menu) { + List list = menuService.list(Condition.getQueryWrapper(menu, Menu.class).lambda().orderByAsc(Menu::getSort)); + return R.data(MenuWrapper.build().listNodeVO(list)); + } + + /** + * 懒加载列表 + */ + @GetMapping("/lazy-list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "code", value = "菜单编号", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "name", value = "菜单名称", paramType = "query", dataType = "string") + }) + @PreAuth(RoleConstant.HAS_ROLE_ADMIN) + @ApiOperationSupport(order = 3) + @ApiOperation(value = "懒加载列表", notes = "传入menu") + public R> lazyList(Long parentId, @ApiIgnore @RequestParam Map menu) { + List list = menuService.lazyList(parentId, menu); + return R.data(MenuWrapper.build().listNodeLazyVO(list)); + } + + /** + * 菜单列表 + */ + @GetMapping("/menu-list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "code", value = "菜单编号", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "name", value = "菜单名称", paramType = "query", dataType = "string") + }) + @PreAuth(RoleConstant.HAS_ROLE_ADMIN) + @ApiOperationSupport(order = 4) + @ApiOperation(value = "菜单列表", notes = "传入menu") + public R> menuList(@ApiIgnore @RequestParam Map menu) { + List list = menuService.list(Condition.getQueryWrapper(menu, Menu.class).lambda().eq(Menu::getCategory, 1).orderByAsc(Menu::getSort)); + return R.data(MenuWrapper.build().listNodeVO(list)); + } + + /** + * 懒加载菜单列表 + */ + @GetMapping("/lazy-menu-list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "code", value = "菜单编号", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "name", value = "菜单名称", paramType = "query", dataType = "string") + }) + @PreAuth(RoleConstant.HAS_ROLE_ADMIN) + @ApiOperationSupport(order = 5) + @ApiOperation(value = "懒加载菜单列表", notes = "传入menu") + public R> lazyMenuList(Long parentId, @ApiIgnore @RequestParam Map menu) { + List list = menuService.lazyMenuList(parentId, menu); + return R.data(MenuWrapper.build().listNodeLazyVO(list)); + } + + /** + * 新增或修改 + */ + @PostMapping("/submit") + @PreAuth(RoleConstant.HAS_ROLE_ADMIN) + @ApiOperationSupport(order = 6) + @ApiOperation(value = "新增或修改", notes = "传入menu") + public R submit(@Valid @RequestBody Menu menu) { + if (menuService.submit(menu)) { + CacheUtil.clear(MENU_CACHE); + CacheUtil.clear(MENU_CACHE, Boolean.FALSE); + // 返回懒加载树更新节点所需字段 + Kv kv = Kv.create().set("id", String.valueOf(menu.getId())); + return R.data(kv); + } + return R.fail("操作失败"); + } + + + /** + * 删除 + */ + @PostMapping("/remove") + @PreAuth(RoleConstant.HAS_ROLE_ADMIN) + @ApiOperationSupport(order = 7) + @ApiOperation(value = "删除", notes = "传入ids") + public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) { + CacheUtil.clear(MENU_CACHE); + CacheUtil.clear(MENU_CACHE, Boolean.FALSE); + return R.status(menuService.removeMenu(ids)); + } + + /** + * 前端菜单数据 + */ + @GetMapping("/routes") + @ApiOperationSupport(order = 8) + @ApiOperation(value = "前端菜单数据", notes = "前端菜单数据") + public R> routes(BladeUser user, Long topMenuId) { + List list = menuService.routes((user == null) ? null : user.getRoleId(), topMenuId); + return R.data(list); + } + + /** + * 前端按钮数据 + */ + @GetMapping("/buttons") + @ApiOperationSupport(order = 10) + @ApiOperation(value = "前端按钮数据", notes = "前端按钮数据") + public R> buttons(BladeUser user) { + List list = menuService.buttons(user.getRoleId()); + return R.data(list); + } + + /** + * 获取菜单树形结构 + */ + @GetMapping("/tree") + @ApiOperationSupport(order = 11) + @ApiOperation(value = "树形结构", notes = "树形结构") + public R> tree() { + List tree = menuService.tree(); + return R.data(tree); + } + + /** + * 获取配置的角色权限 + */ + @GetMapping("auth-routes") + @ApiOperationSupport(order = 17) + @ApiOperation(value = "菜单的角色权限") + public R> authRoutes(BladeUser user) { + if (Func.isEmpty(user)) { + return null; + } + return R.data(menuService.authRoutes(user)); + } +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/RoleController.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/RoleController.java new file mode 100644 index 0000000..e406cf4 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/RoleController.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.AllArgsConstructor; +import org.springblade.auth.system.service.IRoleService; +import org.springblade.core.boot.ctrl.BladeController; +import org.springblade.core.cache.utils.CacheUtil; +import org.springblade.core.mp.support.Condition; +import org.springblade.core.secure.BladeUser; +import org.springblade.core.secure.annotation.PreAuth; +import org.springblade.core.secure.constant.AuthConstant; +import org.springblade.core.tenant.annotation.NonDS; +import org.springblade.core.tool.api.R; +import org.springblade.core.tool.constant.BladeConstant; +import org.springblade.core.tool.constant.RoleConstant; +import org.springblade.core.tool.utils.Func; +import org.springblade.auth.system.cache.SysCache; +import org.springblade.auth.system.entity.Role; +import org.springblade.auth.system.vo.RoleVO; +import org.springblade.auth.system.wrapper.RoleWrapper; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import springfox.documentation.annotations.ApiIgnore; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +import static org.springblade.core.cache.constant.CacheConstant.SYS_CACHE; + +/** + * 控制器 + * + * @author Chill + */ +@NonDS +@RestController +@AllArgsConstructor +@RequestMapping("/role") +@Api(value = "角色", tags = "角色") +@PreAuth(RoleConstant.HAS_ROLE_ADMIN) +public class RoleController extends BladeController { + + private final IRoleService roleService; + + /** + * 详情 + */ + @GetMapping("/detail") + @ApiOperationSupport(order = 1) + @ApiOperation(value = "详情", notes = "传入role") + public R detail(Role role) { + Role detail = roleService.getOne(Condition.getQueryWrapper(role)); + return R.data(RoleWrapper.build().entityVO(detail)); + } + + /** + * 列表 + */ + @GetMapping("/list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "roleName", value = "参数名称", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "roleAlias", value = "角色别名", paramType = "query", dataType = "string") + }) + @ApiOperationSupport(order = 2) + @ApiOperation(value = "列表", notes = "传入role") + public R> list(@ApiIgnore @RequestParam Map role, BladeUser bladeUser) { + QueryWrapper queryWrapper = Condition.getQueryWrapper(role, Role.class); + List list = roleService.list((!bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID)) ? queryWrapper.lambda().eq(Role::getTenantId, bladeUser.getTenantId()) : queryWrapper); + return R.data(RoleWrapper.build().listNodeVO(list)); + } + + /** + * 获取角色树形结构 + */ + @GetMapping("/tree") + @ApiOperationSupport(order = 3) + @ApiOperation(value = "树形结构", notes = "树形结构") + public R> tree(String tenantId, BladeUser bladeUser) { + List tree = roleService.tree(Func.toStrWithEmpty(tenantId, bladeUser.getTenantId())); + return R.data(tree); + } + + /** + * 获取指定角色树形结构 + */ + @GetMapping("/tree-by-id") + @ApiOperationSupport(order = 4) + @ApiOperation(value = "树形结构", notes = "树形结构") + public R> treeById(Long roleId, BladeUser bladeUser) { + Role role = SysCache.getRole(roleId); + List tree = roleService.tree(Func.notNull(role) ? role.getTenantId() : bladeUser.getTenantId()); + return R.data(tree); + } + + /** + * 新增或修改 + */ + @PostMapping("/submit") + @ApiOperationSupport(order = 5) + @ApiOperation(value = "新增或修改", notes = "传入role") + public R submit(@Valid @RequestBody Role role) { + CacheUtil.clear(SYS_CACHE); + CacheUtil.clear(SYS_CACHE, Boolean.FALSE); + return R.status(roleService.submit(role)); + } + + + /** + * 删除 + */ + @PostMapping("/remove") + @ApiOperationSupport(order = 6) + @ApiOperation(value = "删除", notes = "传入ids") + public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) { + CacheUtil.clear(SYS_CACHE); + CacheUtil.clear(SYS_CACHE, Boolean.FALSE); + return R.status(roleService.removeByIds(Func.toLongList(ids))); + } + + /** + * 下拉数据源 + */ + @PreAuth(AuthConstant.PERMIT_ALL) + @GetMapping("/select") + @ApiOperationSupport(order = 8) + @ApiOperation(value = "下拉数据源", notes = "传入id集合") + public R> select(String roleId) { + List list = roleService.list(Wrappers.lambdaQuery().in(Role::getId, Func.toLongList(roleId))); + return R.data(list); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/UserController.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/UserController.java new file mode 100644 index 0000000..4742901 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/controller/UserController.java @@ -0,0 +1,216 @@ +package org.springblade.auth.system.controller; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.AllArgsConstructor; +import org.springblade.auth.system.entity.User; +import org.springblade.auth.system.service.IUserService; +import org.springblade.auth.system.vo.UserVO; +import org.springblade.auth.system.wrapper.UserWrapper; +import org.springblade.core.cache.utils.CacheUtil; +import org.springblade.core.mp.support.Condition; +import org.springblade.core.mp.support.Query; +import org.springblade.core.secure.BladeUser; +import org.springblade.core.secure.utils.AuthUtil; +import org.springblade.core.tenant.annotation.NonDS; +import org.springblade.core.tool.api.R; +import org.springblade.core.tool.constant.BladeConstant; +import org.springblade.core.tool.utils.StringPool; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import springfox.documentation.annotations.ApiIgnore; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +import static org.springblade.core.cache.constant.CacheConstant.USER_CACHE; + +/** + * 控制器 + * + * @author Chill + */ +@NonDS +@RestController +@RequestMapping("/user") +@AllArgsConstructor +public class UserController { + + private final IUserService userService; + + /** + * 查询单条 + */ + @ApiOperationSupport(order = 1) + @ApiOperation(value = "查看详情", notes = "传入id") + @GetMapping("/detail") + public R detail(User user) { + User detail = userService.getOne(Condition.getQueryWrapper(user)); + return R.data(UserWrapper.build().entityVO(detail)); + } + + /** + * 查询单条 + */ + @ApiOperationSupport(order = 2) + @ApiOperation(value = "查看详情", notes = "传入id") + @GetMapping("/info") + public R info(BladeUser user) { + User detail = userService.getById(user.getUserId()); + return R.data(UserWrapper.build().entityVO(detail)); + } + + /** + * 用户列表 + */ + @GetMapping("/list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "account", value = "账号名", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "realName", value = "姓名", paramType = "query", dataType = "string") + }) + @ApiOperationSupport(order = 3) + @ApiOperation(value = "列表", notes = "传入account和realName") + public R> list(@ApiIgnore @RequestParam Map user, Query query, BladeUser bladeUser) { + QueryWrapper queryWrapper = Condition.getQueryWrapper(user, User.class); + IPage pages = userService.page(Condition.getPage(query), (!bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID)) ? queryWrapper.lambda().eq(User::getTenantId, bladeUser.getTenantId()) : queryWrapper); + return R.data(UserWrapper.build().pageVO(pages)); + } + + /** + * 自定义用户列表 + */ + @GetMapping("/page") + @ApiImplicitParams({ + @ApiImplicitParam(name = "account", value = "账号名", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "realName", value = "姓名", paramType = "query", dataType = "string") + }) + @ApiOperationSupport(order = 3) + @ApiOperation(value = "列表", notes = "传入account和realName") + //@PreAuth(RoleConstant.HAS_ROLE_ADMIN) + //添加组长可以查询人员的权限 + //@PreAuth("hasAnyRole('" + RoleConstant.ADMINISTRATOR + "', '" + RoleConstant.ADMIN + "','" + RoleConstant.USER + "')") + public R> page(@ApiIgnore User user, Query query, Long deptId, BladeUser bladeUser) { + IPage pages = userService.selectUserPage(Condition.getPage(query), user, deptId, (bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID) ? StringPool.EMPTY : bladeUser.getTenantId())); + return R.data(UserWrapper.build().pageVO(pages)); + } + + /** + * 新增或修改 + */ + @PostMapping("/submit") + @ApiOperationSupport(order = 4) + @ApiOperation(value = "新增或修改", notes = "传入User") + public R submit(@Valid @RequestBody User user) { + CacheUtil.clear(USER_CACHE); + return R.status(userService.submit(user)); + } + + /** + * 修改 + */ + @PostMapping("/update") + @ApiOperationSupport(order = 5) + @ApiOperation(value = "修改", notes = "传入User") + public R update(@Valid @RequestBody User user) { + CacheUtil.clear(USER_CACHE); + return R.status(userService.updateUser(user)); + } + + /** + * 删除 + */ + @PostMapping("/remove") + @ApiOperationSupport(order = 6) + @ApiOperation(value = "删除", notes = "传入id集合") + public R remove(@RequestParam String ids) { + CacheUtil.clear(USER_CACHE); + return R.status(userService.removeUser(ids)); + } + + /** + * 设置菜单权限 + */ + @PostMapping("/grant") + @ApiOperationSupport(order = 7) + @ApiOperation(value = "权限设置", notes = "传入roleId集合以及menuId集合") + public R grant(@ApiParam(value = "userId集合", required = true) @RequestParam String userIds, + @ApiParam(value = "roleId集合", required = true) @RequestParam String roleIds) { + boolean temp = userService.grant(userIds, roleIds); + return R.status(temp); + } + + /** + * 密码重制 + */ + @PostMapping("/reset-password") + @ApiOperationSupport(order = 8) + @ApiOperation(value = "初始化密码", notes = "传入userId集合") + public R resetPassword(@ApiParam(value = "userId集合", required = true) @RequestParam String userIds) { + boolean temp = userService.resetPassword(userIds); + return R.status(temp); + } + + /** + * 修改密码 + */ + @PostMapping("/update-password") + @ApiOperationSupport(order = 9) + @ApiOperation(value = "修改密码", notes = "传入密码") + public R updatePassword(BladeUser user, @ApiParam(value = "旧密码", required = true) @RequestParam String oldPassword, + @ApiParam(value = "新密码", required = true) @RequestParam String newPassword, + @ApiParam(value = "新密码", required = true) @RequestParam String newPassword1) { + boolean temp = userService.updatePassword(user.getUserId(), oldPassword, newPassword, newPassword1); + return R.status(temp); + } + + /** + * 修改基本信息 + */ + @PostMapping("/update-info") + @ApiOperationSupport(order = 10) + @ApiOperation(value = "修改基本信息", notes = "传入User") + public R updateInfo(@Valid @RequestBody User user) { + CacheUtil.clear(USER_CACHE); + return R.status(userService.updateUserInfo(user)); + } + + /** + * 用户列表 + */ + @GetMapping("/user-list") + @ApiOperationSupport(order = 11) + @ApiOperation(value = "用户列表", notes = "传入user") + public R> userList(User user, BladeUser bladeUser) { + QueryWrapper queryWrapper = Condition.getQueryWrapper(user); + List list = userService.list((!AuthUtil.isAdministrator()) ? queryWrapper.lambda().eq(User::getTenantId, bladeUser.getTenantId()) : queryWrapper); + return R.data(list); + } + + /** + * 用户列表查询 + */ + @ApiImplicitParams({ + @ApiImplicitParam(name = "name", value = "人员姓名", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "deptName", value = "部门名称", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "postName", value = "职位名称", paramType = "query", dataType = "string"), + @ApiImplicitParam(name = "current", value = "当前页数", paramType = "query", dataType = "int"), + @ApiImplicitParam(name = "size", value = "每页数量", paramType = "query", dataType = "int") + }) + @ApiOperationSupport(order = 18) + @ApiOperation(value = "用户列表查询", notes = "用户列表查询") + @GetMapping("/search/user") + public R> userSearch(@ApiIgnore UserVO user, @ApiIgnore Query query) { + return R.data(userService.selectUserSearch(user, query)); + } +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/dto/MenuDTO.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/dto/MenuDTO.java new file mode 100644 index 0000000..bb0e6d8 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/dto/MenuDTO.java @@ -0,0 +1,17 @@ +package org.springblade.auth.system.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 数据传输对象实体类 + * + * @author Chill + */ +@Data +public class MenuDTO implements Serializable { + private static final long serialVersionUID = 1L; + private String alias; + private String path; +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/dto/RoleDTO.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/dto/RoleDTO.java new file mode 100644 index 0000000..560942b --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/dto/RoleDTO.java @@ -0,0 +1,17 @@ +package org.springblade.auth.system.dto; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.auth.system.entity.Role; + +/** + * 数据传输对象实体类 + * + * @author Chill + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RoleDTO extends Role { + private static final long serialVersionUID = 1L; + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/dto/RoleMenuDTO.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/dto/RoleMenuDTO.java new file mode 100644 index 0000000..b19a343 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/dto/RoleMenuDTO.java @@ -0,0 +1,17 @@ +package org.springblade.auth.system.dto; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.auth.system.entity.RoleMenu; + +/** + * 数据传输对象实体类 + * + * @author Chill + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RoleMenuDTO extends RoleMenu { + private static final long serialVersionUID = 1L; + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/DictBiz.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/DictBiz.java new file mode 100644 index 0000000..5a97501 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/DictBiz.java @@ -0,0 +1,92 @@ +package org.springblade.auth.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * 实体类 + * + * @author Chill + */ +@Data +@TableName("blade_dict_biz") +@ApiModel(value = "DictBiz对象", description = "DictBiz对象") +public class DictBiz implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @JsonSerialize(using = ToStringSerializer.class) + @ApiModelProperty(value = "主键") + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 租户ID + */ + @ApiModelProperty(value = "租户ID") + private String tenantId; + + /** + * 父主键 + */ + @JsonSerialize(using = ToStringSerializer.class) + @ApiModelProperty(value = "父主键") + private Long parentId; + + /** + * 字典码 + */ + @ApiModelProperty(value = "字典码") + private String code; + + /** + * 字典值 + */ + @ApiModelProperty(value = "字典值") + private String dictKey; + + /** + * 字典名称 + */ + @ApiModelProperty(value = "字典名称") + private String dictValue; + + /** + * 排序 + */ + @ApiModelProperty(value = "排序") + private Integer sort; + + /** + * 字典备注 + */ + @ApiModelProperty(value = "字典备注") + private String remark; + + /** + * 是否已封存 + */ + @ApiModelProperty(value = "是否已封存") + private Integer isSealed; + + /** + * 是否已删除 + */ + @TableLogic + @ApiModelProperty(value = "是否已删除") + private Integer isDeleted; + + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/Menu.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/Menu.java new file mode 100644 index 0000000..127c98a --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/Menu.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springblade.core.tool.utils.Func; + +import java.io.Serializable; +import java.util.Objects; + +/** + * 实体类 + * + * @author Chill + */ +@Data +@TableName("blade_menu") +@ApiModel(value = "Menu对象", description = "Menu对象") +public class Menu implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @JsonSerialize(using = ToStringSerializer.class) + @ApiModelProperty(value = "主键") + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 菜单父主键 + */ + @JsonSerialize(using = ToStringSerializer.class) + @ApiModelProperty(value = "菜单父主键") + private Long parentId; + + /** + * 菜单编号 + */ + @ApiModelProperty(value = "菜单编号") + private String code; + + /** + * 菜单名称 + */ + @ApiModelProperty(value = "菜单名称") + private String name; + + /** + * 菜单别名 + */ + @ApiModelProperty(value = "菜单别名") + private String alias; + + /** + * 请求地址 + */ + @ApiModelProperty(value = "请求地址") + private String path; + + /** + * 菜单资源 + */ + @ApiModelProperty(value = "菜单资源") + private String source; + + /** + * 排序 + */ + @ApiModelProperty(value = "排序") + private Integer sort; + + /** + * 菜单类型 + */ + @ApiModelProperty(value = "菜单类型") + private Integer category; + + /** + * 操作按钮类型 + */ + @ApiModelProperty(value = "操作按钮类型") + private Integer action; + + /** + * 是否打开新页面 + */ + @ApiModelProperty(value = "是否打开新页面") + private Integer isOpen; + + /** + * 备注 + */ + @ApiModelProperty(value = "备注") + private String remark; + + /** + * 是否已删除 + */ + @TableLogic + @ApiModelProperty(value = "是否已删除") + private Integer isDeleted; + + /** + * 是否隐藏 + */ + @ApiModelProperty(value = "是否隐藏") + private Integer isHidden; + /** + * 手动添加的隐藏的set方法 + */ + public void setIsHidden(Integer isHidden) { + this.isHidden = isHidden; + } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + Menu other = (Menu) obj; + if (Func.equals(this.getId(), other.getId())) { + return true; + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(id, parentId, code); + } + + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/Role.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/Role.java new file mode 100644 index 0000000..0c68d17 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/Role.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * 实体类 + * + * @author Chill + */ +@Data +@TableName("blade_role") +@ApiModel(value = "Role对象", description = "Role对象") +public class Role implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @JsonSerialize(using = ToStringSerializer.class) + @ApiModelProperty(value = "主键") + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 租户ID + */ + @ApiModelProperty(value = "租户ID") + private String tenantId; + + /** + * 父主键 + */ + @JsonSerialize(using = ToStringSerializer.class) + @ApiModelProperty(value = "父主键") + private Long parentId; + + /** + * 角色名 + */ + @ApiModelProperty(value = "角色名") + private String roleName; + + /** + * 排序 + */ + @ApiModelProperty(value = "排序") + private Integer sort; + + /** + * 角色别名 + */ + @ApiModelProperty(value = "角色别名") + private String roleAlias; + + /** + * 是否已删除 + */ + @TableLogic + @ApiModelProperty(value = "是否已删除") + private Integer isDeleted; + + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/RoleMenu.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/RoleMenu.java new file mode 100644 index 0000000..488423e --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/RoleMenu.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * 实体类 + * + * @author Chill + */ +@Data +@TableName("blade_role_menu") +@ApiModel(value = "RoleMenu对象", description = "RoleMenu对象") +public class RoleMenu implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @JsonSerialize(using = ToStringSerializer.class) + @ApiModelProperty(value = "主键") + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 菜单id + */ + @JsonSerialize(using = ToStringSerializer.class) + @ApiModelProperty(value = "菜单id") + private Long menuId; + + /** + * 角色id + */ + @JsonSerialize(using = ToStringSerializer.class) + @ApiModelProperty(value = "角色id") + private Long roleId; + + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/User.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/User.java new file mode 100644 index 0000000..de42756 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/User.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.core.tenant.mp.TenantEntity; + +import java.util.Date; + +/** + * 实体类 + * + * @author Chill + */ +@Data +@TableName("blade_user") +@EqualsAndHashCode(callSuper = true) +public class User extends TenantEntity { + + private static final long serialVersionUID = 1L; + + /** + * 用户编号 + */ + private String code; + /** + * 用户平台 + */ + private Integer userType; + /** + * 账号 + */ + private String account; + /** + * 密码 + */ + private String password; + /** + * 昵称 + */ + private String name; + /** + * 真名 + */ + private String realName; + + /** + * 用户身份证号 + */ + private String idCard; + + /** + * 头像 + */ + private String avatar; + /** + * 邮箱 + */ + private String email; + /** + * 手机 + */ + private String phone; + /** + * 生日 + */ + private Date birthday; + /** + * 性别 + */ + private Integer sex; + /** + * 角色id + */ + private String roleId; + /** + * 部门id + */ + private String deptId; + /** + * 岗位id + */ + private String postId; + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/UserInfo.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/UserInfo.java new file mode 100644 index 0000000..f799ac6 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/entity/UserInfo.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.entity; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springblade.core.tool.support.Kv; + +import java.io.Serializable; +import java.util.List; + +/** + * 用户信息 + * + * @author Chill + */ +@Data +@ApiModel(description = "用户信息") +public class UserInfo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 第三方授权id + */ + @ApiModelProperty(value = "第三方授权id") + private String oauthId; + + /** + * 用户基础信息 + */ + @ApiModelProperty(value = "用户") + private User user; + + /** + * 拓展信息 + */ + @ApiModelProperty(value = "拓展信息") + private Kv detail; + + /** + * 权限标识集合 + */ + @ApiModelProperty(value = "权限集合") + private List permissions; + + /** + * 角色集合 + */ + @ApiModelProperty(value = "角色集合") + private List roles; + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/enums/UserEnum.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/enums/UserEnum.java new file mode 100644 index 0000000..a70bcd7 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/enums/UserEnum.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 用户类型枚举 + * + * @author Chill + */ +@Getter +@AllArgsConstructor +public enum UserEnum { + + /** + * web + */ + WEB("web", 1), + + /** + * app + */ + APP("app", 2), + + /** + * other + */ + OTHER("other", 3), + ; + + final String name; + final int category; + + /** + * 匹配枚举值 + * + * @param name 名称 + * @return BladeUserEnum + */ + public static UserEnum of(String name) { + if (name == null) { + return null; + } + UserEnum[] values = UserEnum.values(); + for (UserEnum smsEnum : values) { + if (smsEnum.name.equals(name)) { + return smsEnum; + } + } + return null; + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/DictBizMapper.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/DictBizMapper.java new file mode 100644 index 0000000..916f378 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/DictBizMapper.java @@ -0,0 +1,48 @@ +package org.springblade.auth.system.mapper; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.springblade.auth.system.entity.DictBiz; +import org.springblade.auth.system.vo.DictBizVO; + +import java.util.List; + +/** + * Mapper 接口 + * + * @author Chill + */ +public interface DictBizMapper extends BaseMapper { + + /** + * 获取字典表对应中文 + * + * @param code 字典编号 + * @param dictKey 字典序号 + * @return + */ + String getValue(String code, String dictKey); + + /** + * 获取字典表 + * + * @param code 字典编号 + * @return + */ + List getList(String code); + + /** + * 获取树形节点 + * + * @return + */ + List tree(); + + /** + * 获取树形节点 + * + * @return + */ + List parentTree(); + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/DictBizMapper.xml b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/DictBizMapper.xml new file mode 100644 index 0000000..25f2884 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/DictBizMapper.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/MenuMapper.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/MenuMapper.java new file mode 100644 index 0000000..73ddea9 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/MenuMapper.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.springblade.auth.system.dto.MenuDTO; +import org.springblade.auth.system.entity.Menu; +import org.springblade.auth.system.vo.MenuVO; + +import java.util.List; +import java.util.Map; + + +/** + * MenuMapper 接口 + * + * @author Chill + */ +public interface MenuMapper extends BaseMapper { + + /** + * 懒加载列表 + * + * @param parentId + * @param param + * @return + */ + List lazyList(Long parentId, Map param); + + /** + * 懒加载菜单列表 + * + * @param parentId + * @param param + * @return + */ + List lazyMenuList(Long parentId, Map param); + + /** + * 树形结构 + * + * @return + */ + List tree(); + + /** + * 授权树形结构 + * + * @return + */ + List grantTree(); + + /** + * 授权树形结构 + * + * @param roleId + * @return + */ + List grantTreeByRole(List roleId); + + /** + * 顶部菜单树形结构 + * + * @return + */ + List grantTopTree(); + + /** + * 顶部菜单树形结构 + * + * @param roleId + * @return + */ + List grantTopTreeByRole(List roleId); + + /** + * 数据权限授权树形结构 + * + * @return + */ + List grantDataScopeTree(); + + /** + * 接口权限授权树形结构 + * + * @return + */ + List grantApiScopeTree(); + + /** + * 数据权限授权树形结构 + * + * @param roleId + * @return + */ + List grantDataScopeTreeByRole(List roleId); + + /** + * 接口权限授权树形结构 + * + * @param roleId + * @return + */ + List grantApiScopeTreeByRole(List roleId); + + /** + * 所有菜单 + * + * @return + */ + List allMenu(); + + /** + * 权限配置菜单 + * + * @param roleId + * @param topMenuId + * @return + */ + List roleMenu(List roleId, Long topMenuId); + + /** + * 权限配置菜单 + * + * @param roleId + * @return + */ + List roleMenuByRoleId(List roleId); + + /** + * 权限配置菜单 + * + * @param topMenuId + * @return + */ + List roleMenuByTopMenuId(Long topMenuId); + + /** + * 菜单树形结构 + * + * @param roleId + * @return + */ + List routes(List roleId); + + /** + * 按钮树形结构 + * + * @return + */ + List allButtons(); + + /** + * 按钮树形结构 + * + * @param roleId + * @return + */ + List buttons(List roleId); + + /** + * 获取配置的角色权限 + * + * @param roleIds + * @return + */ + List authRoutes(List roleIds); +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/MenuMapper.xml b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/MenuMapper.xml new file mode 100644 index 0000000..7be3449 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/MenuMapper.xml @@ -0,0 +1,478 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMapper.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMapper.java new file mode 100644 index 0000000..111c408 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMapper.java @@ -0,0 +1,51 @@ +package org.springblade.auth.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.springblade.auth.system.entity.Role; +import org.springblade.auth.system.vo.RoleVO; + +import java.util.List; + +/** + * Mapper 接口 + * + * @author Chill + */ +public interface RoleMapper extends BaseMapper { + + /** + * 自定义分页 + * + * @param page + * @param role + * @return + */ + List selectRolePage(IPage page, RoleVO role); + + /** + * 获取树形节点 + * + * @param tenantId + * @param excludeRole + * @return + */ + List tree(String tenantId, String excludeRole); + + /** + * 获取角色名 + * + * @param ids + * @return + */ + List getRoleNames(Long[] ids); + + /** + * 获取角色名 + * + * @param ids + * @return + */ + List getRoleAliases(Long[] ids); + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMapper.xml b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMapper.xml new file mode 100644 index 0000000..d2b0866 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMapper.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMenuMapper.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMenuMapper.java new file mode 100644 index 0000000..e4bd115 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMenuMapper.java @@ -0,0 +1,25 @@ +package org.springblade.auth.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.springblade.auth.system.entity.RoleMenu; +import org.springblade.auth.system.vo.RoleMenuVO; + +import java.util.List; + +/** + * Mapper 接口 + * + * @author Chill + */ +public interface RoleMenuMapper extends BaseMapper { + + /** + * 自定义分页 + * @param page + * @param roleMenu + * @return + */ + List selectRoleMenuPage(IPage page, RoleMenuVO roleMenu); + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMenuMapper.xml b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMenuMapper.xml new file mode 100644 index 0000000..3d25206 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/RoleMenuMapper.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/UserMapper.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/UserMapper.java new file mode 100644 index 0000000..59f8d08 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/UserMapper.java @@ -0,0 +1,37 @@ +package org.springblade.auth.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.ibatis.annotations.Param; +import org.springblade.auth.system.entity.User; + +import java.util.List; + +/** + * Mapper 接口 + * + * @author Chill + */ +public interface UserMapper extends BaseMapper { + + /** + * 自定义分页 + * + * @param page + * @param user + * @param deptIdList + * @param tenantId + * @return + */ + List selectUserPage(IPage page, @Param("user") User user, @Param("deptIdList") List deptIdList, @Param("tenantId") String tenantId); + + /** + * 获取用户 + * + * @param tenantId + * @param account + * @return + */ + User getUser(String tenantId, String account); + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/UserMapper.xml b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/UserMapper.xml new file mode 100644 index 0000000..e82adfa --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/mapper/UserMapper.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id,tenant_id,code,user_type,id_card,account,password,name,real_name,email,phone,birthday,sex,role_id,dept_id,post_id, + create_user,create_dept,create_time,update_user,update_time,status,is_deleted + + + + + + + diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IDictBizService.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IDictBizService.java new file mode 100644 index 0000000..ac402b4 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IDictBizService.java @@ -0,0 +1,85 @@ +package org.springblade.auth.system.service; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import org.springblade.core.mp.support.Query; +import org.springblade.auth.system.entity.DictBiz; +import org.springblade.auth.system.vo.DictBizVO; + +import java.util.List; +import java.util.Map; + +/** + * 服务类 + * + * @author Chill + */ +public interface IDictBizService extends IService { + + /** + * 树形结构 + * + * @return + */ + List tree(); + + /** + * 树形结构 + * + * @return + */ + List parentTree(); + + /** + * 获取字典表对应中文 + * + * @param code 字典编号 + * @param dictKey 字典序号 + * @return + */ + String getValue(String code, String dictKey); + + /** + * 获取字典表 + * + * @param code 字典编号 + * @return + */ + List getList(String code); + + /** + * 新增或修改 + * + * @param dict + * @return + */ + boolean submit(DictBiz dict); + + /** + * 删除字典 + * + * @param ids + * @return + */ + boolean removeDict(String ids); + + /** + * 顶级列表 + * + * @param dict + * @param query + * @return + */ + IPage parentList(Map dict, Query query); + + /** + * 子列表 + * + * @param dict + * @param parentId + * @return + */ + List childList(Map dict, Long parentId); + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IMenuService.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IMenuService.java new file mode 100644 index 0000000..333289d --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IMenuService.java @@ -0,0 +1,101 @@ +package org.springblade.auth.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import org.springblade.core.secure.BladeUser; +import org.springblade.core.tool.support.Kv; +import org.springblade.auth.system.entity.Menu; +import org.springblade.auth.system.vo.MenuVO; + +import java.util.List; +import java.util.Map; + +/** + * 服务类 + * + * @author Chill + */ +public interface IMenuService extends IService { + + /** + * 懒加载列表 + * + * @param parentId + * @param param + * @return + */ + List lazyList(Long parentId, Map param); + + /** + * 懒加载菜单列表 + * + * @param parentId + * @param param + * @return + */ + List lazyMenuList(Long parentId, Map param); + + /** + * 菜单树形结构 + * + * @param roleId + * @param topMenuId + * @return + */ + List routes(String roleId, Long topMenuId); + + /** + * 按钮树形结构 + * + * @param roleId + * @return + */ + List buttons(String roleId); + + /** + * 树形结构 + * + * @return + */ + List tree(); + + /** + * 授权树形结构 + * + * @param user + * @return + */ + List grantTree(BladeUser user); + + /** + * 默认选中节点 + * + * @param roleIds + * @return + */ + List roleTreeKeys(String roleIds); + + /** + * 获取配置的角色权限 + * + * @param user + * @return + */ + List authRoutes(BladeUser user); + + /** + * 删除菜单 + * + * @param ids + * @return + */ + boolean removeMenu(String ids); + + /** + * 提交 + * + * @param menu + * @return + */ + boolean submit(Menu menu); + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IRoleMenuService.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IRoleMenuService.java new file mode 100644 index 0000000..4573512 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IRoleMenuService.java @@ -0,0 +1,13 @@ +package org.springblade.auth.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import org.springblade.auth.system.entity.RoleMenu; + +/** + * 服务类 + * + * @author Chill + */ +public interface IRoleMenuService extends IService { + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IRoleService.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IRoleService.java new file mode 100644 index 0000000..979e807 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IRoleService.java @@ -0,0 +1,76 @@ +package org.springblade.auth.system.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import org.springblade.auth.system.entity.Role; +import org.springblade.auth.system.vo.RoleVO; + +import java.util.List; + +/** + * 服务类 + * + * @author Chill + */ +public interface IRoleService extends IService { + + /** + * 自定义分页 + * + * @param page + * @param role + * @return + */ + IPage selectRolePage(IPage page, RoleVO role); + + /** + * 树形结构 + * + * @param tenantId + * @return + */ + List tree(String tenantId); + + /** + * 获取角色ID + * + * @param tenantId + * @param roleNames + * @return + */ + String getRoleIds(String tenantId, String roleNames); + + /** + * 获取角色名 + * + * @param roleIds + * @return + */ + List getRoleNames(String roleIds); + + /** + * 获取角色名 + * + * @param roleIds + * @return + */ + List getRoleAliases(String roleIds); + + /** + * 提交 + * + * @param role + * @return + */ + boolean submit(Role role); + + /** + * 角色信息查询 + * + * @param roleName + * @param parentId + * @return + */ + List search(String roleName, Long parentId); + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IUserService.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IUserService.java new file mode 100644 index 0000000..0b3a1e2 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/IUserService.java @@ -0,0 +1,125 @@ +package org.springblade.auth.system.service; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.springblade.auth.system.entity.User; +import org.springblade.auth.system.entity.UserInfo; +import org.springblade.auth.system.vo.UserVO; +import org.springblade.core.mp.base.BaseService; +import org.springblade.core.mp.support.Query; + +/** + * 服务类 + * + * @author Chill + */ +public interface IUserService extends BaseService { + + /** + * 新增用户 + * + * @param user + * @return + */ + boolean submit(User user); + + /** + * 修改用户 + * + * @param user + * @return + */ + boolean updateUser(User user); + + /** + * 修改用户基本信息 + * + * @param user + * @return + */ + boolean updateUserInfo(User user); + + /** + * 自定义分页 + * + * @param page + * @param user + * @param deptId + * @param tenantId + * @return + */ + IPage selectUserPage(IPage page, User user, Long deptId, String tenantId); + + /** + * 自定义分页 + * + * @param user + * @param query + * @return + */ + IPage selectUserSearch(UserVO user, Query query); + + + /** + * 用户信息 + * + * @param userId + * @return + */ + UserInfo userInfo(Long userId); + + /** + * 用户信息 + * + * @param tenantId + * @param account + * @return + */ + UserInfo userInfo(String tenantId, String account); + + /** + * 根据账号获取用户 + * + * @param tenantId + * @param account + * @return + */ + User userByAccount(String tenantId, String account); + + /** + * 给用户设置角色 + * + * @param userIds + * @param roleIds + * @return + */ + boolean grant(String userIds, String roleIds); + + /** + * 初始化密码 + * + * @param userIds + * @return + */ + boolean resetPassword(String userIds); + + /** + * 修改密码 + * + * @param userId + * @param oldPassword + * @param newPassword + * @param newPassword1 + * @return + */ + boolean updatePassword(Long userId, String oldPassword, String newPassword, String newPassword1); + + /** + * 删除用户 + * + * @param userIds + * @return + */ + boolean removeUser(String userIds); + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/DictBizServiceImpl.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/DictBizServiceImpl.java new file mode 100644 index 0000000..d50c0ea --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/DictBizServiceImpl.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springblade.common.constant.CommonConstant; +import org.springblade.core.cache.utils.CacheUtil; +import org.springblade.core.mp.support.Condition; +import org.springblade.core.mp.support.Query; +import org.springblade.core.tool.constant.BladeConstant; +import org.springblade.core.tool.node.ForestNodeMerger; +import org.springblade.core.tool.utils.Func; +import org.springblade.core.tool.utils.StringPool; +import org.springblade.auth.system.cache.DictBizCache; +import org.springblade.auth.system.entity.DictBiz; +import org.springblade.auth.system.mapper.DictBizMapper; +import org.springblade.auth.system.service.IDictBizService; +import org.springblade.auth.system.vo.DictBizVO; +import org.springblade.auth.system.wrapper.DictBizWrapper; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.springblade.core.cache.constant.CacheConstant.DICT_CACHE; + +/** + * 服务实现类 + * + * @author Chill + */ +@Service +public class DictBizServiceImpl extends ServiceImpl implements IDictBizService { + + @Override + public List tree() { + return ForestNodeMerger.merge(baseMapper.tree()); + } + + @Override + public List parentTree() { + return ForestNodeMerger.merge(baseMapper.parentTree()); + } + + @Override + public String getValue(String code, String dictKey) { + return Func.toStr(baseMapper.getValue(code, dictKey), StringPool.EMPTY); + } + + @Override + public List getList(String code) { + return baseMapper.getList(code); + } + + @Override + public boolean submit(DictBiz dict) { + LambdaQueryWrapper lqw = Wrappers.query().lambda().eq(DictBiz::getCode, dict.getCode()).eq(DictBiz::getDictKey, dict.getDictKey()); + Integer cnt = baseMapper.selectCount((Func.isEmpty(dict.getId())) ? lqw : lqw.notIn(DictBiz::getId, dict.getId())); + if (cnt > 0) { + throw new RuntimeException("当前字典键值已存在!"); + } + // 修改顶级字典后同步更新下属字典的编号 + if (Func.isNotEmpty(dict.getId()) && dict.getParentId().longValue() == BladeConstant.TOP_PARENT_ID) { + DictBiz parent = DictBizCache.getById(dict.getId()); + this.update(Wrappers.update().lambda().set(DictBiz::getCode, dict.getCode()).eq(DictBiz::getCode, parent.getCode()).ne(DictBiz::getParentId, BladeConstant.TOP_PARENT_ID)); + } + if (Func.isEmpty(dict.getParentId())) { + dict.setParentId(BladeConstant.TOP_PARENT_ID); + } + dict.setIsDeleted(BladeConstant.DB_NOT_DELETED); + CacheUtil.clear(DICT_CACHE); + return saveOrUpdate(dict); + } + + @Override + public boolean removeDict(String ids) { + Integer cnt = baseMapper.selectCount(Wrappers.query().lambda().in(DictBiz::getParentId, Func.toLongList(ids))); + if (cnt > 0) { + throw new RuntimeException("请先删除子节点!"); + } + return removeByIds(Func.toLongList(ids)); + } + + @Override + public IPage parentList(Map dict, Query query) { + IPage page = this.page(Condition.getPage(query), Condition.getQueryWrapper(dict, DictBiz.class).lambda().eq(DictBiz::getParentId, CommonConstant.TOP_PARENT_ID).orderByAsc(DictBiz::getSort)); + return DictBizWrapper.build().pageVO(page); + } + + @Override + public List childList(Map dict, Long parentId) { + if (parentId < 0) { + return new ArrayList<>(); + } + dict.remove("parentId"); + DictBiz parentDict = DictBizCache.getById(parentId); + List list = this.list(Condition.getQueryWrapper(dict, DictBiz.class).lambda().ne(DictBiz::getId, parentId).eq(DictBiz::getCode, parentDict.getCode()).orderByAsc(DictBiz::getSort)); + return DictBizWrapper.build().listNodeVO(list); + } +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/MenuServiceImpl.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/MenuServiceImpl.java new file mode 100644 index 0000000..ef25020 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/MenuServiceImpl.java @@ -0,0 +1,187 @@ +package org.springblade.auth.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.AllArgsConstructor; +import org.springblade.auth.system.dto.MenuDTO; +import org.springblade.auth.system.entity.Menu; +import org.springblade.auth.system.entity.RoleMenu; +import org.springblade.auth.system.mapper.MenuMapper; +import org.springblade.auth.system.service.IMenuService; +import org.springblade.auth.system.service.IRoleMenuService; +import org.springblade.auth.system.vo.MenuVO; +import org.springblade.auth.system.wrapper.MenuWrapper; +import org.springblade.core.secure.BladeUser; +import org.springblade.core.secure.utils.AuthUtil; +import org.springblade.core.tool.constant.BladeConstant; +import org.springblade.core.tool.node.ForestNodeMerger; +import org.springblade.core.tool.support.Kv; +import org.springblade.core.tool.utils.Func; +import org.springblade.core.tool.utils.StringUtil; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.springblade.core.cache.constant.CacheConstant.MENU_CACHE; + +/** + * 服务实现类 + * + * @author Chill + */ +@Service +@AllArgsConstructor +public class MenuServiceImpl extends ServiceImpl implements IMenuService { + + private final IRoleMenuService roleMenuService; + private final static String PARENT_ID = "parentId"; + private final static Integer MENU_CATEGORY = 1; + + @Override + public List lazyList(Long parentId, Map param) { + if (Func.isEmpty(Func.toStr(param.get(PARENT_ID)))) { + parentId = null; + } + return baseMapper.lazyList(parentId, param); + } + + @Override + public List lazyMenuList(Long parentId, Map param) { + if (Func.isEmpty(Func.toStr(param.get(PARENT_ID)))) { + parentId = null; + } + return baseMapper.lazyMenuList(parentId, param); + } + + + @Override + public List routes(String roleId, Long topMenuId) { + if (StringUtil.isBlank(roleId)) { + return null; + } + List allMenus = baseMapper.allMenu(); + List roleMenus; + // 超级管理员并且不是顶部菜单请求则返回全部菜单 + if (AuthUtil.isAdministrator() && Func.isEmpty(topMenuId)) { + roleMenus = allMenus; + } + // 非超级管理员并且不是顶部菜单请求则返回对应角色权限菜单 + else if (!AuthUtil.isAdministrator() && Func.isEmpty(topMenuId)) { + roleMenus = baseMapper.roleMenuByRoleId(Func.toLongList(roleId)); + } + // 顶部菜单请求返回对应角色权限菜单 + else { + // 角色配置对应菜单 + List roleIdMenus = baseMapper.roleMenuByRoleId(Func.toLongList(roleId)); + // 反向递归角色菜单所有父级 + List routes = new LinkedList<>(roleIdMenus); + roleIdMenus.forEach(roleMenu -> recursion(allMenus, routes, roleMenu)); + // 顶部配置对应菜单 + List topIdMenus = baseMapper.roleMenuByTopMenuId(topMenuId); + // 筛选匹配角色对应的权限菜单 + roleMenus = topIdMenus.stream().filter(x -> + routes.stream().anyMatch(route -> route.getId().longValue() == x.getId().longValue()) + ).collect(Collectors.toList()); + } + return buildRoutes(allMenus, roleMenus); + } + + private List buildRoutes(List allMenus, List roleMenus) { + List routes = new LinkedList<>(roleMenus); + roleMenus.forEach(roleMenu -> recursion(allMenus, routes, roleMenu)); + routes.sort(Comparator.comparing(Menu::getSort)); + MenuWrapper menuWrapper = new MenuWrapper(); + List collect = routes.stream().filter(x -> Func.equals(x.getCategory(), 1)).collect(Collectors.toList()); + return menuWrapper.listNodeVO(collect); + } + + private void recursion(List allMenus, List routes, Menu roleMenu) { + Optional menu = allMenus.stream().filter(x -> Func.equals(x.getId(), roleMenu.getParentId())).findFirst(); + if (menu.isPresent() && !routes.contains(menu.get())) { + routes.add(menu.get()); + recursion(allMenus, routes, menu.get()); + } + } + + @Override + public List buttons(String roleId) { + List buttons = (AuthUtil.isAdministrator()) ? baseMapper.allButtons() : baseMapper.buttons(Func.toLongList(roleId)); + MenuWrapper menuWrapper = new MenuWrapper(); + return menuWrapper.listNodeVO(buttons); + } + + @Override + public List tree() { + return ForestNodeMerger.merge(baseMapper.tree()); + } + + @Override + public List grantTree(BladeUser user) { + return ForestNodeMerger.merge(user.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID) ? baseMapper.grantTree() : baseMapper.grantTreeByRole(Func.toLongList(user.getRoleId()))); + } + + @Override + public List roleTreeKeys(String roleIds) { + List roleMenus = roleMenuService.list(Wrappers.query().lambda().in(RoleMenu::getRoleId, Func.toLongList(roleIds))); + return roleMenus.stream().map(roleMenu -> Func.toStr(roleMenu.getMenuId())).collect(Collectors.toList()); + } + + + @Override + @Cacheable(cacheNames = MENU_CACHE, key = "'auth:routes:' + #user.roleId") + public List authRoutes(BladeUser user) { + List routes = baseMapper.authRoutes(Func.toLongList(user.getRoleId())); + List list = new ArrayList<>(); + routes.forEach(route -> list.add(Kv.create().set(route.getPath(), Kv.create().set("authority", Func.toStrArray(route.getAlias()))))); + return list; + } + + @Override + public boolean removeMenu(String ids) { + Integer cnt = baseMapper.selectCount(Wrappers.query().lambda().in(Menu::getParentId, Func.toLongList(ids))); + if (cnt > 0) { + throw new RuntimeException("请先删除子节点!"); + } + return removeByIds(Func.toLongList(ids)); + } + + @Override + public boolean submit(Menu menu) { + LambdaQueryWrapper menuQueryWrapper = Wrappers.lambdaQuery(); + if (menu.getId() == null) { + menuQueryWrapper.eq(Menu::getCode, menu.getCode()).or( + wrapper -> wrapper.eq(Menu::getName, menu.getName()).eq(Menu::getCategory, MENU_CATEGORY) + ); + } else { + menuQueryWrapper.ne(Menu::getId, menu.getId()).and( + wrapper -> wrapper.eq(Menu::getCode, menu.getCode()).or( + o -> o.eq(Menu::getName, menu.getName()).eq(Menu::getCategory, MENU_CATEGORY) + ) + ); + } + Integer cnt = baseMapper.selectCount(menuQueryWrapper); + if (cnt > 0) { + throw new RuntimeException("菜单名或编号已存在!"); + } + if (menu.getParentId() == null && menu.getId() == null) { + menu.setParentId(BladeConstant.TOP_PARENT_ID); + } + if (menu.getParentId() != null && menu.getId() == null) { + Menu parentMenu = baseMapper.selectById(menu.getParentId()); + if (parentMenu != null && parentMenu.getCategory() != 1) { + throw new RuntimeException("父节点只可选择菜单类型!"); + } + } + menu.setIsDeleted(BladeConstant.DB_NOT_DELETED); + return saveOrUpdate(menu); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/RoleMenuServiceImpl.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/RoleMenuServiceImpl.java new file mode 100644 index 0000000..d0b387c --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/RoleMenuServiceImpl.java @@ -0,0 +1,17 @@ +package org.springblade.auth.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springblade.auth.system.entity.RoleMenu; +import org.springblade.auth.system.mapper.RoleMenuMapper; +import org.springblade.auth.system.service.IRoleMenuService; +import org.springframework.stereotype.Service; + +/** + * 服务实现类 + * + * @author Chill + */ +@Service +public class RoleMenuServiceImpl extends ServiceImpl implements IRoleMenuService { + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/RoleServiceImpl.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/RoleServiceImpl.java new file mode 100644 index 0000000..4acb257 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/RoleServiceImpl.java @@ -0,0 +1,152 @@ +package org.springblade.auth.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.AllArgsConstructor; +import org.springblade.auth.system.entity.Role; +import org.springblade.auth.system.entity.RoleMenu; +import org.springblade.auth.system.mapper.RoleMapper; +import org.springblade.auth.system.service.IRoleMenuService; +import org.springblade.auth.system.service.IRoleService; +import org.springblade.auth.system.vo.RoleVO; +import org.springblade.auth.system.wrapper.RoleWrapper; +import org.springblade.core.secure.utils.AuthUtil; +import org.springblade.core.tool.constant.BladeConstant; +import org.springblade.core.tool.constant.RoleConstant; +import org.springblade.core.tool.node.ForestNodeMerger; +import org.springblade.core.tool.utils.CollectionUtil; +import org.springblade.core.tool.utils.Func; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 服务实现类 + * + * @author Chill + */ +@Service +@Validated +@AllArgsConstructor +public class RoleServiceImpl extends ServiceImpl implements IRoleService { + + private final IRoleMenuService roleMenuService; + + @Override + public IPage selectRolePage(IPage page, RoleVO role) { + return page.setRecords(baseMapper.selectRolePage(page, role)); + } + + @Override + public List tree(String tenantId) { + String userRole = AuthUtil.getUserRole(); + String excludeRole = null; + if (!CollectionUtil.contains(Func.toStrArray(userRole), RoleConstant.ADMIN) && !CollectionUtil.contains(Func.toStrArray(userRole), RoleConstant.ADMINISTRATOR)) { + excludeRole = RoleConstant.ADMINISTRATOR; + } + return ForestNodeMerger.merge(baseMapper.tree(tenantId, excludeRole)); + } + + private boolean grantRoleMenu(List roleIds, List menuIds) { + // 防止越权配置超管角色 + int administratorCount = baseMapper.selectCount(Wrappers.query().lambda().eq(Role::getRoleAlias, RoleConstant.ADMINISTRATOR).in(Role::getId, roleIds)); + if (!AuthUtil.isAdministrator() && administratorCount > 0) { + throw new RuntimeException("无权配置超管角色!"); + } + // 防止越权配置管理员角色 + //int adminCount = baseMapper.selectCount(Wrappers.query().lambda().eq(Role::getRoleAlias, RoleConstant.ADMIN).in(Role::getId, roleIds)); + //if (!AuthUtil.isAdmin() && adminCount > 0) { +// throw new ServiceException("无权配置管理员角色!"); +// } + // 删除角色配置的菜单集合 + roleMenuService.remove(Wrappers.update().lambda().in(RoleMenu::getRoleId, roleIds)); + // 组装配置 + List roleMenus = new ArrayList<>(); + roleIds.forEach(roleId -> menuIds.forEach(menuId -> { + RoleMenu roleMenu = new RoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + roleMenus.add(roleMenu); + })); + // 新增配置 + roleMenuService.saveBatch(roleMenus); + // 递归设置下属角色菜单集合 + recursionRoleMenu(roleIds, menuIds); + return true; + } + + private void recursionRoleMenu(List roleIds, List menuIds) { + roleIds.forEach(roleId -> baseMapper.selectList(Wrappers.query().lambda().eq(Role::getParentId, roleId)).forEach(role -> { + List roleMenuList = roleMenuService.list(Wrappers.query().lambda().eq(RoleMenu::getRoleId, role.getId())); + // 子节点过滤出父节点删除的菜单集合 + List collectRoleMenuIds = roleMenuList.stream().map(RoleMenu::getMenuId).filter(menuId -> !menuIds.contains(menuId)).collect(Collectors.toList()); + if (collectRoleMenuIds.size() > 0) { + // 删除子节点权限外的菜单集合 + roleMenuService.remove(Wrappers.update().lambda().eq(RoleMenu::getRoleId, role.getId()).in(RoleMenu::getMenuId, collectRoleMenuIds)); + // 递归设置下属角色菜单集合 + recursionRoleMenu(Collections.singletonList(role.getId()), menuIds); + } + })); + } + + @Override + public String getRoleIds(String tenantId, String roleNames) { + List roleList = baseMapper.selectList(Wrappers.query().lambda().eq(Role::getTenantId, tenantId).in(Role::getRoleName, Func.toStrList(roleNames))); + if (roleList != null && roleList.size() > 0) { + return roleList.stream().map(role -> Func.toStr(role.getId())).distinct().collect(Collectors.joining(",")); + } + return null; + } + + @Override + public List getRoleNames(String roleIds) { + return baseMapper.getRoleNames(Func.toLongArray(roleIds)); + } + + @Override + public List getRoleAliases(String roleIds) { + return baseMapper.getRoleAliases(Func.toLongArray(roleIds)); + } + + @Override + public boolean submit(Role role) { + if (!AuthUtil.isAdministrator()) { + if (Func.toStr(role.getRoleAlias()).equals(RoleConstant.ADMINISTRATOR)) { + throw new RuntimeException("无权限创建超管角色!"); + } + } + if (Func.isEmpty(role.getParentId())) { + role.setTenantId(AuthUtil.getTenantId()); + role.setParentId(BladeConstant.TOP_PARENT_ID); + } + if (role.getParentId() > 0) { + Role parent = getById(role.getParentId()); + if (Func.toLong(role.getParentId()) == Func.toLong(role.getId())) { + throw new RuntimeException("父节点不可选择自身!"); + } + role.setTenantId(parent.getTenantId()); + } + role.setIsDeleted(BladeConstant.DB_NOT_DELETED); + return saveOrUpdate(role); + } + + @Override + public List search(String roleName, Long parentId) { + LambdaQueryWrapper queryWrapper = Wrappers.query().lambda(); + if (Func.isNotEmpty(roleName)) { + queryWrapper.like(Role::getRoleName, roleName); + } + if (Func.isNotEmpty(parentId) && parentId > 0L) { + queryWrapper.eq(Role::getParentId, parentId); + } + List roleList = baseMapper.selectList(queryWrapper); + return RoleWrapper.build().listNodeVO(roleList); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/UserServiceImpl.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..be1a733 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/service/impl/UserServiceImpl.java @@ -0,0 +1,159 @@ +package org.springblade.auth.system.service.impl; + + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springblade.auth.system.cache.SysCache; +import org.springblade.auth.system.entity.User; +import org.springblade.auth.system.entity.UserInfo; +import org.springblade.auth.system.mapper.UserMapper; +import org.springblade.auth.system.service.IRoleService; +import org.springblade.auth.system.service.IUserService; +import org.springblade.auth.system.vo.UserVO; +import org.springblade.auth.system.wrapper.UserWrapper; +import org.springblade.common.constant.CommonConstant; +import org.springblade.core.mp.base.BaseServiceImpl; +import org.springblade.core.mp.support.Condition; +import org.springblade.core.mp.support.Query; +import org.springblade.core.secure.utils.AuthUtil; +import org.springblade.core.tenant.BladeTenantProperties; +import org.springblade.core.tool.api.R; +import org.springblade.core.tool.constant.BladeConstant; +import org.springblade.core.tool.support.Kv; +import org.springblade.core.tool.utils.DateUtil; +import org.springblade.core.tool.utils.DigestUtil; +import org.springblade.core.tool.utils.Func; +import org.springblade.core.tool.utils.StringUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 服务实现类 + * + * @author Chill + */ +@Service +@RequiredArgsConstructor +public class UserServiceImpl extends BaseServiceImpl implements IUserService { + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean submit(User user) { + if (StringUtil.isBlank(user.getTenantId())) { + user.setTenantId(BladeConstant.ADMIN_TENANT_ID); + } + if (Func.isNotEmpty(user.getPassword())) { + user.setPassword(DigestUtil.encrypt(user.getPassword())); + } + Integer userCount = baseMapper.selectCount(Wrappers.query().lambda().eq(User::getTenantId, user.getTenantId()).eq(User::getAccount, user.getAccount())); + if (userCount > 0 && Func.isEmpty(user.getId())) { + throw new RuntimeException(StringUtil.format("当前用户 [{}] 已存在!", user.getAccount())); + } + return save(user); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateUser(User user) { + String tenantId = user.getTenantId(); + Integer userCount = baseMapper.selectCount( + Wrappers.query().lambda() + .eq(User::getTenantId, tenantId) + .eq(User::getAccount, user.getAccount()) + .notIn(User::getId, user.getId()) + ); + if (userCount > 0) { + throw new RuntimeException(StringUtil.format("当前用户 [{}] 已存在!", user.getAccount())); + } + return updateUserInfo(user); + } + + @Override + public boolean updateUserInfo(User user) { + user.setPassword(null); + return updateById(user); + } + + @Override + public IPage selectUserPage(IPage page, User user, Long deptId, String tenantId) { + return page.setRecords(baseMapper.selectUserPage(page, user, null, tenantId)); + } + + @Override + public IPage selectUserSearch(UserVO user, Query query) { + LambdaQueryWrapper queryWrapper = Wrappers.query().lambda(); + if (StringUtil.isNotBlank(user.getName())) { + queryWrapper.like(User::getName, user.getName()); + } + IPage pages = this.page(Condition.getPage(query), queryWrapper); + return UserWrapper.build().pageVO(pages); + } + + @Override + public User userByAccount(String tenantId, String account) { + return baseMapper.selectOne(Wrappers.query().lambda().eq(User::getTenantId, tenantId).eq(User::getAccount, account).eq(User::getIsDeleted, BladeConstant.DB_NOT_DELETED)); + } + + @Override + public UserInfo userInfo(Long userId) { + User user = baseMapper.selectById(userId); + return buildUserInfo(user); + } + + @Override + public UserInfo userInfo(String tenantId, String account) { + User user = baseMapper.getUser(tenantId, account); + return buildUserInfo(user); + } + + private UserInfo buildUserInfo(User user) { + UserInfo userInfo = new UserInfo(); + userInfo.setUser(user); + if (Func.isNotEmpty(user)) { + userInfo.setRoles(SysCache.getRoleAliases(user.getRoleId())); + } + userInfo.setDetail(Kv.create().set("type", "web")); + return userInfo; + } + + + @Override + public boolean grant(String userIds, String roleIds) { + User user = new User(); + user.setRoleId(roleIds); + return this.update(user, Wrappers.update().lambda().in(User::getId, Func.toLongList(userIds))); + } + + @Override + public boolean resetPassword(String userIds) { + User user = new User(); + user.setPassword(DigestUtil.encrypt(CommonConstant.DEFAULT_PASSWORD)); + user.setUpdateTime(DateUtil.now()); + return this.update(user, Wrappers.update().lambda().in(User::getId, Func.toLongList(userIds))); + } + + @Override + public boolean updatePassword(Long userId, String oldPassword, String newPassword, String newPassword1) { + User user = getById(userId); + if (!newPassword.equals(newPassword1)) { + throw new RuntimeException("请输入正确的确认密码!"); + } + if (!user.getPassword().equals(DigestUtil.hex(oldPassword))) { + throw new RuntimeException("原密码不正确!"); + } + return this.update(Wrappers.update().lambda().set(User::getPassword, DigestUtil.hex(newPassword)).eq(User::getId, userId)); + } + + @Override + public boolean removeUser(String userIds) { + if (Func.contains(Func.toLongArray(userIds), AuthUtil.getUserId())) { + throw new RuntimeException("不能删除本账号!"); + } + return deleteLogic(Func.toLongList(userIds)); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/DictBizVO.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/DictBizVO.java new file mode 100644 index 0000000..b4325d8 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/DictBizVO.java @@ -0,0 +1,55 @@ +package org.springblade.auth.system.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.core.tool.node.INode; +import org.springblade.auth.system.entity.DictBiz; + +import java.util.ArrayList; +import java.util.List; + +/** + * 视图实体类 + * + * @author Chill + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel(value = "DictBizVO对象", description = "DictBizVO对象") +public class DictBizVO extends DictBiz implements INode { + private static final long serialVersionUID = 1L; + /** + * 主键ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** + * 父节点ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long parentId; + + /** + * 子孙节点 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List children; + + @Override + public List getChildren() { + if (this.children == null) { + this.children = new ArrayList<>(); + } + return this.children; + } + + /** + * 上级字典 + */ + private String parentName; +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/MenuVO.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/MenuVO.java new file mode 100644 index 0000000..2b06c40 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/MenuVO.java @@ -0,0 +1,62 @@ +package org.springblade.auth.system.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.core.tool.node.INode; +import org.springblade.auth.system.entity.Menu; + +import java.util.ArrayList; +import java.util.List; + +/** + * 视图实体类 + * + * @author Chill + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel(value = "MenuVO对象", description = "MenuVO对象") +public class MenuVO extends Menu implements INode { + private static final long serialVersionUID = 1L; + /** + * 子孙节点 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List children; + + /** + * 是否有子孙节点 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Boolean hasChildren; + + @Override + public List getChildren() { + if (this.children == null) { + this.children = new ArrayList<>(); + } + return this.children; + } + + /** + * 上级菜单 + */ + private String parentName; + + /** + * 菜单类型 + */ + private String categoryName; + + /** + * 按钮功能 + */ + private String actionName; + + /** + * 是否新窗口打开 + */ + private String isOpenName; +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/RoleMenuVO.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/RoleMenuVO.java new file mode 100644 index 0000000..2ef34b0 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/RoleMenuVO.java @@ -0,0 +1,19 @@ +package org.springblade.auth.system.vo; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.auth.system.entity.RoleMenu; + +/** + * 视图实体类 + * + * @author Chill + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel(value = "RoleMenuVO对象", description = "RoleMenuVO对象") +public class RoleMenuVO extends RoleMenu { + private static final long serialVersionUID = 1L; + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/RoleVO.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/RoleVO.java new file mode 100644 index 0000000..f03ba79 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/RoleVO.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.core.tool.node.INode; +import org.springblade.auth.system.entity.Role; + +import java.util.ArrayList; +import java.util.List; + +/** + * 视图实体类 + * + * @author Chill + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel(value = "RoleVO对象", description = "RoleVO对象") +public class RoleVO extends Role implements INode { + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** + * 父节点ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long parentId; + + /** + * 子孙节点 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List children; + + @Override + public List getChildren() { + if (this.children == null) { + this.children = new ArrayList<>(); + } + return this.children; + } + + /** + * 上级角色 + */ + private String parentName; +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/UserVO.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/UserVO.java new file mode 100644 index 0000000..5090440 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/vo/UserVO.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.vo; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.auth.system.entity.User; + +/** + * 视图实体类 + * + * @author Chill + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel(value = "UserVO对象", description = "UserVO对象") +public class UserVO extends User { + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** + * 密码 + */ + @JsonIgnore + private String password; + + /** + * 租户名 + */ + private String tenantName; + + /** + * 角色名 + */ + private String roleName; + + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/DictBizWrapper.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/DictBizWrapper.java new file mode 100644 index 0000000..19ab1be --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/DictBizWrapper.java @@ -0,0 +1,45 @@ +package org.springblade.auth.system.wrapper; + +import org.springblade.core.mp.support.BaseEntityWrapper; +import org.springblade.core.tool.constant.BladeConstant; +import org.springblade.core.tool.node.ForestNodeMerger; +import org.springblade.core.tool.utils.BeanUtil; +import org.springblade.core.tool.utils.Func; +import org.springblade.auth.system.cache.DictBizCache; +import org.springblade.auth.system.entity.DictBiz; +import org.springblade.auth.system.vo.DictBizVO; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + + +/** + * 包装类,返回视图层所需的字段 + * + * @author Chill + */ +public class DictBizWrapper extends BaseEntityWrapper { + + public static DictBizWrapper build() { + return new DictBizWrapper(); + } + + @Override + public DictBizVO entityVO(DictBiz dict) { + DictBizVO dictVO = Objects.requireNonNull(BeanUtil.copy(dict, DictBizVO.class)); + if (Func.equals(dict.getParentId(), BladeConstant.TOP_PARENT_ID)) { + dictVO.setParentName(BladeConstant.TOP_PARENT_NAME); + } else { + DictBiz parent = DictBizCache.getById(dict.getParentId()); + dictVO.setParentName(parent.getDictValue()); + } + return dictVO; + } + + public List listNodeVO(List list) { + List collect = list.stream().map(dict -> BeanUtil.copy(dict, DictBizVO.class)).collect(Collectors.toList()); + return ForestNodeMerger.merge(collect); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/MenuWrapper.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/MenuWrapper.java new file mode 100644 index 0000000..e8ab548 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/MenuWrapper.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.system.wrapper; + +import org.springblade.core.mp.support.BaseEntityWrapper; +import org.springblade.core.tool.constant.BladeConstant; +import org.springblade.core.tool.node.ForestNodeMerger; +import org.springblade.core.tool.utils.BeanUtil; +import org.springblade.core.tool.utils.Func; +import org.springblade.auth.system.cache.SysCache; +import org.springblade.auth.system.entity.Menu; +import org.springblade.auth.system.vo.MenuVO; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 包装类,返回视图层所需的字段 + * + * @author Chill + */ +public class MenuWrapper extends BaseEntityWrapper { + + public static MenuWrapper build() { + return new MenuWrapper(); + } + + @Override + public MenuVO entityVO(Menu menu) { + MenuVO menuVO = Objects.requireNonNull(BeanUtil.copy(menu, MenuVO.class)); + if (Func.equals(menu.getParentId(), BladeConstant.TOP_PARENT_ID)) { + menuVO.setParentName(BladeConstant.TOP_PARENT_NAME); + } else { + Menu parent = SysCache.getMenu(menu.getParentId()); + menuVO.setParentName(parent.getName()); + } + return menuVO; + } + + public List listNodeVO(List list) { + List collect = list.stream().map(menu -> BeanUtil.copy(menu, MenuVO.class)).collect(Collectors.toList()); + return ForestNodeMerger.merge(collect); + } + + public List listNodeLazyVO(List list) { + return ForestNodeMerger.merge(list); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/RoleWrapper.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/RoleWrapper.java new file mode 100644 index 0000000..04011a8 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/RoleWrapper.java @@ -0,0 +1,45 @@ +package org.springblade.auth.system.wrapper; + +import org.springblade.core.mp.support.BaseEntityWrapper; +import org.springblade.core.tool.constant.BladeConstant; +import org.springblade.core.tool.node.ForestNodeMerger; +import org.springblade.core.tool.utils.BeanUtil; +import org.springblade.core.tool.utils.Func; +import org.springblade.auth.system.cache.SysCache; +import org.springblade.auth.system.entity.Role; +import org.springblade.auth.system.vo.RoleVO; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 包装类,返回视图层所需的字段 + * + * @author Chill + */ +public class RoleWrapper extends BaseEntityWrapper { + + public static RoleWrapper build() { + return new RoleWrapper(); + } + + @Override + public RoleVO entityVO(Role role) { + RoleVO roleVO = Objects.requireNonNull(BeanUtil.copy(role, RoleVO.class)); + if (Func.equals(role.getParentId(), BladeConstant.TOP_PARENT_ID)) { + roleVO.setParentName(BladeConstant.TOP_PARENT_NAME); + } else { + Role parent = SysCache.getRole(role.getParentId()); + roleVO.setParentName(parent.getRoleName()); + } + return roleVO; + } + + + public List listNodeVO(List list) { + List collect = list.stream().map(this::entityVO).collect(Collectors.toList()); + return ForestNodeMerger.merge(collect); + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/UserWrapper.java b/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/UserWrapper.java new file mode 100644 index 0000000..11c8710 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/system/wrapper/UserWrapper.java @@ -0,0 +1,32 @@ +package org.springblade.auth.system.wrapper; + +import org.springblade.core.mp.support.BaseEntityWrapper; +import org.springblade.core.tool.utils.BeanUtil; +import org.springblade.core.tool.utils.Func; +import org.springblade.auth.system.cache.SysCache; +import org.springblade.auth.system.entity.User; +import org.springblade.auth.system.vo.UserVO; + +import java.util.List; +import java.util.Objects; + +/** + * 包装类,返回视图层所需的字段 + * + * @author Chill + */ +public class UserWrapper extends BaseEntityWrapper { + + public static UserWrapper build() { + return new UserWrapper(); + } + + @Override + public UserVO entityVO(User user) { + UserVO userVO = Objects.requireNonNull(BeanUtil.copy(user, UserVO.class)); + List roleName = SysCache.getRoleNames(user.getRoleId()); + userVO.setRoleName(Func.join(roleName)); + return userVO; + } + +} diff --git a/kn-sys-manager/src/main/java/org/springblade/auth/utils/TokenUtil.java b/kn-sys-manager/src/main/java/org/springblade/auth/utils/TokenUtil.java new file mode 100644 index 0000000..0119590 --- /dev/null +++ b/kn-sys-manager/src/main/java/org/springblade/auth/utils/TokenUtil.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.auth.utils; + +import lombok.SneakyThrows; +import org.springblade.core.launch.constant.TokenConstant; +import org.springblade.core.tenant.BladeTenantProperties; +import org.springblade.core.tool.utils.Charsets; +import org.springblade.core.tool.utils.SpringUtil; +import org.springblade.core.tool.utils.StringPool; +import org.springblade.core.tool.utils.WebUtil; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException; + +import java.util.Base64; +import java.util.Calendar; + +/** + * 认证工具类 + * + * @author Chill + */ +public class TokenUtil { + + public final static String AVATAR = TokenConstant.AVATAR; + public final static String ACCOUNT = TokenConstant.ACCOUNT; + public final static String USER_NAME = TokenConstant.USER_NAME; + public final static String NICK_NAME = TokenConstant.NICK_NAME; + public final static String REAL_NAME = TokenConstant.REAL_NAME; + public final static String USER_ID = TokenConstant.USER_ID; + public final static String DEPT_ID = TokenConstant.DEPT_ID; + public final static String POST_ID = TokenConstant.POST_ID; + public final static String ROLE_ID = TokenConstant.ROLE_ID; + public final static String ROLE_NAME = TokenConstant.ROLE_NAME; + public final static String TENANT_ID = TokenConstant.TENANT_ID; + public final static String OAUTH_ID = TokenConstant.OAUTH_ID; + public final static String CLIENT_ID = TokenConstant.CLIENT_ID; + public final static String DETAIL = TokenConstant.DETAIL; + public final static String EMAIL = "email"; + public final static String DEPT_HEADER_KEY = "Dept-Id"; + public final static String ROLE_HEADER_KEY = "Role-Id"; + public final static String MOBILE_HEADER_KEY = "Mobile-Key"; + public final static String MOBILE_HEADER_CODE = "Mobile-Code"; + public final static String CAPTCHA_HEADER_KEY = "Captcha-Key"; + public final static String CAPTCHA_HEADER_CODE = "Captcha-Code"; + public final static String CAPTCHA_NOT_CORRECT = "验证码不正确"; + public final static String TENANT_HEADER_KEY = "Tenant-Id"; + public final static String TENANT_PARAM_KEY = "tenant_id"; + public final static String DEFAULT_TENANT_ID = "000000"; + public final static String TENANT_NOT_FOUND = "租户ID未找到"; + public final static String USER_TYPE_HEADER_KEY = "User-Type"; + public final static String DEFAULT_USER_TYPE = "web"; + public final static String USER_NOT_FOUND = "用户名或密码错误"; + public final static String USER_HAS_NO_ROLE = "未获得用户的角色信息"; + public final static String USER_HAS_NO_TENANT = "未获得用户的租户信息"; + public final static String USER_HAS_NO_TENANT_PERMISSION = "租户授权已过期,请联系管理员"; + public final static String USER_HAS_TOO_MANY_FAILS = "登录错误次数过多,请稍后再试"; + public final static String HEADER_KEY = "Authorization"; + public final static String HEADER_PREFIX = "Basic "; + public final static String DEFAULT_AVATAR = ""; + public final static String PASSWORD_KEY = "password"; + public final static String GRANT_TYPE_KEY = "grant_type"; + public final static String REFRESH_TOKEN_KEY = "refresh_token"; + public final static String LICENSE_NAME = "KeNing"; + private static BladeTenantProperties tenantProperties; + + /** + * 获取租户配置 + * + * @return tenantProperties + */ + private static BladeTenantProperties getTenantProperties() { + if (tenantProperties == null) { + tenantProperties = SpringUtil.getBean(BladeTenantProperties.class); + } + return tenantProperties; + } + + /** + * 解码 + */ + @SneakyThrows + public static String[] extractAndDecodeHeader() { + String header = WebUtil.getRequest().getHeader(TokenUtil.HEADER_KEY); + if (header == null || !header.startsWith(TokenUtil.HEADER_PREFIX)) { + throw new UnapprovedClientAuthenticationException("请求头中无client信息"); + } + + byte[] base64Token = header.substring(6).getBytes(Charsets.UTF_8_NAME); + + byte[] decoded; + try { + decoded = Base64.getDecoder().decode(base64Token); + } catch (IllegalArgumentException var7) { + throw new BadCredentialsException("Failed to decode basic authentication token"); + } + + String token = new String(decoded, Charsets.UTF_8_NAME); + int index = token.indexOf(StringPool.COLON); + if (index == -1) { + throw new BadCredentialsException("Invalid basic authentication token"); + } else { + return new String[]{token.substring(0, index), token.substring(index + 1)}; + } + } + + /** + * 获取请求头中的客户端id + */ + public static String getClientIdFromHeader() { + String[] tokens = extractAndDecodeHeader(); + return tokens[0]; + } + + /** + * 获取token过期时间(次日凌晨3点) + * + * @return expire + */ + public static int getTokenValiditySecond() { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, 1); + cal.set(Calendar.HOUR_OF_DAY, 3); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.MILLISECOND, 0); + return (int) (cal.getTimeInMillis() - System.currentTimeMillis()) / 1000; + } + + /** + * 获取refreshToken过期时间 + * + * @return expire + */ + public static int getRefreshTokenValiditySeconds() { + return 60 * 60 * 24 * 15; + } + +} diff --git a/kn-sys-manager/src/main/resources/application-dev.yml b/kn-sys-manager/src/main/resources/application-dev.yml new file mode 100644 index 0000000..14c252c --- /dev/null +++ b/kn-sys-manager/src/main/resources/application-dev.yml @@ -0,0 +1,19 @@ +#服务器端口 +server: + port: 8100 + +#数据源配置 +spring: + datasource: + url: ${blade.datasource.dev.url} + username: ${blade.datasource.dev.username} + password: ${blade.datasource.dev.password} + +#第三方登陆 +social: + enabled: true + domain: http://127.0.0.1:1888 + + +mobile: + enabled: true diff --git a/kn-sys-manager/src/main/resources/application-prod.yml b/kn-sys-manager/src/main/resources/application-prod.yml new file mode 100644 index 0000000..7297d88 --- /dev/null +++ b/kn-sys-manager/src/main/resources/application-prod.yml @@ -0,0 +1,18 @@ +#服务器端口 +server: + port: 8100 + +#数据源配置 +spring: + datasource: + url: ${blade.datasource.prod.url} + username: ${blade.datasource.prod.username} + password: ${blade.datasource.prod.password} + +#第三方登陆 +social: + enabled: true + domain: http://127.0.0.1:1888 + +mobile: + enabled: true diff --git a/kn-sys-manager/src/main/resources/application-test.yml b/kn-sys-manager/src/main/resources/application-test.yml new file mode 100644 index 0000000..3e554a9 --- /dev/null +++ b/kn-sys-manager/src/main/resources/application-test.yml @@ -0,0 +1,18 @@ +#服务器端口 +server: + port: 8100 + +#数据源配置 +spring: + datasource: + url: ${blade.datasource.test.url} + username: ${blade.datasource.test.username} + password: ${blade.datasource.test.password} + +#第三方登陆 +social: + enabled: true + domain: http://127.0.0.1:1888 + +mobile: + enabled: true diff --git a/kn-sys-manager/src/main/resources/application.yml b/kn-sys-manager/src/main/resources/application.yml new file mode 100644 index 0000000..c219b6f --- /dev/null +++ b/kn-sys-manager/src/main/resources/application.yml @@ -0,0 +1,34 @@ +# 在使用Spring默认数据源Hikari的情况下配置以下配置项 +spring: + datasource: + hikari: + # 自动提交从池中返回的连接 + auto-commit: true + # 连接池中维护的最小空闲连接数 + minimum-idle: 10 + # 连接池中允许的最大连接数。缺省值:10;推荐的公式:((core_count * 2) + effective_spindle_count) + maximum-pool-size: 60 + # 空闲连接超时时间,默认值600000(10分钟),大于等于max-lifetime且max-lifetime>0,会被重置为0;不等于0且小于10秒,会被重置为10秒。 + # 只有空闲连接数大于最大连接数且空闲时间超过该值,才会被释放 + idle-timeout: 30000 + # 连接最大存活时间.不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短 + max-lifetime: 1800000 + # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒 + connection-timeout: 30000 + # 连接测试查询 + connection-test-query: select 1 + #connection-test-query: select 1 from dual + +#swagger文档 +swagger: + base-packages: + - org.springblade + - org.springframework.security.oauth2.provider.endpoint + +#第三方登陆 +social: + oauth: + WECHAT_OPEN: + client-id: 233************ + client-secret: 233************************************ + redirect-uri: ${social.domain}/oauth/redirect/wechat diff --git a/pom.xml b/pom.xml index a78703c..551e3b5 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,7 @@ kn-launcher kn-service kn-service-api + kn-sys-manager @@ -70,6 +71,11 @@ kn-launcher ${revision} + + com.kening.platform + kn-common + ${revision} +