9 files modified
18 files added
40 files deleted
| | |
| | | <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> |
| | |
| | | <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> |
| | |
| | | <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> |
| | | |
| New file |
| | |
| | | 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()"); |
| | | } |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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"); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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 = ?"; |
| | | |
| | | } |
| New file |
| | |
| | | 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()); |
| | | } |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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"); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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() { |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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)); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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() { |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | |
| | | } |
| | |
| | | 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)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 通过机构查询物业公司人员 |
| | |
| | | /* |
| | | * 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; |
| | |
| | | */ |
| | | UserVO searchUserById(Long id); |
| | | |
| | | List<UserEntity> getUserInfoByDistrictId(String districtId, String building); |
| | | |
| | | /** |
| | | * 查询没有匹配的数据 |
| | | * |
| | |
| | | List<User> getUserListByDeptIds(@Param("deptIds") String receiveDept); |
| | | |
| | | List<User> getUserInfoByPropertyId(String deptId, String roleId); |
| | | |
| | | |
| | | /** |
| | | * 通过机构查询用户 |
| | | * |
| | | * @param deptIdList |
| | | * @return |
| | | */ |
| | | List<UserEntity> selectUserByDept(List<Long> deptIdList); |
| | | |
| | | /** |
| | | * 通过经纬度查询最近的民警人员 |
| | |
| | | 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 |
| | |
| | | |
| | | 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; |
| | |
| | | * @return |
| | | */ |
| | | boolean setting(Integer accountNumber, Date expireTime, String ids); |
| | | |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | * @return |
| | | */ |
| | | UserVO getuserById(Long id); |
| | | |
| | | List<UserEntity> getUserInfoByCode(String houseCode, String type); |
| | | |
| | | List<UserEntity> getUserInfoByDistrictId(String districtId, String building); |
| | | |
| | | /** |
| | | * 处理漏绑定的user_dept |
| | |
| | | /* |
| | | * 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; |
| | |
| | | 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; |
| | |
| | | /* |
| | | * 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.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; |
| | |
| | | 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 |
| | |
| | | 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: |
| | |
| | | #接口放行 |
| | | 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 |