zhongrj
2024-04-27 7e82c16716481ee185330c63535936af6ff6af79
去除flow,集成oauth2
9 files modified
18 files added
40 files deleted
6020 ■■■■ changed files
pom.xml 107 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/config/BladeAuthorizationServerConfiguration.java 101 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/config/BladeResourceServerConfiguration.java 41 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/config/JwtTokenStoreConfiguration.java 61 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/config/SecurityConfiguration.java 48 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/constant/AuthConstant.java 37 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/endpoint/BladeSocialEndpoint.java 72 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/endpoint/BladeTokenEndPoint.java 141 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/granter/BladeTokenGranter.java 36 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/granter/CaptchaTokenGranter.java 82 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/granter/SocialTokenGranter.java 110 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/service/BladeClientDetailsServiceImpl.java 35 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/service/BladeUserDetails.java 83 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/service/BladeUserDetailsServiceImpl.java 186 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/support/BladeJwtTokenEnhancer.java 70 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/support/BladeNoOpPasswordEncoder.java 34 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/support/BladePasswordEncoder.java 23 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/support/BladePasswordEncoderFactories.java 51 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/auth/utils/TokenUtil.java 166 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/config/BladeReportConfiguration.java 43 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/config/WxMiniConfig.java 21 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/config/WxPayConfig.java 188 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/utils/ParseMail.java 253 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/utils/SmsUtils.java 127 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/utils/WechatPay2ValidatorForRequest.java 114 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/utils/WeiXinSecurityUtil.java 321 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/business/controller/WorkController.java 146 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/business/service/FlowBusinessService.java 72 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/business/service/IFlowService.java 77 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/business/service/impl/FlowBusinessServiceImpl.java 377 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/business/service/impl/FlowServiceImpl.java 97 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/core/constant/ProcessConstant.java 61 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/core/entity/BladeFlow.java 213 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/core/entity/FlowEntity.java 43 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/core/enums/FlowModeEnum.java 45 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/core/utils/FlowUtil.java 66 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/core/utils/TaskUtil.java 71 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/demo/leave/controller/LeaveController.java 65 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/demo/leave/entity/ProcessLeave.java 67 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/demo/leave/mapper/LeaveMapper.java 29 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/demo/leave/mapper/LeaveMapper.xml 6 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/demo/leave/service/ILeaveService.java 37 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/demo/leave/service/impl/LeaveServiceImpl.java 79 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/demo/package-info.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/config/FlowableConfiguration.java 44 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/constant/FlowEngineConstant.java 52 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/controller/FlowFollowController.java 73 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/controller/FlowManagerController.java 125 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/controller/FlowModelController.java 121 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/controller/FlowProcessController.java 98 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/entity/FlowExecution.java 50 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/entity/FlowModel.java 58 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/entity/FlowProcess.java 65 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/mapper/FlowMapper.java 46 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/mapper/FlowMapper.xml 53 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/service/FlowEngineService.java 165 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/service/impl/FlowEngineServiceImpl.java 562 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/flow/engine/utils/FlowCache.java 80 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/controller/UserController.java 19 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/mapper/UserMapper.java 28 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/mapper/UserMapper.xml 32 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/service/ITenantService.java 2 ●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/service/IUserService.java 5 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/service/impl/MenuServiceImpl.java 20 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java 37 ●●●●● patch | view | raw | blame | history
src/main/resources/application.yml 54 ●●●● patch | view | raw | blame | history
src/main/resources/processes/LeaveProcess.bpmn20.xml 123 ●●●●● patch | view | raw | blame | history
pom.xml
@@ -117,16 +117,6 @@
            <artifactId>blade-core-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 报表 -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-starter-report</artifactId>
        </dependency>
        <!-- 工作流 -->
        <dependency>
            <groupId>org.springblade</groupId>
            <artifactId>blade-starter-flowable</artifactId>
        </dependency>
        <!-- 验证码 -->
        <dependency>
            <groupId>com.github.whvcse</groupId>
@@ -194,56 +184,18 @@
            <artifactId>jts</artifactId>
            <version>1.13</version>
        </dependency>
        <!-- 微信支付 SDK-->
<!--        <dependency>-->
<!--            <groupId>com.github.binarywang</groupId>-->
<!--            <artifactId>weixin-java-pay</artifactId>-->
<!--            <version>4.4.9.B</version>-->
<!--        </dependency>-->
        <!-- 微信支付依赖 -->
        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-apache-httpclient</artifactId>
            <version>0.3.0</version>
        </dependency>
        <!--微信支付 APIv2 SDK-->
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>
        <!--xxl-job-core 相关依赖-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>${netty-all.version}</version>
        </dependency>
        <!-- groovy-all -->
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy</artifactId>
            <version>${groovy.version}</version>
        </dependency>
        <!--邮件依赖-->
        <!--安全模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.github.shyiko/mysql-binlog-connector-java -->
        <dependency>
            <groupId>com.github.shyiko</groupId>
            <artifactId>mysql-binlog-connector-java</artifactId>
            <version>0.17.0</version>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/args4j/args4j -->
        <dependency>
            <groupId>args4j</groupId>
            <artifactId>args4j</artifactId>
            <version>2.33</version>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
@@ -251,51 +203,10 @@
            <version>5.5.4</version>
            <scope>compile</scope>
        </dependency>
        <!-- Tesseract OCR -->
        <dependency>
            <groupId>net.sourceforge.tess4j</groupId>
            <artifactId>tess4j</artifactId>
            <version>4.5.4</version>
        </dependency>
        <!--压缩图片-->
        <dependency>
            <groupId>net.coobird</groupId>
            <artifactId>thumbnailator</artifactId>
            <version>0.4.8</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <!-- ElasticSearch -->
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>-->
<!--            <version>2.7.1</version>-->
<!--        </dependency>-->
        <!--导入了elasticsearch  -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.17.4</version>
            <!--            <version>6.7.2</version>-->
            <exclusions>
                <exclusion>
                    <artifactId>elasticsearch</artifactId>
                    <groupId>org.elasticsearch</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.17.4</version>
<!--            <version>6.7.2</version>-->
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <scope>provided</scope>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
    </dependencies>
src/main/java/org/springblade/auth/config/BladeAuthorizationServerConfiguration.java
New file
@@ -0,0 +1,101 @@
package org.springblade.auth.config;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springblade.auth.constant.AuthConstant;
import org.springblade.auth.granter.BladeTokenGranter;
import org.springblade.auth.service.BladeClientDetailsServiceImpl;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.social.props.SocialProperties;
import org.springblade.modules.system.service.IUserService;
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(proxyBeanMethods = false)
@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;
    private final IUserService userClient;
    private final SocialProperties socialProperties;
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        //获取自定义tokenGranter
        TokenGranter tokenGranter = BladeTokenGranter.getTokenGranter(authenticationManager, endpoints, bladeRedis, userClient, socialProperties);
        //配置端点
        endpoints.tokenStore(tokenStore)
            .authenticationManager(authenticationManager)
            .userDetailsService(userDetailsService)
            .tokenGranter(tokenGranter);
        //扩展token返回结果
        if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) {
            TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
            List<TokenEnhancer> 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) {
        BladeClientDetailsServiceImpl clientDetailsService = new BladeClientDetailsServiceImpl(dataSource);
        clientDetailsService.setSelectClientDetailsSql(AuthConstant.DEFAULT_SELECT_STATEMENT);
        clientDetailsService.setFindClientDetailsSql(AuthConstant.DEFAULT_FIND_STATEMENT);
        clients.withClientDetails(clientDetailsService);
    }
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
        oauthServer
            .allowFormAuthenticationForClients()
            .tokenKeyAccess("permitAll()")
            .checkTokenAccess("isAuthenticated()");
    }
}
src/main/java/org/springblade/auth/config/BladeResourceServerConfiguration.java
New file
@@ -0,0 +1,41 @@
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.ResourceServerConfigurerAdapter;
/**
 * 自定义资源放行
 *
 * @author Chill
 */
@Configuration(proxyBeanMethods = false)
@AllArgsConstructor
public class BladeResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    @Override
    @SneakyThrows
    public void configure(HttpSecurity http) {
        http.authorizeRequests()
            .antMatchers(
                "/actuator/**",
                "/oauth/captcha",
                "/oauth/logout",
                "/oauth/clear-cache",
                "/oauth/render/**",
                "/oauth/callback/**",
                "/oauth/revoke/**",
                "/oauth/refresh/**",
                "/oauth/login",
                "/oauth/form",
                "/token/**",
                "/mobile/**",
                "/static/**",
                "/v2/api-docs").permitAll()
            .anyRequest().authenticated().and()
            .csrf().disable();
    }
}
src/main/java/org/springblade/auth/config/JwtTokenStoreConfiguration.java
New file
@@ -0,0 +1,61 @@
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.jwt.crypto.sign.MacSigner;
import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
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(proxyBeanMethods = false)
@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(getJwtAccessTokenConverter(jwtProperties));
    }
    /**
     * 用于生成jwt
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(JwtProperties jwtProperties) {
        return getJwtAccessTokenConverter(jwtProperties);
    }
    /**
     * 自定义 JwtAccessTokenConverter
     */
    private JwtAccessTokenConverter getJwtAccessTokenConverter(JwtProperties jwtProperties) {
        JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
        accessTokenConverter.setSigningKey(jwtProperties.getSignKey());
        SignatureVerifier verifier = new MacSigner(jwtProperties.getSignKey());
        accessTokenConverter.setVerifier(verifier);
        return accessTokenConverter;
    }
    /**
     * 用于扩展jwt
     */
    @Bean
    @ConditionalOnMissingBean(name = "jwtTokenEnhancer")
    public TokenEnhancer jwtTokenEnhancer(JwtAccessTokenConverter jwtAccessTokenConverter, JwtProperties jwtProperties) {
        return new BladeJwtTokenEnhancer(jwtAccessTokenConverter, jwtProperties);
    }
}
src/main/java/org/springblade/auth/config/SecurityConfiguration.java
New file
@@ -0,0 +1,48 @@
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
 * Security配置
 *
 * @author Chill
 */
@Configuration(proxyBeanMethods = false)
@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.headers().frameOptions().disable();
        http.httpBasic().and().csrf().disable();
        http.formLogin().loginPage("/oauth/login").loginProcessingUrl("/oauth/form");
    }
    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers("/js/*.js", "/css/*.css");
    }
}
src/main/java/org/springblade/auth/constant/AuthConstant.java
New file
@@ -0,0 +1,37 @@
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 = ?";
}
src/main/java/org/springblade/auth/endpoint/BladeSocialEndpoint.java
New file
@@ -0,0 +1,72 @@
package org.springblade.auth.endpoint;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springblade.core.social.props.SocialProperties;
import org.springblade.core.social.utils.SocialUtil;
import org.springblade.core.tenant.annotation.NonDS;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * SocialEndpoint
 *
 * @author Chill
 */
@NonDS
@Slf4j
@RestController
@AllArgsConstructor
@ConditionalOnProperty(value = "social.enabled", havingValue = "true")
public class BladeSocialEndpoint {
    private final SocialProperties socialProperties;
    /**
     * 授权完毕跳转
     */
    @RequestMapping("/oauth/render/{source}")
    public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException {
        AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        response.sendRedirect(authorizeUrl);
    }
    /**
     * 获取认证信息
     */
    @RequestMapping("/oauth/callback/{source}")
    public Object login(@PathVariable("source") String source, AuthCallback callback) {
        AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
        return authRequest.login(callback);
    }
    /**
     * 撤销授权
     */
    @RequestMapping("/oauth/revoke/{source}/{token}")
    public Object revokeAuth(@PathVariable("source") String source, @PathVariable("token") String token) {
        AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
        return authRequest.revoke(AuthToken.builder().accessToken(token).build());
    }
    /**
     * 续期令牌
     */
    @RequestMapping("/oauth/refresh/{source}")
    public Object refreshAuth(@PathVariable("source") String source, String token) {
        AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
        return authRequest.refresh(AuthToken.builder().refreshToken(token).build());
    }
}
src/main/java/org/springblade/auth/endpoint/BladeTokenEndPoint.java
New file
@@ -0,0 +1,141 @@
package org.springblade.auth.endpoint;
import com.wf.captcha.SpecCaptcha;
import lombok.AllArgsConstructor;
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.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import java.time.Duration;
import static org.springblade.core.cache.constant.CacheConstant.*;
/**
 * BladeEndPoint
 *
 * @author Chill
 */
@NonDS
@Slf4j
@RestController
@AllArgsConstructor
public class BladeTokenEndPoint {
    private final BladeRedis bladeRedis;
    private final JwtProperties jwtProperties;
    private final ClientDetailsService clientDetailsService;
    private final TokenStore tokenStore;
    /**
     * 登录页面
     */
    @GetMapping("/oauth/login")
    public ModelAndView require(ModelAndView model) {
        model.setViewName("login");
        return model;
    }
    /**
     * 授权页面
     */
    @GetMapping("/oauth/confirm_access")
    public ModelAndView confirm(HttpSession session, ModelAndView model) {
        Object auth = session.getAttribute("authorizationRequest");
        if (auth != null) {
            AuthorizationRequest authorizationRequest = (AuthorizationRequest) auth;
            model.addObject("client", clientDetailsService.loadClientByClientId(authorizationRequest.getClientId()));
            model.addObject("principal", SecurityContextHolder.getContext().getAuthentication().getPrincipal());
        }
        model.setViewName("confirm");
        return model;
    }
    /**
     * 用户信息
     */
    @GetMapping("/oauth/user-info")
    public R<Authentication> currentUser(Authentication authentication) {
        return R.data(authentication);
    }
    /**
     * 验证码
     */
    @GetMapping("/oauth/captcha")
    public Kv captcha() {
        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
        String verCode = specCaptcha.text().toLowerCase();
        String key = StringUtil.randomUUID();
        // 存入redis并设置过期时间为30分钟
        bladeRedis.setEx(CacheNames.CAPTCHA_KEY + key, verCode, Duration.ofMinutes(30));
        // 将key和base64返回给前端
        return Kv.create().set("key", key).set("image", specCaptcha.toBase64());
    }
    /**
     * 退出登录
     */
    @GetMapping("/oauth/logout")
    public Kv logout() {
        BladeUser user = AuthUtil.getUser();
        String token = JwtUtil.getToken(WebUtil.getRequest().getHeader(TokenConstant.HEADER));
        // 清空redis保存的token
        if (user != null && jwtProperties.getState()) {
            JwtUtil.removeAccessToken(user.getTenantId(), String.valueOf(user.getUserId()), token);
        }
        // 清空资源服务器保存的token
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(token);
        OAuth2RefreshToken refreshToken = null;
        if (accessToken != null && StringUtil.isNoneBlank(accessToken.getValue())) {
            refreshToken = accessToken.getRefreshToken();
            tokenStore.removeAccessToken(accessToken);
        }
        if (refreshToken != null && StringUtil.isNoneBlank(refreshToken.getValue())) {
            tokenStore.removeRefreshToken(refreshToken);
        }
        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");
    }
}
src/main/java/org/springblade/auth/granter/BladeTokenGranter.java
New file
@@ -0,0 +1,36 @@
package org.springblade.auth.granter;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.social.props.SocialProperties;
import org.springblade.modules.system.service.IUserService;
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, IUserService userClient, SocialProperties socialProperties) {
        // 默认tokenGranter集合
        List<TokenGranter> granters = new ArrayList<>(Collections.singletonList(endpoints.getTokenGranter()));
        // 增加验证码模式
        granters.add(new CaptchaTokenGranter(authenticationManager, endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), bladeRedis));
        // 增加第三方登陆模式
        granters.add(new SocialTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), userClient, socialProperties));
        // 组合tokenGranter集合
        return new CompositeTokenGranter(granters);
    }
}
src/main/java/org/springblade/auth/granter/CaptchaTokenGranter.java
New file
@@ -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<String, String> parameters = new LinkedHashMap<String, String>(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);
    }
}
src/main/java/org/springblade/auth/granter/SocialTokenGranter.java
New file
@@ -0,0 +1,110 @@
package org.springblade.auth.granter;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import org.springblade.auth.constant.AuthConstant;
import org.springblade.auth.service.BladeUserDetails;
import org.springblade.auth.utils.TokenUtil;
import org.springblade.core.social.props.SocialProperties;
import org.springblade.core.social.utils.SocialUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.UserInfo;
import org.springblade.modules.system.entity.UserOauth;
import org.springblade.modules.system.service.IUserService;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
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;
import java.util.Objects;
/**
 * 第三方登录认证类
 *
 * @author Chill
 */
public class SocialTokenGranter extends AbstractTokenGranter {
    private static final String GRANT_TYPE = "social";
    private static final Integer AUTH_SUCCESS_CODE = 2000;
    private final IUserService userClient;
    private final SocialProperties socialProperties;
    protected SocialTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, IUserService userClient, SocialProperties socialProperties) {
        super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        this.userClient = userClient;
        this.socialProperties = socialProperties;
    }
    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
        // 请求头租户信息
        HttpServletRequest request = WebUtil.getRequest();
        String tenantId = Func.toStr(request.getHeader(TokenUtil.TENANT_HEADER_KEY), TokenUtil.DEFAULT_TENANT_ID);
        Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
        // 开放平台来源
        String sourceParameter = parameters.get("source");
        // 匹配是否有别名定义
        String source = socialProperties.getAlias().getOrDefault(sourceParameter, sourceParameter);
        // 开放平台授权码
        String code = parameters.get("code");
        // 开放平台状态吗
        String state = parameters.get("state");
        // 获取开放平台授权数据
        AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
        AuthCallback authCallback = new AuthCallback();
        authCallback.setCode(code);
        authCallback.setState(state);
        AuthResponse authResponse = authRequest.login(authCallback);
        AuthUser authUser;
        if (authResponse.getCode() == AUTH_SUCCESS_CODE) {
            authUser = (AuthUser) authResponse.getData();
        } else {
            throw new InvalidGrantException("social grant failure, auth response is not success");
        }
        // 组装数据
        UserOauth userOauth = Objects.requireNonNull(BeanUtil.copy(authUser, UserOauth.class));
        userOauth.setSource(authUser.getSource());
        userOauth.setTenantId(tenantId);
        userOauth.setUuid(authUser.getUuid());
        // 远程调用,获取认证信息
        UserInfo userInfo = userClient.userInfo(userOauth);
        BladeUserDetails bladeUserDetails;
        User user = userInfo.getUser();
        Kv detail = userInfo.getDetail();
        if (user == null || user.getId() == null) {
            throw new InvalidGrantException("social grant failure, user is null");
        }
        bladeUserDetails = new BladeUserDetails(user.getId(),
            tenantId, userInfo.getOauthId(), user.getName(), user.getRealName(), user.getDeptId(), user.getPostId(), user.getRoleId(), Func.join(userInfo.getRoles()), Func.toStr(userOauth.getAvatar(), TokenUtil.DEFAULT_AVATAR),
            userOauth.getUsername(), AuthConstant.ENCRYPT + user.getPassword(), detail, true, true, true, true,
            AuthorityUtils.commaSeparatedStringToAuthorityList(Func.join(userInfo.getRoles())));
        // 组装认证数据,关闭密码校验
        Authentication userAuth = new UsernamePasswordAuthenticationToken(bladeUserDetails, null, bladeUserDetails.getAuthorities());
        ((AbstractAuthenticationToken) userAuth).setDetails(parameters);
        OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
        // 返回 OAuth2Authentication
        return new OAuth2Authentication(storedOAuth2Request, userAuth);
    }
}
src/main/java/org/springblade/auth/service/BladeClientDetailsServiceImpl.java
New file
@@ -0,0 +1,35 @@
package org.springblade.auth.service;
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);
    }
    /**
     * 缓存客户端信息
     *
     * @param clientId 客户端id
     */
    @Override
    public ClientDetails loadClientByClientId(String clientId) {
        try {
            return super.loadClientByClientId(clientId);
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }
}
src/main/java/org/springblade/auth/service/BladeUserDetails.java
New file
@@ -0,0 +1,83 @@
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 Chill
 */
@Getter
public class BladeUserDetails extends User {
    /**
     * 用户id
     */
    private final Long userId;
    /**
     * 租户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 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<? extends GrantedAuthority> authorities) {
        super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
        this.userId = userId;
        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;
    }
}
src/main/java/org/springblade/auth/service/BladeUserDetailsServiceImpl.java
New file
@@ -0,0 +1,186 @@
package org.springblade.auth.service;
import io.jsonwebtoken.Claims;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springblade.auth.constant.AuthConstant;
import org.springblade.auth.utils.TokenUtil;
import org.springblade.common.cache.CacheNames;
import org.springblade.common.cache.ParamCache;
import org.springblade.core.jwt.JwtUtil;
import org.springblade.core.jwt.props.JwtProperties;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.utils.*;
import org.springblade.modules.auth.enums.UserEnum;
import org.springblade.modules.system.entity.Tenant;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.UserInfo;
import org.springblade.modules.system.service.IRoleService;
import org.springblade.modules.system.service.ITenantService;
import org.springblade.modules.system.service.IUserService;
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 Chill
 */
@Service
@AllArgsConstructor
public class BladeUserDetailsServiceImpl implements UserDetailsService {
    public static final Integer FAIL_COUNT = 5;
    public static final String FAIL_COUNT_VALUE = "account.failCount";
    private final IUserService userClient;
    private final ITenantService sysClient;
    private final IRoleService roleService;
    private final BladeRedis bladeRedis;
    private final JwtProperties jwtProperties;
    @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);
        }
        // 判断令牌合法性
        if (!judgeRefreshToken(grantType, request)) {
            throw new UserDeniedAuthorizationException(TokenUtil.TOKEN_NOT_PERMISSION);
        }
        // 指定租户ID
        String tenantId = StringUtils.isBlank(headerTenant) ? paramTenant : headerTenant;
        // 判断登录是否锁定
        int count = getFailCount(tenantId, username);
        int failCount = Func.toInt(ParamCache.getValue(FAIL_COUNT_VALUE), FAIL_COUNT);
        if (count >= failCount) {
            throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_TOO_MANY_FAILS);
        }
        // 获取租户信息
        Tenant tenant = sysClient.getByTenantId(tenantId);
        if (TokenUtil.judgeTenant(tenant)) {
            throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_NO_TENANT_PERMISSION);
        }
        // 获取用户类型
        String userType = Func.toStr(request.getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE);
        // 远程调用返回数据
        UserInfo userInfo;
        // 根据不同用户类型调用对应的接口返回数据,用户可自行拓展
        if (userType.equals(UserEnum.WEB.getName())) {
            userInfo = userClient.userInfo(tenantId, username, UserEnum.WEB.getName());
        } else if (userType.equals(UserEnum.APP.getName())) {
            userInfo = userClient.userInfo(tenantId, username, UserEnum.APP.getName());
        } else {
            userInfo = userClient.userInfo(tenantId, username, UserEnum.OTHER.getName());
        }
        // 判断返回信息
        User user = userInfo.getUser();
        // 用户不存在,但提示用户名与密码错误并锁定账号
        if (user == null || user.getId() == null) {
            setFailCount(tenantId, username, count);
            throw new UsernameNotFoundException(TokenUtil.USER_NOT_FOUND);
        }
        // 用户存在但密码错误,超过次数则锁定账号
        if (grantType != null && !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(headerDept) && user.getDeptId().contains(headerDept)) {
            user.setDeptId(headerDept);
        }
        // 多角色情况下指定单角色
        if (Func.isNotEmpty(headerRole) && user.getRoleId().contains(headerRole)) {
            List<String> roleResult = roleService.getRoleAliases(headerRole);
            userInfo.setRoles(roleResult);
            user.setRoleId(headerRole);
        }
        // 成功则清除登录错误次数
        delFailCount(tenantId, username);
        return new BladeUserDetails(user.getId(),
            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));
    }
    /**
     * 清空账号错误次数
     *
     * @param tenantId 租户id
     * @param username 账号
     */
    private void delFailCount(String tenantId, String username) {
        bladeRedis.del(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username));
    }
    /**
     * 校验refreshToken合法性
     *
     * @param grantType 认证类型
     * @param request   请求
     */
    private boolean judgeRefreshToken(String grantType, HttpServletRequest request) {
        if (jwtProperties.getState() && jwtProperties.getSingle() && StringUtil.equals(grantType, TokenUtil.REFRESH_TOKEN_KEY)) {
            String refreshToken = request.getParameter(TokenUtil.REFRESH_TOKEN_KEY);
            Claims claims = JwtUtil.parseJWT(refreshToken);
            String tenantId = String.valueOf(claims.get("tenant_id"));
            String userId = String.valueOf(claims.get("user_id"));
            String token = JwtUtil.getRefreshToken(tenantId, userId, refreshToken);
            return StringUtil.equalsIgnoreCase(token, refreshToken);
        }
        return true;
    }
}
src/main/java/org/springblade/auth/support/BladeJwtTokenEnhancer.java
New file
@@ -0,0 +1,70 @@
package org.springblade.auth.support;
import lombok.AllArgsConstructor;
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.common.OAuth2RefreshToken;
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
 */
@AllArgsConstructor
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<String, Object> 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.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());
        info.put(TokenUtil.LICENSE, TokenUtil.LICENSE_NAME);
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
        //token状态设置
        if (jwtProperties.getState()) {
            OAuth2AccessToken oAuth2AccessToken = jwtAccessTokenConverter.enhance(accessToken, authentication);
            String accessTokenValue = oAuth2AccessToken.getValue();
            String tenantId = principal.getTenantId();
            String userId = Func.toStr(principal.getUserId());
            JwtUtil.addAccessToken(tenantId, userId, accessTokenValue, accessToken.getExpiresIn());
            if (jwtProperties.getSingle()) {
                OAuth2RefreshToken oAuth2RefreshToken = oAuth2AccessToken.getRefreshToken();
                String refreshTokenValue = oAuth2RefreshToken.getValue();
                JwtUtil.addRefreshToken(tenantId, userId, refreshTokenValue, accessToken.getExpiresIn() * 168);
            }
        }
        return accessToken;
    }
}
src/main/java/org/springblade/auth/support/BladeNoOpPasswordEncoder.java
New file
@@ -0,0 +1,34 @@
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() {
    }
}
src/main/java/org/springblade/auth/support/BladePasswordEncoder.java
New file
@@ -0,0 +1,23 @@
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));
    }
}
src/main/java/org/springblade/auth/support/BladePasswordEncoderFactories.java
New file
@@ -0,0 +1,51 @@
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:
     *
     * <ul>
     * <li>blade - {@link BladePasswordEncoder} (sha1(md5("password")))</li>
     * <li>bcrypt - {@link BCryptPasswordEncoder} (Also used for encoding)</li>
     * <li>noop - {@link BladeNoOpPasswordEncoder}</li>
     * <li>pbkdf2 - {@link Pbkdf2PasswordEncoder}</li>
     * <li>scrypt - {@link SCryptPasswordEncoder}</li>
     * </ul>
     *
     * @return the {@link PasswordEncoder} to use
     */
    public static PasswordEncoder createDelegatingPasswordEncoder() {
        String encodingId = "blade";
        Map<String, PasswordEncoder> 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() {
    }
}
src/main/java/org/springblade/auth/utils/TokenUtil.java
New file
@@ -0,0 +1,166 @@
package org.springblade.auth.utils;
import lombok.SneakyThrows;
import org.springblade.common.constant.TenantConstant;
import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.tenant.BladeTenantProperties;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.*;
import org.springblade.modules.system.entity.Tenant;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
/**
 * 认证工具类
 *
 * @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 LICENSE = TokenConstant.LICENSE;
    public final static String LICENSE_NAME = TokenConstant.LICENSE_NAME;
    public final static String DEPT_HEADER_KEY = "Dept-Id";
    public final static String ROLE_HEADER_KEY = "Role-Id";
    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 TOKEN_NOT_PERMISSION = "令牌授权已过期";
    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";
    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;
    }
    /**
     * 判断租户权限
     *
     * @param tenant 租户信息
     * @return boolean
     */
    public static boolean judgeTenant(Tenant tenant) {
        if (tenant == null || tenant.getId() == null) {
            throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_NO_TENANT);
        }
        if (StringUtil.equalsIgnoreCase(tenant.getTenantId(), BladeConstant.ADMIN_TENANT_ID)) {
            return false;
        }
        Date expireTime = tenant.getExpireTime();
        if (getTenantProperties().getLicense()) {
            String licenseKey = tenant.getLicenseKey();
            String decrypt = DesUtil.decryptFormHex(licenseKey, TenantConstant.DES_KEY);
            expireTime = JsonUtil.parse(decrypt, Tenant.class).getExpireTime();
        }
        if (expireTime != null && expireTime.before(DateUtil.now())) {
            throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_NO_TENANT_PERMISSION);
        }
        return false;
    }
}
src/main/java/org/springblade/common/config/BladeReportConfiguration.java
File was deleted
src/main/java/org/springblade/common/config/WxMiniConfig.java
File was deleted
src/main/java/org/springblade/common/config/WxPayConfig.java
File was deleted
src/main/java/org/springblade/common/utils/ParseMail.java
File was deleted
src/main/java/org/springblade/common/utils/SmsUtils.java
File was deleted
src/main/java/org/springblade/common/utils/WechatPay2ValidatorForRequest.java
File was deleted
src/main/java/org/springblade/common/utils/WeiXinSecurityUtil.java
File was deleted
src/main/java/org/springblade/flow/business/controller/WorkController.java
File was deleted
src/main/java/org/springblade/flow/business/service/FlowBusinessService.java
File was deleted
src/main/java/org/springblade/flow/business/service/IFlowService.java
File was deleted
src/main/java/org/springblade/flow/business/service/impl/FlowBusinessServiceImpl.java
File was deleted
src/main/java/org/springblade/flow/business/service/impl/FlowServiceImpl.java
File was deleted
src/main/java/org/springblade/flow/core/constant/ProcessConstant.java
File was deleted
src/main/java/org/springblade/flow/core/entity/BladeFlow.java
File was deleted
src/main/java/org/springblade/flow/core/entity/FlowEntity.java
File was deleted
src/main/java/org/springblade/flow/core/enums/FlowModeEnum.java
File was deleted
src/main/java/org/springblade/flow/core/utils/FlowUtil.java
File was deleted
src/main/java/org/springblade/flow/core/utils/TaskUtil.java
File was deleted
src/main/java/org/springblade/flow/demo/leave/controller/LeaveController.java
File was deleted
src/main/java/org/springblade/flow/demo/leave/entity/ProcessLeave.java
File was deleted
src/main/java/org/springblade/flow/demo/leave/mapper/LeaveMapper.java
File was deleted
src/main/java/org/springblade/flow/demo/leave/mapper/LeaveMapper.xml
File was deleted
src/main/java/org/springblade/flow/demo/leave/service/ILeaveService.java
File was deleted
src/main/java/org/springblade/flow/demo/leave/service/impl/LeaveServiceImpl.java
File was deleted
src/main/java/org/springblade/flow/demo/package-info.java
File was deleted
src/main/java/org/springblade/flow/engine/config/FlowableConfiguration.java
File was deleted
src/main/java/org/springblade/flow/engine/constant/FlowEngineConstant.java
File was deleted
src/main/java/org/springblade/flow/engine/controller/FlowFollowController.java
File was deleted
src/main/java/org/springblade/flow/engine/controller/FlowManagerController.java
File was deleted
src/main/java/org/springblade/flow/engine/controller/FlowModelController.java
File was deleted
src/main/java/org/springblade/flow/engine/controller/FlowProcessController.java
File was deleted
src/main/java/org/springblade/flow/engine/entity/FlowExecution.java
File was deleted
src/main/java/org/springblade/flow/engine/entity/FlowModel.java
File was deleted
src/main/java/org/springblade/flow/engine/entity/FlowProcess.java
File was deleted
src/main/java/org/springblade/flow/engine/mapper/FlowMapper.java
File was deleted
src/main/java/org/springblade/flow/engine/mapper/FlowMapper.xml
File was deleted
src/main/java/org/springblade/flow/engine/service/FlowEngineService.java
File was deleted
src/main/java/org/springblade/flow/engine/service/impl/FlowEngineServiceImpl.java
File was deleted
src/main/java/org/springblade/flow/engine/utils/FlowCache.java
File was deleted
src/main/java/org/springblade/modules/system/controller/UserController.java
@@ -420,25 +420,6 @@
        return R.data(userService.getUserInfo(AuthUtil.getUserId()));
    }
    /**
     * 修改
     */
    @GetMapping("/getUserInfoByCode")
    @ApiOperation(value = "查询物业人员/网格人员", notes = "houseCode")
    public R getUserInfoByCode(@RequestParam("houseCode") String houseCode, @RequestParam(value = "type", defaultValue = "2") String type) {
        return R.data(userService.getUserInfoByCode(houseCode, type));
    }
    /**
     * 通过小区id查询物业人员/网格人员
     */
    @GetMapping("/getUserInfoByDistrictId")
    @ApiOperation(value = "查询物业人员/网格人员", notes = "houseCode")
    public R getUserInfoByDistrictId(@RequestParam("districtId") String districtId, @RequestParam(value = "building", required = false) String building) {
        return R.data(userService.getUserInfoByDistrictId(districtId, building));
    }
    /**
     * 通过机构查询物业公司人员
src/main/java/org/springblade/modules/system/mapper/UserMapper.java
@@ -1,26 +1,9 @@
/*
 *      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.modules.system.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;
import org.flowable.idm.engine.impl.persistence.entity.UserEntity;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.excel.UserExcel;
import org.springblade.modules.system.vo.UserDetailVO;
@@ -102,8 +85,6 @@
     */
    UserVO searchUserById(Long id);
    List<UserEntity> getUserInfoByDistrictId(String districtId, String building);
    /**
     * 查询没有匹配的数据
     *
@@ -114,15 +95,6 @@
    List<User> getUserListByDeptIds(@Param("deptIds") String receiveDept);
    List<User> getUserInfoByPropertyId(String deptId, String roleId);
    /**
     * 通过机构查询用户
     *
     * @param deptIdList
     * @return
     */
    List<UserEntity> selectUserByDept(List<Long> deptIdList);
    /**
     * 通过经纬度查询最近的民警人员
src/main/java/org/springblade/modules/system/mapper/UserMapper.xml
@@ -191,38 +191,6 @@
        id = #{id}
    </select>
    <select id="getUserInfoByDistrictId"
            resultType="org.flowable.idm.engine.impl.persistence.entity.UserEntity">
        SELECT
        bu.id,
        bu.tenant_id,
        bu.code,
        bu.user_type,
        bu.account,
        bu.name,
        bu.real_name,
        bu.avatar,
        bu.email,
        bu.phone,
        bu.birthday
        FROM
        blade_user bu
        LEFT JOIN jczz_household jh ON bu.id = jh.associated_user_id
        LEFT JOIN jczz_house jhe ON jhe.house_code = jh.house_code
        LEFT JOIN jczz_district jd on jd.aoi_code=jhe.district_code
        <where>
            <if test="districtId != null and districtId != ''">
                and jd.id = #{districtId}
                and bu.is_deleted = 0
            </if>
            <if test="building != null and building != ''">
                and jhe.building=#{building}
            </if>
        </where>
    </select>
    <!--查询没有匹配的数据-->
    <select id="getNotBindUserDept" resultType="org.springblade.modules.system.entity.User">
        select bu.* from blade_user bu
src/main/java/org/springblade/modules/system/service/ITenantService.java
@@ -18,6 +18,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import org.springblade.core.tool.api.R;
import org.springblade.modules.system.entity.Tenant;
import java.util.Date;
@@ -72,5 +73,4 @@
     * @return
     */
    boolean setting(Integer accountNumber, Date expireTime, String ids);
}
src/main/java/org/springblade/modules/system/service/IUserService.java
@@ -19,7 +19,6 @@
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.flowable.idm.engine.impl.persistence.entity.UserEntity;
import org.springblade.core.mp.base.BaseService;
import org.springblade.core.mp.support.Query;
import org.springblade.modules.auth.enums.UserEnum;
@@ -244,10 +243,6 @@
     * @return
     */
    UserVO getuserById(Long id);
    List<UserEntity> getUserInfoByCode(String houseCode, String type);
    List<UserEntity> getUserInfoByDistrictId(String districtId, String building);
    /**
     * 处理漏绑定的user_dept
src/main/java/org/springblade/modules/system/service/impl/MenuServiceImpl.java
@@ -1,19 +1,3 @@
/*
 *      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.modules.system.service.impl;
import com.alibaba.fastjson.JSON;
@@ -21,10 +5,8 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import net.logstash.logback.encoder.org.apache.commons.lang3.StringUtils;
import org.springblade.common.cache.SysCache;
import org.springblade.common.constant.CommonConstant;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java
@@ -1,19 +1,3 @@
/*
 *      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.modules.system.service.impl;
@@ -24,10 +8,8 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.apache.logging.log4j.util.Strings;
import org.flowable.idm.engine.impl.persistence.entity.UserEntity;
import org.springblade.common.cache.DictCache;
import org.springblade.common.cache.ParamCache;
import org.springblade.common.cache.SysCache;
@@ -521,25 +503,6 @@
    public UserVO getuserById(Long id) {
        return baseMapper.searchUserById(id);
    }
    @Override
    public List<UserEntity> getUserInfoByCode(String houseCode, String type) {
        return null;
    }
    /**
     * 通过小区id查询物业人员
     *
     * @param districtId
     * @param building
     * @return
     */
    @Override
    public List<UserEntity> getUserInfoByDistrictId(String districtId, String building) {
        return baseMapper.getUserInfoByDistrictId(districtId, building);
    }
    /**
     * 处理漏绑定的user_dept
src/main/resources/application.yml
@@ -137,14 +137,14 @@
    url: https://gitee.com/smallc
#flowable配置
flowable:
  activity-font-name: \u5B8B\u4F53
  label-font-name: \u5B8B\u4F53
  annotation-font-name: \u5B8B\u4F53
  check-process-definitions: false
  database-schema-update: false
  async-executor-activate: false
  async-history-executor-activate: false
#flowable:
#  activity-font-name: \u5B8B\u4F53
#  label-font-name: \u5B8B\u4F53
#  annotation-font-name: \u5B8B\u4F53
#  check-process-definitions: false
#  database-schema-update: false
#  async-executor-activate: false
#  async-history-executor-activate: false
#报表配置
report:
@@ -229,43 +229,7 @@
    #接口放行
    skip-url:
      - /blade-test/**
      - /sse/**
      - /blade-doorplateAddress/doorplateAddress/getFuncList
      - /blade-rotation/rotation/page
      - /blade-article/article/page
      - /blade-article/article/detail
      - /blade-articleComment/articleComment/page
      - /public_discuss/publicDiscuss/detail
      - /blade-userPublicEnroll/userPublicEnroll/page
      - /blade-topics/topics/lists
      - /blade-household/household/getHouseholdOtherInfo
      - /blade-resource/oss/endpoint/put-file
      - /blade-resource/oss/endpoint/put-file-attach-by-prefix-path
      - /blade-hiddenDangerRecord/**
      - /blade-system/user/getPoliceUser
      - /blade-policeAlarmRecords/policeAlarmRecords/save
      - /blade-smsSend/smsSend/send
#      - /blade-householdLabel/**
#      - /blade-placeRel/**
#      - /blade-doorplateAddress/doorplateAddress/**
#      - /blade-house/house/**
#      - /blade-household/household/**
#      - /blade-label/label/**
#      - /blade-houseRental/houseRental/**
#      - /blade-resource/oss/**
#      - /blade-place/**
#      - /blade-taskReportForRepairs/**
#      - /blade-placeExt/**
#      - /blade-grid/**
#      - /blade-community/**
#      - /blade-gridman/**
#      - /blade-propertyCompany/**
#      - /blade-eCallEvent/**
#      - /blade-system/**
#      - /blade-propertyCompanyComment/**
#      - /blade-policeStation/**
#      - /blade-policeAffairsGrid/**
#      - /blade-category/**
    #授权认证配置
    auth:
      - method: ALL
src/main/resources/processes/LeaveProcess.bpmn20.xml
File was deleted