鉴权以及用户管理模块

This commit is contained in:
王洪庆 2023-04-06 09:36:50 +08:00
parent b5e19e36cb
commit de6444c233
71 changed files with 5717 additions and 1 deletions

View File

@ -52,5 +52,8 @@ public interface CommonConstant {
*/
String KN_VORDM_MODULE_NAME = "biz-vordm";
/**
* 系统管理模块 application name
*/
String KN_SYSTEM_MANAGER_MODULE_NAME = "system-manager";
}

15
kn-sys-manager/Dockerfile Normal file
View File

@ -0,0 +1,15 @@
FROM bladex/alpine-java:openjdk8-openj9_cn_slim
LABEL maintainer=whq<460794335@qq.com>
RUN mkdir -p /kn/auth
WORKDIR /kn/auth
EXPOSE 8100
ADD ./target/kn-sys-manager.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"]

159
kn-sys-manager/pom.xml Normal file
View File

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.kening.platform</groupId>
<artifactId>kn-vordm</artifactId>
<version>${revision}</version>
</parent>
<artifactId>kn-sys-manager</artifactId>
<name>${project.artifactId}</name>
<version>${revision}</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>com.kening.platform</groupId>
<artifactId>kn-common</artifactId>
</dependency>
<dependency>
<groupId>com.kening.platform</groupId>
<artifactId>kn-launcher</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-db</artifactId>
<exclusions>
<exclusion>
<artifactId>postgresql</artifactId>
<groupId>org.postgresql</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-tenant</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-cloud</artifactId>
<exclusions>
<exclusion>
<artifactId>HdrHistogram</artifactId>
<groupId>org.hdrhistogram</groupId>
</exclusion>
<exclusion>
<artifactId>javassist</artifactId>
<groupId>org.javassist</groupId>
</exclusion>
<exclusion>
<artifactId>simpleclient</artifactId>
<groupId>io.prometheus</groupId>
</exclusion>
<exclusion>
<artifactId>fastjson</artifactId>
<groupId>com.alibaba</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hdrhistogram</groupId>
<artifactId>HdrHistogram</artifactId>
<version>2.1.12</version>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-metrics</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-redis</artifactId>
<exclusions>
<exclusion>
<artifactId>javassist</artifactId>
<groupId>org.javassist</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-swagger</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
</dependency>
<!-- 验证码 -->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-boot</artifactId>
</dependency>
<!-- 链路追踪、服务监控 -->
<!--<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-trace</artifactId>
</dependency>-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<configuration>
<skip>${dockerfile.skip}</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,24 @@
package org.springblade.auth;
import org.springblade.common.constant.CommonConstant;
import org.springblade.core.cloud.feign.EnableBladeFeign;
import org.springblade.core.launch.BladeApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.context.annotation.ComponentScan;
/**
* 用户认证服务器
*
* @author Chill
*/
@EnableBladeFeign
@SpringCloudApplication
@ComponentScan({"org.springblade.auth"})
public class SystemManagerApplication {
public static void main(String[] args) {
BladeApplication.run(CommonConstant.KN_SYSTEM_MANAGER_MODULE_NAME, SystemManagerApplication.class, args);
}
}

View File

@ -0,0 +1,91 @@
package org.springblade.auth.config;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springblade.auth.granter.BladeTokenGranter;
import org.springblade.auth.service.BladeClientDetailsServiceImpl;
import org.springblade.core.redis.cache.BladeRedis;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
/**
* 认证服务器配置
*
* @author Chill
*/
@Order
@Configuration
@AllArgsConstructor
@EnableAuthorizationServer
public class BladeAuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private final DataSource dataSource;
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailsService;
private final TokenStore tokenStore;
private final TokenEnhancer jwtTokenEnhancer;
private final JwtAccessTokenConverter jwtAccessTokenConverter;
private final BladeRedis bladeRedis;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
//获取自定义tokenGranter
TokenGranter tokenGranter = BladeTokenGranter.getTokenGranter(authenticationManager, endpoints, bladeRedis);
//配置端点
endpoints.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.tokenGranter(tokenGranter);
//扩展token返回结果
if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
List<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) {
clients.withClientDetails(new BladeClientDetailsServiceImpl(dataSource));
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
.allowFormAuthenticationForClients()
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.config;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
/**
* 自定义登录成功配置
*
* @author Chill
*/
@Configuration
@AllArgsConstructor
@EnableResourceServer
public class BladeResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
@SneakyThrows
public void configure(HttpSecurity http) {
http.headers().frameOptions().disable();
http.formLogin()
.and()
.authorizeRequests()
.antMatchers(
"/actuator/**",
"/oauth/captcha",
"/oauth/logout",
"/oauth/mobile",
"/oauth/clear-cache",
"/oauth/render/**",
"/oauth/callback/**",
"/oauth/revoke/**",
"/oauth/refresh/**",
"/token/**",
"/user/**",
"/role/**",
"/menu/**",
"/dict-biz",
"/v2/api-docs").permitAll()
.anyRequest().authenticated().and()
.csrf().disable();
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.config;
import org.springblade.auth.support.BladeJwtTokenEnhancer;
import org.springblade.core.jwt.props.JwtProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
/**
* JwtTokenStore
*
* @author Chill
*/
@Configuration
@ConditionalOnProperty(prefix = "blade.security.oauth2", name = "storeType", havingValue = "jwt", matchIfMissing = true)
public class JwtTokenStoreConfiguration {
/**
* 使用jwtTokenStore存储token
*/
@Bean
public TokenStore jwtTokenStore(JwtProperties jwtProperties) {
return new JwtTokenStore(jwtAccessTokenConverter(jwtProperties));
}
/**
* 用于生成jwt
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(JwtProperties jwtProperties) {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey(jwtProperties.getSignKey());
return accessTokenConverter;
}
/**
* 用于扩展jwt
*/
@Bean
@ConditionalOnMissingBean(name = "jwtTokenEnhancer")
public TokenEnhancer jwtTokenEnhancer(JwtAccessTokenConverter jwtAccessTokenConverter, JwtProperties jwtProperties) {
return new BladeJwtTokenEnhancer(jwtAccessTokenConverter, jwtProperties);
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.config;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springblade.auth.support.BladePasswordEncoderFactories;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* Security配置
*
* @author Chill
*/
@Configuration
@AllArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
@Override
@SneakyThrows
public AuthenticationManager authenticationManagerBean() {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return BladePasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Override
@SneakyThrows
protected void configure(HttpSecurity http) {
http.httpBasic().and().csrf().disable().authorizeRequests().anyRequest().fullyAuthenticated();
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.constant;
/**
* 授权校验常量
*
* @author Chill
*/
public interface AuthConstant {
/**
* 密码加密规则
*/
String ENCRYPT = "{blade}";
/**
* blade_client表字段
*/
String CLIENT_FIELDS = "client_id, CONCAT('{noop}',client_secret) as client_secret, resource_ids, scope, authorized_grant_types, " +
"web_server_redirect_uri, authorities, access_token_validity, " +
"refresh_token_validity, additional_information, autoapprove";
/**
* blade_client查询语句
*/
String BASE_STATEMENT = "select " + CLIENT_FIELDS + " from blade_client";
/**
* blade_client查询排序
*/
String DEFAULT_FIND_STATEMENT = BASE_STATEMENT + " order by client_id";
/**
* 查询client_id
*/
String DEFAULT_SELECT_STATEMENT = BASE_STATEMENT + " where client_id = ?";
}

View File

@ -0,0 +1,93 @@
package org.springblade.auth.endpoint;
import com.wf.captcha.SpecCaptcha;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.cache.CacheNames;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.jwt.JwtUtil;
import org.springblade.core.jwt.props.JwtProperties;
import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
import static org.springblade.core.cache.constant.CacheConstant.*;
/**
* BladeEndPoint
*
* @author Chill
*/
@NonDS
@Slf4j
@RestController
@RequiredArgsConstructor
public class BladeTokenEndPoint {
private final BladeRedis bladeRedis;
private final JwtProperties jwtProperties;
@Value("${captcha.image.width:130}")
private Integer imageWidth;
@Value("${captcha.image.height:48}")
private Integer imageHeight;
@Value("${captcha.image.code.length:5}")
private Integer codeLength;
@Value("${captcha.image.code.time:30}")
private Integer codeValidateTime;
@GetMapping("/oauth/user-info")
public R<Authentication> currentUser(Authentication authentication) {
return R.data(authentication);
}
@GetMapping("/oauth/captcha")
public Kv captcha() {
SpecCaptcha specCaptcha = new SpecCaptcha(imageWidth, imageHeight, codeLength);
String verCode = specCaptcha.text().toLowerCase();
String key = StringUtil.randomUUID();
// 存入redis并设置过期时间为30分钟
bladeRedis.setEx(CacheNames.CAPTCHA_KEY + key, verCode, Duration.ofMinutes(codeValidateTime));
// 将key和base64返回给前端
return Kv.create().set("key", key).set("image", specCaptcha.toBase64());
}
@GetMapping("/oauth/logout")
public Kv logout() {
BladeUser user = AuthUtil.getUser();
if (user != null && jwtProperties.getState()) {
String token = JwtUtil.getToken(WebUtil.getRequest().getHeader(TokenConstant.HEADER));
JwtUtil.removeAccessToken(user.getTenantId(), String.valueOf(user.getUserId()), token);
}
return Kv.create().set("success", "true").set("msg", "success");
}
@GetMapping("/oauth/clear-cache")
public Kv clearCache() {
CacheUtil.clear(BIZ_CACHE);
CacheUtil.clear(USER_CACHE);
CacheUtil.clear(DICT_CACHE);
CacheUtil.clear(FLOW_CACHE);
CacheUtil.clear(SYS_CACHE);
CacheUtil.clear(PARAM_CACHE);
CacheUtil.clear(RESOURCE_CACHE);
CacheUtil.clear(MENU_CACHE);
CacheUtil.clear(DICT_CACHE, Boolean.FALSE);
CacheUtil.clear(MENU_CACHE, Boolean.FALSE);
CacheUtil.clear(SYS_CACHE, Boolean.FALSE);
CacheUtil.clear(PARAM_CACHE, Boolean.FALSE);
return Kv.create().set("success", "true").set("msg", "success");
}
}

View File

@ -0,0 +1,33 @@
package org.springblade.auth.granter;
import org.springblade.core.redis.cache.BladeRedis;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 自定义拓展TokenGranter
*
* @author Chill
*/
public class BladeTokenGranter {
/**
* 自定义tokenGranter
*/
public static TokenGranter getTokenGranter(final AuthenticationManager authenticationManager,
final AuthorizationServerEndpointsConfigurer endpoints,
BladeRedis bladeRedis) {
// 默认tokenGranter集合
List<TokenGranter> granters = new ArrayList<>(Collections.singletonList(endpoints.getTokenGranter()));
// 增加验证码模式
granters.add(new CaptchaTokenGranter(authenticationManager, endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), bladeRedis));
return new CompositeTokenGranter(granters);
}
}

View 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<>(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);
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.service;
import org.springblade.auth.constant.AuthConstant;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
/**
* 客户端信息
*
* @author Chill
*/
@Component
public class BladeClientDetailsServiceImpl extends JdbcClientDetailsService {
public BladeClientDetailsServiceImpl(DataSource dataSource) {
super(dataSource);
setSelectClientDetailsSql(AuthConstant.DEFAULT_SELECT_STATEMENT);
setFindClientDetailsSql(AuthConstant.DEFAULT_FIND_STATEMENT);
}
/**
* 缓存客户端信息
*
* @param clientId 客户端id
*/
@Override
public ClientDetails loadClientByClientId(String clientId) {
try {
return super.loadClientByClientId(clientId);
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}

View File

@ -0,0 +1,93 @@
package org.springblade.auth.service;
import lombok.Getter;
import org.springblade.core.tool.support.Kv;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
/**
* 用户信息拓展
*
* @author whq
*/
@Getter
public class BladeUserDetails extends User {
/**
* 用户id
*/
private final Long userId;
private final String email;
/**
* 租户ID
*/
private final String tenantId;
/**
* 第三方认证ID
*/
private final String oauthId;
/**
* 昵称
*/
private final String name;
/**
* 真名
*/
private final String realName;
/**
* 账号
*/
private final String account;
/**
* 部门id
*/
private final String deptId;
/**
* 岗位id
*/
private final String postId;
/**
* 角色id
*/
private final String roleId;
/**
* 角色名
*/
private final String roleName;
/**
* 头像
*/
private final String avatar;
/**
* 用户详情
*/
private final Kv detail;
public BladeUserDetails(Long userId, String email,
String tenantId, String oauthId, String name,
String realName, String deptId, String postId, String roleId,
String roleName, String avatar, String username, String password, Kv detail,
boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired,
boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
this.userId = userId;
this.email = email;
this.tenantId = tenantId;
this.oauthId = oauthId;
this.name = name;
this.realName = realName;
this.account = username;
this.deptId = deptId;
this.postId = postId;
this.roleId = roleId;
this.roleName = roleName;
this.avatar = avatar;
this.detail = detail;
}
}

View File

@ -0,0 +1,124 @@
package org.springblade.auth.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.springblade.auth.constant.AuthConstant;
import org.springblade.auth.system.cache.SysCache;
import org.springblade.auth.system.cache.UserCache;
import org.springblade.auth.system.entity.User;
import org.springblade.auth.system.entity.UserInfo;
import org.springblade.auth.utils.TokenUtil;
import org.springblade.common.cache.CacheNames;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.utils.DigestUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.List;
/**
* 用户信息
*
* @author whq
*/
@Service
@AllArgsConstructor
public class BladeUserDetailsServiceImpl implements UserDetailsService {
public static final Integer FAIL_COUNT = 5;
private final BladeRedis bladeRedis;
@Override
@SneakyThrows
public BladeUserDetails loadUserByUsername(String username) {
HttpServletRequest request = WebUtil.getRequest();
// 获取用户绑定ID
String headerDept = request.getHeader(TokenUtil.DEPT_HEADER_KEY);
String headerRole = request.getHeader(TokenUtil.ROLE_HEADER_KEY);
// 获取租户ID
String headerTenant = request.getHeader(TokenUtil.TENANT_HEADER_KEY);
String paramTenant = request.getParameter(TokenUtil.TENANT_PARAM_KEY);
String password = request.getParameter(TokenUtil.PASSWORD_KEY);
String grantType = request.getParameter(TokenUtil.GRANT_TYPE_KEY);
if (StringUtil.isAllBlank(headerTenant, paramTenant)) {
throw new UserDeniedAuthorizationException(TokenUtil.TENANT_NOT_FOUND);
}
String tenantId = StringUtils.isBlank(headerTenant) ? paramTenant : headerTenant;
// 判断登录是否锁定
// 新版本将增加1.参数管理读取配置 2.用户管理增加解封按钮
int count = getFailCount(tenantId, username);
if (count >= FAIL_COUNT) {
throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_TOO_MANY_FAILS);
}
// 获取用户类型
String userType = Func.toStr(request.getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE);
// 远程调用返回数据
UserInfo userInfo = UserCache.getUser(tenantId, username);
User user = userInfo.getUser();
// 判断返回信息
// 用户不存在,但提示用户名与密码错误并锁定账号
if (user == null || user.getId() == null) {
setFailCount(tenantId, username, count);
throw new UsernameNotFoundException(TokenUtil.USER_NOT_FOUND);
}
// 用户存在但密码错误,超过次数则锁定账号
if (!grantType.equals(TokenUtil.REFRESH_TOKEN_KEY) && !user.getPassword().equals(DigestUtil.hex(password))) {
setFailCount(tenantId, username, count);
throw new UsernameNotFoundException(TokenUtil.USER_NOT_FOUND);
}
// 用户角色不存在
if (Func.isEmpty(userInfo.getRoles())) {
throw new UserDeniedAuthorizationException(TokenUtil.USER_HAS_NO_ROLE);
}
// 多角色情况下指定单角色
if (Func.isNotEmpty(headerRole) && user.getRoleId().contains(headerRole)) {
List<String> roleResult = SysCache.getRoleAliases(headerRole);
userInfo.setRoles(roleResult);
user.setRoleId(headerRole);
}
return new BladeUserDetails(user.getId(), user.getEmail(),
user.getTenantId(), StringPool.EMPTY, user.getName(), user.getRealName(), user.getDeptId(), user.getPostId(), user.getRoleId(), Func.join(userInfo.getRoles()), Func.toStr(user.getAvatar(), TokenUtil.DEFAULT_AVATAR),
username, AuthConstant.ENCRYPT + user.getPassword(), userInfo.getDetail(), true, true, true, true,
AuthorityUtils.commaSeparatedStringToAuthorityList(Func.join(userInfo.getRoles())));
}
/**
* 获取账号错误次数
*
* @param tenantId 租户id
* @param username 账号
* @return int
*/
private int getFailCount(String tenantId, String username) {
return Func.toInt(bladeRedis.get(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username)), 0);
}
/**
* 设置账号错误次数
*
* @param tenantId 租户id
* @param username 账号
* @param count 次数
*/
private void setFailCount(String tenantId, String username, int count) {
bladeRedis.setEx(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, username), count + 1, Duration.ofMinutes(30));
}
}

View File

@ -0,0 +1,60 @@
package org.springblade.auth.support;
import lombok.RequiredArgsConstructor;
import org.springblade.auth.service.BladeUserDetails;
import org.springblade.auth.utils.TokenUtil;
import org.springblade.core.jwt.JwtUtil;
import org.springblade.core.jwt.props.JwtProperties;
import org.springblade.core.tool.utils.Func;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import java.util.HashMap;
import java.util.Map;
/**
* jwt返回参数增强
*
* @author Chill
*/
@RequiredArgsConstructor
public class BladeJwtTokenEnhancer implements TokenEnhancer {
private final JwtAccessTokenConverter jwtAccessTokenConverter;
private final JwtProperties jwtProperties;
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
BladeUserDetails principal = (BladeUserDetails) authentication.getUserAuthentication().getPrincipal();
//token参数增强
Map<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.EMAIL, principal.getEmail());
//info.put(TokenUtil.OAUTH_ID, principal.getOauthId());
info.put(TokenUtil.ACCOUNT, principal.getAccount());
info.put(TokenUtil.USER_NAME, principal.getUsername());
info.put(TokenUtil.NICK_NAME, principal.getName());
info.put(TokenUtil.REAL_NAME, principal.getRealName());
info.put(TokenUtil.ROLE_NAME, principal.getRoleName());
info.put(TokenUtil.AVATAR, principal.getAvatar());
info.put(TokenUtil.DETAIL, principal.getDetail());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
//token状态设置, 有状态默认无状态
if (jwtProperties.getState()) {
OAuth2AccessToken oAuth2AccessToken = jwtAccessTokenConverter.enhance(accessToken, authentication);
String tokenValue = oAuth2AccessToken.getValue();
String tenantId = principal.getTenantId();
String userId = Func.toStr(principal.getUserId());
JwtUtil.addAccessToken(tenantId, userId, tokenValue, accessToken.getExpiresIn());
}
return accessToken;
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.support;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* 无密码加密
*
* @author Chill
*/
public class BladeNoOpPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return rawPassword.toString().equals(encodedPassword);
}
/**
* Get the singleton {@link BladeNoOpPasswordEncoder}.
*/
public static PasswordEncoder getInstance() {
return INSTANCE;
}
private static final PasswordEncoder INSTANCE = new BladeNoOpPasswordEncoder();
private BladeNoOpPasswordEncoder() {
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.support;
import org.springblade.core.tool.utils.DigestUtil;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* 自定义密码加密
*
* @author Chill
*/
public class BladePasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return DigestUtil.hex((String) rawPassword);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encodedPassword.equals(encode(rawPassword));
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.auth.support;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
import java.util.HashMap;
import java.util.Map;
/**
* 自定义密码工厂
*
* @author Rob Winch, Chill
* @since 5.0
*/
public class BladePasswordEncoderFactories {
/**
* Creates a {@link DelegatingPasswordEncoder} with default mappings. Additional
* mappings may be added and the encoding will be updated to conform with best
* practices. However, due to the nature of {@link DelegatingPasswordEncoder} the
* updates should not impact users. The mappings current are:
*
* <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() {
}
}

View File

@ -0,0 +1,89 @@
package org.springblade.auth.system.cache;
import org.springblade.auth.system.service.IDictBizService;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.auth.system.entity.DictBiz;
import java.util.List;
import static org.springblade.core.cache.constant.CacheConstant.DICT_CACHE;
/**
* 业务字典缓存工具类
*
* @author Chill
*/
public class DictBizCache {
private static final String DICT_ID = "dictBiz:id";
private static final String DICT_VALUE = "dictBiz:value";
private static final String DICT_LIST = "dictBiz:list";
private static IDictBizService dictClient;
private static IDictBizService getDictClient() {
if (dictClient == null) {
dictClient = SpringUtil.getBean(IDictBizService.class);
}
return dictClient;
}
/**
* 获取字典实体
*
* @param id 主键
* @return DictBiz
*/
public static DictBiz getById(Long id) {
String keyPrefix = DICT_ID.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON);
return CacheUtil.get(DICT_CACHE, keyPrefix, id, () -> {
return getDictClient().getById(id);
});
}
/**
* 获取字典值
*
* @param code 字典编号
* @param dictKey Integer型字典键
* @return String
*/
public static String getValue(String code, Integer dictKey) {
String keyPrefix = DICT_VALUE.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON);
return CacheUtil.get(DICT_CACHE, keyPrefix + code + StringPool.COLON, String.valueOf(dictKey), () -> {
return getDictClient().getValue(code, String.valueOf(dictKey));
});
}
/**
* 获取字典值
*
* @param code 字典编号
* @param dictKey String型字典键
* @return String
*/
public static String getValue(String code, String dictKey) {
String keyPrefix = DICT_VALUE.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON);
return CacheUtil.get(DICT_CACHE, keyPrefix + code + StringPool.COLON, dictKey, () -> {
return getDictClient().getValue(code, dictKey);
});
}
/**
* 获取字典集合
*
* @param code 字典编号
* @return List<DictBiz>
*/
public static List<DictBiz> getList(String code) {
String keyPrefix = DICT_LIST.concat(StringPool.DASH).concat(AuthUtil.getTenantId()).concat(StringPool.COLON);
return CacheUtil.get(DICT_CACHE, keyPrefix, code, () -> {
return getDictClient().getList(code);
});
}
}

View File

@ -0,0 +1,116 @@
package org.springblade.auth.system.cache;
import org.springblade.auth.system.entity.Menu;
import org.springblade.auth.system.entity.Role;
import org.springblade.auth.system.service.IMenuService;
import org.springblade.auth.system.service.IRoleService;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.StringPool;
import java.util.List;
import static org.springblade.core.cache.constant.CacheConstant.SYS_CACHE;
/**
* 系统缓存
*
* @author Chill
*/
public class SysCache {
private static final String MENU_ID = "menu:id:";
private static final String ROLE_ID = "role:id:";
private static final String ROLE_NAME = "role:name:";
private static final String ROLE_NAME_ID = "roleName:id:";
private static final String ROLE_NAMES_ID = "roleNames:id:";
private static final String ROLE_ALIAS_ID = "roleAlias:id:";
private static final String ROLE_ALIASES_ID = "roleAliases:id:";
private static IMenuService menuService;
private static IRoleService roleService;
private static IMenuService getSysClient() {
if (menuService == null) {
menuService = SpringUtil.getBean(IMenuService.class);
}
return menuService;
}
private static IRoleService getRoleClient() {
if (roleService == null) {
roleService = SpringUtil.getBean(IRoleService.class);
}
return roleService;
}
/**
* 获取菜单
*
* @param id 主键
* @return 菜单
*/
public static Menu getMenu(Long id) {
return CacheUtil.get(SYS_CACHE, MENU_ID, id, () -> getSysClient().getById(id));
}
/**
* 获取角色
*
* @param id 主键
* @return Role
*/
public static Role getRole(Long id) {
return CacheUtil.get(SYS_CACHE, ROLE_ID, id, () -> getRoleClient().getById(id));
}
/**
* 获取角色id
*
* @param tenantId 租户id
* @param roleNames 角色名
* @return
*/
public static String getRoleIds(String tenantId, String roleNames) {
return CacheUtil.get(SYS_CACHE, ROLE_NAME, tenantId + StringPool.DASH + roleNames, () -> getRoleClient().getRoleIds(tenantId, roleNames));
}
/**
* 获取角色名
*
* @param id 主键
* @return 角色名
*/
public static String getRoleName(Long id) {
return CacheUtil.get(SYS_CACHE, ROLE_NAME_ID, id, () -> getRoleClient().getById(id).getRoleName());
}
/**
* 获取角色别名
*
* @param id 主键
* @return 角色别名
*/
public static String getRoleAlias(Long id) {
return CacheUtil.get(SYS_CACHE, ROLE_ALIAS_ID, id, () -> getRoleClient().getById(id).getRoleAlias());
}
/**
* 获取角色名集合
*
* @param roleIds 主键集合
* @return 角色名
*/
public static List<String> getRoleNames(String roleIds) {
return CacheUtil.get(SYS_CACHE, ROLE_NAMES_ID, roleIds, () -> getRoleClient().getRoleNames(roleIds));
}
/**
* 获取角色别名集合
*
* @param roleIds 主键集合
* @return 角色别名
*/
public static List<String> getRoleAliases(String roleIds) {
return CacheUtil.get(SYS_CACHE, ROLE_ALIASES_ID, roleIds, () -> getRoleClient().getRoleAliases(roleIds));
}
}

View File

@ -0,0 +1,65 @@
package org.springblade.auth.system.cache;
import org.springblade.auth.system.entity.User;
import org.springblade.auth.system.entity.UserInfo;
import org.springblade.auth.system.service.IUserService;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import static org.springblade.core.cache.constant.CacheConstant.USER_CACHE;
import static org.springblade.core.launch.constant.FlowConstant.TASK_USR_PREFIX;
/**
* 系统缓存
*
* @author Chill
*/
public class UserCache {
private static final String USER_CACHE_ID = "user:id:";
private static final String USER_CACHE_ACCOUNT = "user:account:";
private static IUserService userClient;
private static IUserService getUserClient() {
if (userClient == null) {
userClient = SpringUtil.getBean(IUserService.class);
}
return userClient;
}
/**
* 根据任务用户id获取用户信息
*
* @param taskUserId 任务用户id
* @return
*/
public static User getUserByTaskUser(String taskUserId) {
Long userId = Func.toLong(StringUtil.removePrefix(taskUserId, TASK_USR_PREFIX));
return getUser(userId);
}
/**
* 获取用户
*
* @param userId 用户id
* @return
*/
public static User getUser(Long userId) {
return CacheUtil.get(USER_CACHE, USER_CACHE_ID, userId, () -> getUserClient().getById(userId));
}
/**
* 获取用户
*
* @param tenantId 租户id
* @param account 账号名
* @return
*/
public static UserInfo getUser(String tenantId, String account) {
return CacheUtil.get(USER_CACHE, USER_CACHE_ACCOUNT, tenantId + StringPool.DASH + account, () -> getUserClient().userInfo(tenantId, account));
}
}

View File

@ -0,0 +1,171 @@
package org.springblade.auth.system.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import org.springblade.auth.system.entity.DictBiz;
import org.springblade.auth.system.service.IDictBizService;
import org.springblade.auth.system.vo.DictBizVO;
import org.springblade.auth.system.wrapper.DictBizWrapper;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import static org.springblade.core.cache.constant.CacheConstant.DICT_CACHE;
/**
* 控制器
*
* @author Chill
*/
@NonDS
@RestController
@AllArgsConstructor
@RequestMapping("/dict-biz")
@Api(value = "业务字典", tags = "业务字典")
public class DictBizController {
private final IDictBizService dictService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@ApiOperation(value = "详情", notes = "传入dict")
public R<DictBizVO> detail(DictBiz dict) {
DictBiz detail = dictService.getOne(Condition.getQueryWrapper(dict));
return R.data(DictBizWrapper.build().entityVO(detail));
}
/**
* 列表
*/
@GetMapping("/list")
@ApiImplicitParams({
@ApiImplicitParam(name = "code", value = "字典编号", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "dictValue", value = "字典名称", paramType = "query", dataType = "string")
})
@ApiOperationSupport(order = 2)
@ApiOperation(value = "列表", notes = "传入dict")
public R<List<DictBizVO>> list(@ApiIgnore @RequestParam Map<String, Object> dict) {
List<DictBiz> list = dictService.list(Condition.getQueryWrapper(dict, DictBiz.class).lambda().orderByAsc(DictBiz::getSort));
return R.data(DictBizWrapper.build().listNodeVO(list));
}
/**
* 顶级列表
*/
@GetMapping("/parent-list")
@ApiImplicitParams({
@ApiImplicitParam(name = "code", value = "字典编号", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "dictValue", value = "字典名称", paramType = "query", dataType = "string")
})
@ApiOperationSupport(order = 3)
@ApiOperation(value = "列表", notes = "传入dict")
public R<IPage<DictBizVO>> parentList(@ApiIgnore @RequestParam Map<String, Object> dict, Query query) {
return R.data(dictService.parentList(dict, query));
}
/**
* 子列表
*/
@GetMapping("/child-list")
@ApiImplicitParams({
@ApiImplicitParam(name = "code", value = "字典编号", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "dictValue", value = "字典名称", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "parentId", value = "字典名称", paramType = "query", dataType = "string")
})
@ApiOperationSupport(order = 4)
@ApiOperation(value = "列表", notes = "传入dict")
public R<List<DictBizVO>> childList(@ApiIgnore @RequestParam Map<String, Object> dict, @RequestParam(required = false, defaultValue = "-1") Long parentId) {
return R.data(dictService.childList(dict, parentId));
}
/**
* 获取字典树形结构
*/
@GetMapping("/tree")
@ApiOperationSupport(order = 5)
@ApiOperation(value = "树形结构", notes = "树形结构")
public R<List<DictBizVO>> tree() {
List<DictBizVO> tree = dictService.tree();
return R.data(tree);
}
/**
* 获取字典树形结构
*/
@GetMapping("/parent-tree")
@ApiOperationSupport(order = 5)
@ApiOperation(value = "树形结构", notes = "树形结构")
public R<List<DictBizVO>> parentTree() {
List<DictBizVO> tree = dictService.parentTree();
return R.data(tree);
}
/**
* 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@ApiOperation(value = "新增或修改", notes = "传入dict")
public R submit(@Valid @RequestBody DictBiz dict) {
CacheUtil.clear(DICT_CACHE);
return R.status(dictService.submit(dict));
}
/**
* 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@ApiOperation(value = "删除", notes = "传入ids")
public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
CacheUtil.clear(DICT_CACHE);
return R.status(dictService.removeDict(ids));
}
/**
* 获取字典
*/
@GetMapping("/dictionary")
@ApiOperationSupport(order = 8)
@ApiOperation(value = "获取字典", notes = "获取字典")
public R<List<DictBiz>> dictionary(String code) {
List<DictBiz> tree = dictService.getList(code);
return R.data(tree);
}
/**
* 获取字典树
*/
@GetMapping("/dictionary-tree")
@ApiOperationSupport(order = 9)
@ApiOperation(value = "获取字典树", notes = "获取字典树")
public R<List<DictBizVO>> dictionaryTree(String code) {
List<DictBiz> tree = dictService.getList(code);
return R.data(DictBizWrapper.build().listNodeVO(tree));
}
}

View File

@ -0,0 +1,206 @@
package org.springblade.auth.system.controller;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import org.springblade.auth.system.entity.Menu;
import org.springblade.auth.system.service.IMenuService;
import org.springblade.auth.system.vo.MenuVO;
import org.springblade.auth.system.wrapper.MenuWrapper;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.Func;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import static org.springblade.core.cache.constant.CacheConstant.MENU_CACHE;
/**
* 控制器
*
* @author Chill
*/
@NonDS
@RestController
@AllArgsConstructor
@RequestMapping("/menu")
@Api(value = "菜单", tags = "菜单")
public class MenuController extends BladeController {
private final IMenuService menuService;
/**
* 详情
*/
@GetMapping("/detail")
@PreAuth(RoleConstant.HAS_ROLE_ADMINISTRATOR)
@ApiOperationSupport(order = 1)
@ApiOperation(value = "详情", notes = "传入menu")
public R<MenuVO> detail(Menu menu) {
Menu detail = menuService.getOne(Condition.getQueryWrapper(menu));
return R.data(MenuWrapper.build().entityVO(detail));
}
/**
* 列表
*/
@GetMapping("/list")
@ApiImplicitParams({
@ApiImplicitParam(name = "code", value = "菜单编号", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "name", value = "菜单名称", paramType = "query", dataType = "string")
})
@PreAuth(RoleConstant.HAS_ROLE_ADMINISTRATOR)
@ApiOperationSupport(order = 2)
@ApiOperation(value = "列表", notes = "传入menu")
public R<List<MenuVO>> list(@ApiIgnore @RequestParam Map<String, Object> menu) {
List<Menu> list = menuService.list(Condition.getQueryWrapper(menu, Menu.class).lambda().orderByAsc(Menu::getSort));
return R.data(MenuWrapper.build().listNodeVO(list));
}
/**
* 懒加载列表
*/
@GetMapping("/lazy-list")
@ApiImplicitParams({
@ApiImplicitParam(name = "code", value = "菜单编号", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "name", value = "菜单名称", paramType = "query", dataType = "string")
})
@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
@ApiOperationSupport(order = 3)
@ApiOperation(value = "懒加载列表", notes = "传入menu")
public R<List<MenuVO>> lazyList(Long parentId, @ApiIgnore @RequestParam Map<String, Object> menu) {
List<MenuVO> list = menuService.lazyList(parentId, menu);
return R.data(MenuWrapper.build().listNodeLazyVO(list));
}
/**
* 菜单列表
*/
@GetMapping("/menu-list")
@ApiImplicitParams({
@ApiImplicitParam(name = "code", value = "菜单编号", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "name", value = "菜单名称", paramType = "query", dataType = "string")
})
@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
@ApiOperationSupport(order = 4)
@ApiOperation(value = "菜单列表", notes = "传入menu")
public R<List<MenuVO>> menuList(@ApiIgnore @RequestParam Map<String, Object> menu) {
List<Menu> list = menuService.list(Condition.getQueryWrapper(menu, Menu.class).lambda().eq(Menu::getCategory, 1).orderByAsc(Menu::getSort));
return R.data(MenuWrapper.build().listNodeVO(list));
}
/**
* 懒加载菜单列表
*/
@GetMapping("/lazy-menu-list")
@ApiImplicitParams({
@ApiImplicitParam(name = "code", value = "菜单编号", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "name", value = "菜单名称", paramType = "query", dataType = "string")
})
@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
@ApiOperationSupport(order = 5)
@ApiOperation(value = "懒加载菜单列表", notes = "传入menu")
public R<List<MenuVO>> lazyMenuList(Long parentId, @ApiIgnore @RequestParam Map<String, Object> menu) {
List<MenuVO> list = menuService.lazyMenuList(parentId, menu);
return R.data(MenuWrapper.build().listNodeLazyVO(list));
}
/**
* 新增或修改
*/
@PostMapping("/submit")
@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
@ApiOperationSupport(order = 6)
@ApiOperation(value = "新增或修改", notes = "传入menu")
public R<Kv> submit(@Valid @RequestBody Menu menu) {
if (menuService.submit(menu)) {
CacheUtil.clear(MENU_CACHE);
CacheUtil.clear(MENU_CACHE, Boolean.FALSE);
// 返回懒加载树更新节点所需字段
Kv kv = Kv.create().set("id", String.valueOf(menu.getId()));
return R.data(kv);
}
return R.fail("操作失败");
}
/**
* 删除
*/
@PostMapping("/remove")
@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
@ApiOperationSupport(order = 7)
@ApiOperation(value = "删除", notes = "传入ids")
public R<Boolean> remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
CacheUtil.clear(MENU_CACHE);
CacheUtil.clear(MENU_CACHE, Boolean.FALSE);
return R.status(menuService.removeMenu(ids));
}
/**
* 前端菜单数据
*/
@GetMapping("/routes")
@ApiOperationSupport(order = 8)
@ApiOperation(value = "前端菜单数据", notes = "前端菜单数据")
public R<List<MenuVO>> routes(BladeUser user, Long topMenuId) {
List<MenuVO> list = menuService.routes((user == null) ? null : user.getRoleId(), topMenuId);
return R.data(list);
}
/**
* 前端按钮数据
*/
@GetMapping("/buttons")
@ApiOperationSupport(order = 10)
@ApiOperation(value = "前端按钮数据", notes = "前端按钮数据")
public R<List<MenuVO>> buttons(BladeUser user) {
List<MenuVO> list = menuService.buttons(user.getRoleId());
return R.data(list);
}
/**
* 获取菜单树形结构
*/
@GetMapping("/tree")
@ApiOperationSupport(order = 11)
@ApiOperation(value = "树形结构", notes = "树形结构")
public R<List<MenuVO>> tree() {
List<MenuVO> tree = menuService.tree();
return R.data(tree);
}
/**
* 获取配置的角色权限
*/
@GetMapping("auth-routes")
@ApiOperationSupport(order = 17)
@ApiOperation(value = "菜单的角色权限")
public R<List<Kv>> authRoutes(BladeUser user) {
if (Func.isEmpty(user)) {
return null;
}
return R.data(menuService.authRoutes(user));
}
}

View File

@ -0,0 +1,160 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import org.springblade.auth.system.service.IRoleService;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.secure.constant.AuthConstant;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.utils.Func;
import org.springblade.auth.system.cache.SysCache;
import org.springblade.auth.system.entity.Role;
import org.springblade.auth.system.vo.RoleVO;
import org.springblade.auth.system.wrapper.RoleWrapper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import static org.springblade.core.cache.constant.CacheConstant.SYS_CACHE;
/**
* 控制器
*
* @author Chill
*/
@NonDS
@RestController
@AllArgsConstructor
@RequestMapping("/role")
@Api(value = "角色", tags = "角色")
@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
public class RoleController extends BladeController {
private final IRoleService roleService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@ApiOperation(value = "详情", notes = "传入role")
public R<RoleVO> detail(Role role) {
Role detail = roleService.getOne(Condition.getQueryWrapper(role));
return R.data(RoleWrapper.build().entityVO(detail));
}
/**
* 列表
*/
@GetMapping("/list")
@ApiImplicitParams({
@ApiImplicitParam(name = "roleName", value = "参数名称", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "roleAlias", value = "角色别名", paramType = "query", dataType = "string")
})
@ApiOperationSupport(order = 2)
@ApiOperation(value = "列表", notes = "传入role")
public R<List<RoleVO>> list(@ApiIgnore @RequestParam Map<String, Object> role, BladeUser bladeUser) {
QueryWrapper<Role> queryWrapper = Condition.getQueryWrapper(role, Role.class);
List<Role> list = roleService.list((!bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID)) ? queryWrapper.lambda().eq(Role::getTenantId, bladeUser.getTenantId()) : queryWrapper);
return R.data(RoleWrapper.build().listNodeVO(list));
}
/**
* 获取角色树形结构
*/
@GetMapping("/tree")
@ApiOperationSupport(order = 3)
@ApiOperation(value = "树形结构", notes = "树形结构")
public R<List<RoleVO>> tree(String tenantId, BladeUser bladeUser) {
List<RoleVO> tree = roleService.tree(Func.toStrWithEmpty(tenantId, bladeUser.getTenantId()));
return R.data(tree);
}
/**
* 获取指定角色树形结构
*/
@GetMapping("/tree-by-id")
@ApiOperationSupport(order = 4)
@ApiOperation(value = "树形结构", notes = "树形结构")
public R<List<RoleVO>> treeById(Long roleId, BladeUser bladeUser) {
Role role = SysCache.getRole(roleId);
List<RoleVO> tree = roleService.tree(Func.notNull(role) ? role.getTenantId() : bladeUser.getTenantId());
return R.data(tree);
}
/**
* 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 5)
@ApiOperation(value = "新增或修改", notes = "传入role")
public R submit(@Valid @RequestBody Role role) {
CacheUtil.clear(SYS_CACHE);
CacheUtil.clear(SYS_CACHE, Boolean.FALSE);
return R.status(roleService.submit(role));
}
/**
* 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 6)
@ApiOperation(value = "删除", notes = "传入ids")
public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
CacheUtil.clear(SYS_CACHE);
CacheUtil.clear(SYS_CACHE, Boolean.FALSE);
return R.status(roleService.removeByIds(Func.toLongList(ids)));
}
/**
* 下拉数据源
*/
@PreAuth(AuthConstant.PERMIT_ALL)
@GetMapping("/select")
@ApiOperationSupport(order = 8)
@ApiOperation(value = "下拉数据源", notes = "传入id集合")
public R<List<Role>> select(String roleId) {
List<Role> list = roleService.list(Wrappers.<Role>lambdaQuery().in(Role::getId, Func.toLongList(roleId)));
return R.data(list);
}
}

View File

@ -0,0 +1,216 @@
package org.springblade.auth.system.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import org.springblade.auth.system.entity.User;
import org.springblade.auth.system.service.IUserService;
import org.springblade.auth.system.vo.UserVO;
import org.springblade.auth.system.wrapper.UserWrapper;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.StringPool;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import static org.springblade.core.cache.constant.CacheConstant.USER_CACHE;
/**
* 控制器
*
* @author Chill
*/
@NonDS
@RestController
@RequestMapping("/user")
@AllArgsConstructor
public class UserController {
private final IUserService userService;
/**
* 查询单条
*/
@ApiOperationSupport(order = 1)
@ApiOperation(value = "查看详情", notes = "传入id")
@GetMapping("/detail")
public R<UserVO> detail(User user) {
User detail = userService.getOne(Condition.getQueryWrapper(user));
return R.data(UserWrapper.build().entityVO(detail));
}
/**
* 查询单条
*/
@ApiOperationSupport(order = 2)
@ApiOperation(value = "查看详情", notes = "传入id")
@GetMapping("/info")
public R<UserVO> info(BladeUser user) {
User detail = userService.getById(user.getUserId());
return R.data(UserWrapper.build().entityVO(detail));
}
/**
* 用户列表
*/
@GetMapping("/list")
@ApiImplicitParams({
@ApiImplicitParam(name = "account", value = "账号名", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "realName", value = "姓名", paramType = "query", dataType = "string")
})
@ApiOperationSupport(order = 3)
@ApiOperation(value = "列表", notes = "传入account和realName")
public R<IPage<UserVO>> list(@ApiIgnore @RequestParam Map<String, Object> user, Query query, BladeUser bladeUser) {
QueryWrapper<User> queryWrapper = Condition.getQueryWrapper(user, User.class);
IPage<User> pages = userService.page(Condition.getPage(query), (!bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID)) ? queryWrapper.lambda().eq(User::getTenantId, bladeUser.getTenantId()) : queryWrapper);
return R.data(UserWrapper.build().pageVO(pages));
}
/**
* 自定义用户列表
*/
@GetMapping("/page")
@ApiImplicitParams({
@ApiImplicitParam(name = "account", value = "账号名", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "realName", value = "姓名", paramType = "query", dataType = "string")
})
@ApiOperationSupport(order = 3)
@ApiOperation(value = "列表", notes = "传入account和realName")
//@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
//添加组长可以查询人员的权限
//@PreAuth("hasAnyRole('" + RoleConstant.ADMINISTRATOR + "', '" + RoleConstant.ADMIN + "','" + RoleConstant.USER + "')")
public R<IPage<UserVO>> page(@ApiIgnore User user, Query query, Long deptId, BladeUser bladeUser) {
IPage<User> pages = userService.selectUserPage(Condition.getPage(query), user, deptId, (bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID) ? StringPool.EMPTY : bladeUser.getTenantId()));
return R.data(UserWrapper.build().pageVO(pages));
}
/**
* 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 4)
@ApiOperation(value = "新增或修改", notes = "传入User")
public R submit(@Valid @RequestBody User user) {
CacheUtil.clear(USER_CACHE);
return R.status(userService.submit(user));
}
/**
* 修改
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@ApiOperation(value = "修改", notes = "传入User")
public R update(@Valid @RequestBody User user) {
CacheUtil.clear(USER_CACHE);
return R.status(userService.updateUser(user));
}
/**
* 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 6)
@ApiOperation(value = "删除", notes = "传入id集合")
public R remove(@RequestParam String ids) {
CacheUtil.clear(USER_CACHE);
return R.status(userService.removeUser(ids));
}
/**
* 设置菜单权限
*/
@PostMapping("/grant")
@ApiOperationSupport(order = 7)
@ApiOperation(value = "权限设置", notes = "传入roleId集合以及menuId集合")
public R grant(@ApiParam(value = "userId集合", required = true) @RequestParam String userIds,
@ApiParam(value = "roleId集合", required = true) @RequestParam String roleIds) {
boolean temp = userService.grant(userIds, roleIds);
return R.status(temp);
}
/**
* 密码重制
*/
@PostMapping("/reset-password")
@ApiOperationSupport(order = 8)
@ApiOperation(value = "初始化密码", notes = "传入userId集合")
public R resetPassword(@ApiParam(value = "userId集合", required = true) @RequestParam String userIds) {
boolean temp = userService.resetPassword(userIds);
return R.status(temp);
}
/**
* 修改密码
*/
@PostMapping("/update-password")
@ApiOperationSupport(order = 9)
@ApiOperation(value = "修改密码", notes = "传入密码")
public R updatePassword(BladeUser user, @ApiParam(value = "旧密码", required = true) @RequestParam String oldPassword,
@ApiParam(value = "新密码", required = true) @RequestParam String newPassword,
@ApiParam(value = "新密码", required = true) @RequestParam String newPassword1) {
boolean temp = userService.updatePassword(user.getUserId(), oldPassword, newPassword, newPassword1);
return R.status(temp);
}
/**
* 修改基本信息
*/
@PostMapping("/update-info")
@ApiOperationSupport(order = 10)
@ApiOperation(value = "修改基本信息", notes = "传入User")
public R updateInfo(@Valid @RequestBody User user) {
CacheUtil.clear(USER_CACHE);
return R.status(userService.updateUserInfo(user));
}
/**
* 用户列表
*/
@GetMapping("/user-list")
@ApiOperationSupport(order = 11)
@ApiOperation(value = "用户列表", notes = "传入user")
public R<List<User>> userList(User user, BladeUser bladeUser) {
QueryWrapper<User> queryWrapper = Condition.getQueryWrapper(user);
List<User> list = userService.list((!AuthUtil.isAdministrator()) ? queryWrapper.lambda().eq(User::getTenantId, bladeUser.getTenantId()) : queryWrapper);
return R.data(list);
}
/**
* 用户列表查询
*/
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "人员姓名", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "deptName", value = "部门名称", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "postName", value = "职位名称", paramType = "query", dataType = "string"),
@ApiImplicitParam(name = "current", value = "当前页数", paramType = "query", dataType = "int"),
@ApiImplicitParam(name = "size", value = "每页数量", paramType = "query", dataType = "int")
})
@ApiOperationSupport(order = 18)
@ApiOperation(value = "用户列表查询", notes = "用户列表查询")
@GetMapping("/search/user")
public R<IPage<UserVO>> userSearch(@ApiIgnore UserVO user, @ApiIgnore Query query) {
return R.data(userService.selectUserSearch(user, query));
}
}

View File

@ -0,0 +1,17 @@
package org.springblade.auth.system.dto;
import lombok.Data;
import java.io.Serializable;
/**
* 数据传输对象实体类
*
* @author Chill
*/
@Data
public class MenuDTO implements Serializable {
private static final long serialVersionUID = 1L;
private String alias;
private String path;
}

View File

@ -0,0 +1,17 @@
package org.springblade.auth.system.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.auth.system.entity.Role;
/**
* 数据传输对象实体类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class RoleDTO extends Role {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,17 @@
package org.springblade.auth.system.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.auth.system.entity.RoleMenu;
/**
* 数据传输对象实体类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class RoleMenuDTO extends RoleMenu {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,92 @@
package org.springblade.auth.system.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("blade_dict_biz")
@ApiModel(value = "DictBiz对象", description = "DictBiz对象")
public class DictBiz implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 租户ID
*/
@ApiModelProperty(value = "租户ID")
private String tenantId;
/**
* 父主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "父主键")
private Long parentId;
/**
* 字典码
*/
@ApiModelProperty(value = "字典码")
private String code;
/**
* 字典值
*/
@ApiModelProperty(value = "字典值")
private String dictKey;
/**
* 字典名称
*/
@ApiModelProperty(value = "字典名称")
private String dictValue;
/**
* 排序
*/
@ApiModelProperty(value = "排序")
private Integer sort;
/**
* 字典备注
*/
@ApiModelProperty(value = "字典备注")
private String remark;
/**
* 是否已封存
*/
@ApiModelProperty(value = "是否已封存")
private Integer isSealed;
/**
* 是否已删除
*/
@TableLogic
@ApiModelProperty(value = "是否已删除")
private Integer isDeleted;
}

View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springblade.core.tool.utils.Func;
import java.io.Serializable;
import java.util.Objects;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("blade_menu")
@ApiModel(value = "Menu对象", description = "Menu对象")
public class Menu implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 菜单父主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "菜单父主键")
private Long parentId;
/**
* 菜单编号
*/
@ApiModelProperty(value = "菜单编号")
private String code;
/**
* 菜单名称
*/
@ApiModelProperty(value = "菜单名称")
private String name;
/**
* 菜单别名
*/
@ApiModelProperty(value = "菜单别名")
private String alias;
/**
* 请求地址
*/
@ApiModelProperty(value = "请求地址")
private String path;
/**
* 菜单资源
*/
@ApiModelProperty(value = "菜单资源")
private String source;
/**
* 排序
*/
@ApiModelProperty(value = "排序")
private Integer sort;
/**
* 菜单类型
*/
@ApiModelProperty(value = "菜单类型")
private Integer category;
/**
* 操作按钮类型
*/
@ApiModelProperty(value = "操作按钮类型")
private Integer action;
/**
* 是否打开新页面
*/
@ApiModelProperty(value = "是否打开新页面")
private Integer isOpen;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remark;
/**
* 是否已删除
*/
@TableLogic
@ApiModelProperty(value = "是否已删除")
private Integer isDeleted;
/**
* 是否隐藏
*/
@ApiModelProperty(value = "是否隐藏")
private Integer isHidden;
/**
* 手动添加的隐藏的set方法
*/
public void setIsHidden(Integer isHidden) {
this.isHidden = isHidden;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
Menu other = (Menu) obj;
if (Func.equals(this.getId(), other.getId())) {
return true;
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(id, parentId, code);
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("blade_role")
@ApiModel(value = "Role对象", description = "Role对象")
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 租户ID
*/
@ApiModelProperty(value = "租户ID")
private String tenantId;
/**
* 父主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "父主键")
private Long parentId;
/**
* 角色名
*/
@ApiModelProperty(value = "角色名")
private String roleName;
/**
* 排序
*/
@ApiModelProperty(value = "排序")
private Integer sort;
/**
* 角色别名
*/
@ApiModelProperty(value = "角色别名")
private String roleAlias;
/**
* 是否已删除
*/
@TableLogic
@ApiModelProperty(value = "是否已删除")
private Integer isDeleted;
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("blade_role_menu")
@ApiModel(value = "RoleMenu对象", description = "RoleMenu对象")
public class RoleMenu implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 菜单id
*/
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "菜单id")
private Long menuId;
/**
* 角色id
*/
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "角色id")
private Long roleId;
}

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.util.Date;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("blade_user")
@EqualsAndHashCode(callSuper = true)
public class User extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 用户编号
*/
private String code;
/**
* 用户平台
*/
private Integer userType;
/**
* 账号
*/
private String account;
/**
* 密码
*/
private String password;
/**
* 昵称
*/
private String name;
/**
* 真名
*/
private String realName;
/**
* 用户身份证号
*/
private String idCard;
/**
* 头像
*/
private String avatar;
/**
* 邮箱
*/
private String email;
/**
* 手机
*/
private String phone;
/**
* 生日
*/
private Date birthday;
/**
* 性别
*/
private Integer sex;
/**
* 角色id
*/
private String roleId;
/**
* 部门id
*/
private String deptId;
/**
* 岗位id
*/
private String postId;
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springblade.core.tool.support.Kv;
import java.io.Serializable;
import java.util.List;
/**
* 用户信息
*
* @author Chill
*/
@Data
@ApiModel(description = "用户信息")
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 第三方授权id
*/
@ApiModelProperty(value = "第三方授权id")
private String oauthId;
/**
* 用户基础信息
*/
@ApiModelProperty(value = "用户")
private User user;
/**
* 拓展信息
*/
@ApiModelProperty(value = "拓展信息")
private Kv detail;
/**
* 权限标识集合
*/
@ApiModelProperty(value = "权限集合")
private List<String> permissions;
/**
* 角色集合
*/
@ApiModelProperty(value = "角色集合")
private List<String> roles;
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 用户类型枚举
*
* @author Chill
*/
@Getter
@AllArgsConstructor
public enum UserEnum {
/**
* web
*/
WEB("web", 1),
/**
* app
*/
APP("app", 2),
/**
* other
*/
OTHER("other", 3),
;
final String name;
final int category;
/**
* 匹配枚举值
*
* @param name 名称
* @return BladeUserEnum
*/
public static UserEnum of(String name) {
if (name == null) {
return null;
}
UserEnum[] values = UserEnum.values();
for (UserEnum smsEnum : values) {
if (smsEnum.name.equals(name)) {
return smsEnum;
}
}
return null;
}
}

View File

@ -0,0 +1,48 @@
package org.springblade.auth.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springblade.auth.system.entity.DictBiz;
import org.springblade.auth.system.vo.DictBizVO;
import java.util.List;
/**
* Mapper 接口
*
* @author Chill
*/
public interface DictBizMapper extends BaseMapper<DictBiz> {
/**
* 获取字典表对应中文
*
* @param code 字典编号
* @param dictKey 字典序号
* @return
*/
String getValue(String code, String dictKey);
/**
* 获取字典表
*
* @param code 字典编号
* @return
*/
List<DictBiz> getList(String code);
/**
* 获取树形节点
*
* @return
*/
List<DictBizVO> tree();
/**
* 获取树形节点
*
* @return
*/
List<DictBizVO> parentTree();
}

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.springblade.auth.system.mapper.DictBizMapper">
<!-- 通用查询映射结果 -->
<resultMap id="dictResultMap" type="org.springblade.auth.system.entity.DictBiz">
<id column="id" property="id"/>
<result column="tenant_id" property="tenantId"/>
<result column="parent_id" property="parentId"/>
<result column="code" property="code"/>
<result column="dict_key" property="dictKey"/>
<result column="dict_value" property="dictValue"/>
<result column="sort" property="sort"/>
<result column="remark" property="remark"/>
<result column="is_deleted" property="isDeleted"/>
</resultMap>
<resultMap id="treeNodeResultMap" type="org.springblade.core.tool.node.TreeNode">
<id column="id" property="id"/>
<result column="parent_id" property="parentId"/>
<result column="title" property="title"/>
<result column="value" property="value"/>
<result column="key" property="key"/>
</resultMap>
<select id="getValue" resultType="java.lang.String">
select
dict_value
from blade_dict_biz where code = #{param1} and dict_key = #{param2} and is_deleted = 0
</select>
<!-- oracle 版本 -->
<!--<select id="getValue" resultType="java.lang.String">
select
dict_value
from blade_dict_biz where code = #{param1, jdbcType=VARCHAR} and dict_key = #{param2} and dict_key >= 0 rownum 1
</select>-->
<select id="getList" resultMap="dictResultMap">
select id, parent_id, code, dict_key, dict_value, sort, remark from blade_dict_biz where code = #{param1} and parent_id > 0 and is_sealed = 0 and is_deleted = 0
</select>
<select id="tree" resultMap="treeNodeResultMap">
select id, parent_id, dict_value as title, id as "value", id as "key" from blade_dict_biz where is_deleted = 0
</select>
<select id="parentTree" resultMap="treeNodeResultMap">
select id, parent_id, dict_value as title, id as "value", id as "key" from blade_dict_biz where is_deleted = 0 and parent_id = 0
</select>
</mapper>

View File

@ -0,0 +1,182 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springblade.auth.system.dto.MenuDTO;
import org.springblade.auth.system.entity.Menu;
import org.springblade.auth.system.vo.MenuVO;
import java.util.List;
import java.util.Map;
/**
* MenuMapper 接口
*
* @author Chill
*/
public interface MenuMapper extends BaseMapper<Menu> {
/**
* 懒加载列表
*
* @param parentId
* @param param
* @return
*/
List<MenuVO> lazyList(Long parentId, Map<String, Object> param);
/**
* 懒加载菜单列表
*
* @param parentId
* @param param
* @return
*/
List<MenuVO> lazyMenuList(Long parentId, Map<String, Object> param);
/**
* 树形结构
*
* @return
*/
List<MenuVO> tree();
/**
* 授权树形结构
*
* @return
*/
List<MenuVO> grantTree();
/**
* 授权树形结构
*
* @param roleId
* @return
*/
List<MenuVO> grantTreeByRole(List<Long> roleId);
/**
* 顶部菜单树形结构
*
* @return
*/
List<MenuVO> grantTopTree();
/**
* 顶部菜单树形结构
*
* @param roleId
* @return
*/
List<MenuVO> grantTopTreeByRole(List<Long> roleId);
/**
* 数据权限授权树形结构
*
* @return
*/
List<MenuVO> grantDataScopeTree();
/**
* 接口权限授权树形结构
*
* @return
*/
List<MenuVO> grantApiScopeTree();
/**
* 数据权限授权树形结构
*
* @param roleId
* @return
*/
List<MenuVO> grantDataScopeTreeByRole(List<Long> roleId);
/**
* 接口权限授权树形结构
*
* @param roleId
* @return
*/
List<MenuVO> grantApiScopeTreeByRole(List<Long> roleId);
/**
* 所有菜单
*
* @return
*/
List<Menu> allMenu();
/**
* 权限配置菜单
*
* @param roleId
* @param topMenuId
* @return
*/
List<Menu> roleMenu(List<Long> roleId, Long topMenuId);
/**
* 权限配置菜单
*
* @param roleId
* @return
*/
List<Menu> roleMenuByRoleId(List<Long> roleId);
/**
* 权限配置菜单
*
* @param topMenuId
* @return
*/
List<Menu> roleMenuByTopMenuId(Long topMenuId);
/**
* 菜单树形结构
*
* @param roleId
* @return
*/
List<Menu> routes(List<Long> roleId);
/**
* 按钮树形结构
*
* @return
*/
List<Menu> allButtons();
/**
* 按钮树形结构
*
* @param roleId
* @return
*/
List<Menu> buttons(List<Long> roleId);
/**
* 获取配置的角色权限
*
* @param roleIds
* @return
*/
List<MenuDTO> authRoutes(List<Long> roleIds);
}

View File

@ -0,0 +1,478 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.springblade.auth.system.mapper.MenuMapper">
<!-- 通用查询映射结果 -->
<resultMap id="menuResultMap" type="org.springblade.auth.system.entity.Menu">
<id column="id" property="id"/>
<result column="code" property="code"/>
<result column="parent_id" property="parentId"/>
<result column="name" property="name"/>
<result column="alias" property="alias"/>
<result column="path" property="path"/>
<result column="source" property="source"/>
<result column="sort" property="sort"/>
<result column="category" property="category"/>
<result column="action" property="action"/>
<result column="is_open" property="isOpen"/>
<result column="remark" property="remark"/>
<result column="is_deleted" property="isDeleted"/>
</resultMap>
<resultMap id="menuVOResultMap" type="org.springblade.auth.system.vo.MenuVO">
<id column="id" property="id"/>
<result column="code" property="code"/>
<result column="parent_id" property="parentId"/>
<result column="name" property="name"/>
<result column="alias" property="alias"/>
<result column="path" property="path"/>
<result column="source" property="source"/>
<result column="sort" property="sort"/>
<result column="category" property="category"/>
<result column="action" property="action"/>
<result column="is_open" property="isOpen"/>
<result column="remark" property="remark"/>
<result column="is_deleted" property="isDeleted"/>
<result column="has_children" property="hasChildren"/>
</resultMap>
<resultMap id="treeNodeResultMap" type="org.springblade.core.tool.node.TreeNode">
<id column="id" property="id"/>
<result column="parent_id" property="parentId"/>
<result column="title" property="title"/>
<result column="value" property="value"/>
<result column="key" property="key"/>
</resultMap>
<select id="lazyList" resultMap="menuVOResultMap">
SELECT
menu.*,
(
SELECT
CASE WHEN count( 1 ) > 0 THEN 1 ELSE 0 END
FROM
blade_menu
WHERE
parent_id = menu.id AND is_deleted = 0
) AS "has_children"
FROM
blade_menu menu
WHERE menu.is_deleted = 0
<if test="param1!=null">
and menu.parent_id = #{param1}
</if>
<if test="param2.name!=null and param2.name!=''">
and menu.name like concat(concat('%', #{param2.name}),'%')
</if>
<if test="param2.code!=null and param2.code!=''">
and menu.code like concat(concat('%', #{param2.code}),'%')
</if>
<if test="param2.alias!=null and param2.alias!=''">
and menu.alias like concat(concat('%', #{param2.alias}),'%')
</if>
ORDER BY menu.sort
</select>
<select id="lazyMenuList" resultMap="menuVOResultMap">
SELECT
menu.*,
(
SELECT
CASE WHEN count( 1 ) > 0 THEN 1 ELSE 0 END
FROM
blade_menu
WHERE
parent_id = menu.id AND is_deleted = 0 AND category = 1
) AS "has_children"
FROM
blade_menu menu
WHERE menu.is_deleted = 0 AND menu.category = 1
<if test="param1!=null">
and menu.parent_id = #{param1}
</if>
<if test="param2.name!=null and param2.name!=''">
and menu.name like concat(concat('%', #{param2.name}),'%')
</if>
<if test="param2.code!=null and param2.code!=''">
and menu.code like concat(concat('%', #{param2.code}),'%')
</if>
<if test="param2.alias!=null and param2.alias!=''">
and menu.alias like concat(concat('%', #{param2.alias}),'%')
</if>
ORDER BY menu.sort
</select>
<select id="tree" resultMap="treeNodeResultMap">
select id, parent_id, name as title, id as "value", id as "key" from blade_menu where is_deleted = 0 and category = 1
</select>
<select id="allMenu" resultMap="menuResultMap">
select * from blade_menu where is_deleted = 0 and category = 1
</select>
<select id="roleMenu" resultMap="menuResultMap">
select * from blade_menu where is_deleted = 0 and id IN
( SELECT menu_id FROM blade_role_menu WHERE role_id IN
<foreach collection="param1" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
)
<if test="param2!=null and param2>0">
AND id IN
(
SELECT menu_id FROM blade_top_menu_setting WHERE top_menu_id = #{param2}
)
</if>
</select>
<select id="roleMenuByRoleId" resultMap="menuResultMap">
select * from blade_menu where is_deleted = 0 and id IN
( SELECT menu_id FROM blade_role_menu WHERE role_id IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
)
</select>
<select id="roleMenuByTopMenuId" resultMap="menuResultMap">
select * from blade_menu where is_deleted = 0 and id IN
(
SELECT menu_id FROM blade_top_menu_setting WHERE top_menu_id = #{param1}
)
</select>
<select id="routes" resultMap="menuResultMap">
SELECT
*
FROM
blade_menu
WHERE
is_deleted = 0 and category = 1
and id IN ( SELECT menu_id FROM blade_role_menu WHERE role_id IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach> )
</select>
<select id="allButtons" resultMap="menuResultMap">
SELECT
id,
parent_id,
CODE,
NAME,
alias,
path,
source,
action,
sort
FROM
blade_menu
WHERE
(
category = 2 OR id IN ( SELECT parent_id FROM blade_menu WHERE is_deleted = 0 AND category = 2 )
)
AND is_deleted = 0
ORDER BY sort
</select>
<select id="buttons" resultMap="menuResultMap">
SELECT * FROM (
SELECT
id,
parent_id,
code,
name,
alias,
path,
source,
action,
sort
FROM
blade_menu
WHERE
is_deleted = 0 and id IN (
SELECT parent_id FROM blade_menu
WHERE ( category = 2 AND id IN ( SELECT menu_id FROM blade_role_menu WHERE role_id IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
) ) )
UNION ALL
SELECT
id,
parent_id,
code,
name,
alias,
path,
source,
action,
sort
FROM
blade_menu
WHERE
is_deleted = 0 and category = 2 AND id IN ( SELECT menu_id FROM blade_role_menu WHERE role_id IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>)
) menu ORDER BY sort
</select>
<select id="grantTree" resultMap="treeNodeResultMap">
select id, parent_id, name as title, id as "value", id as "key" from blade_menu where is_deleted = 0 order by sort
</select>
<select id="grantTreeByRole" resultMap="treeNodeResultMap">
select id, parent_id, name as title, id as "value", id as "key" from blade_menu where is_deleted = 0
and id in ( select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach> )
or id in (
select parent_id from blade_menu where is_deleted = 0
and id in ( select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach> )
)
order by sort
</select>
<select id="grantTopTree" resultMap="treeNodeResultMap">
select id, parent_id, name as title, id as "value", id as "key" from blade_menu where category = 1 and is_deleted = 0 order by sort
</select>
<select id="grantTopTreeByRole" resultMap="treeNodeResultMap">
select id, parent_id, name as title, id as "value", id as "key" from blade_menu where category = 1 and is_deleted = 0
and id in ( select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach> )
or id in (
select parent_id from blade_menu where is_deleted = 0
and id in ( select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach> )
)
order by sort
</select>
<select id="grantDataScopeTree" resultMap="treeNodeResultMap">
SELECT
*
FROM
(
SELECT
id,
parent_id,
NAME AS title,
id AS "value",
id AS "key"
FROM
blade_menu
WHERE
category = 1
AND is_deleted = 0
AND id IN ( SELECT menu_id FROM blade_scope_data WHERE is_deleted = 0 AND menu_id IS NOT NULL )
) menu
UNION ALL
SELECT
id,
menu_id AS parent_id,
scope_name AS title,
id AS "value",
id AS "key"
FROM
blade_scope_data
WHERE
is_deleted = 0
AND menu_id IS NOT NULL
</select>
<select id="grantApiScopeTree" resultMap="treeNodeResultMap">
SELECT
*
FROM
(
SELECT
id,
parent_id,
NAME AS title,
id AS "value",
id AS "key"
FROM
blade_menu
WHERE
category = 1
AND is_deleted = 0
AND id IN ( SELECT menu_id FROM blade_scope_api WHERE is_deleted = 0 AND menu_id IS NOT NULL )
) menu
UNION ALL
SELECT
id,
menu_id AS parent_id,
scope_name AS title,
id AS "value",
id AS "key"
FROM
blade_scope_api
WHERE
is_deleted = 0
AND menu_id IS NOT NULL
</select>
<select id="grantDataScopeTreeByRole" resultMap="treeNodeResultMap">
SELECT
*
FROM
(
SELECT
id,
parent_id,
NAME AS title,
id AS "value",
id AS "key"
FROM
blade_menu
WHERE
category = 1
AND is_deleted = 0
AND id IN ( SELECT menu_id FROM blade_scope_data WHERE is_deleted = 0 AND menu_id IS NOT NULL )
AND (
id IN (
select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
)
OR id IN (
select parent_id from blade_menu where is_deleted = 0
and id in ( select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach> )
)
)
) menu
UNION ALL
SELECT
id,
menu_id AS parent_id,
scope_name AS title,
id AS "value",
id AS "key"
FROM
blade_scope_data
WHERE
is_deleted = 0
AND (
menu_id IN (
select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
)
OR menu_id IN (
select parent_id from blade_menu where is_deleted = 0
and id in ( select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach> )
)
)
AND menu_id IS NOT NULL
</select>
<select id="grantApiScopeTreeByRole" resultMap="treeNodeResultMap">
SELECT
*
FROM
(
SELECT
id,
parent_id,
NAME AS title,
id AS "value",
id AS "key"
FROM
blade_menu
WHERE
category = 1
AND is_deleted = 0
AND id IN ( SELECT menu_id FROM blade_scope_api WHERE is_deleted = 0 AND menu_id IS NOT NULL )
AND (
id IN (
select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
)
OR id IN (
select parent_id from blade_menu where is_deleted = 0
and id in (
select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach> )
)
)
) menu
UNION ALL
SELECT
id,
menu_id AS parent_id,
scope_name AS title,
id AS "value",
id AS "key"
FROM
blade_scope_api
WHERE
is_deleted = 0
AND
(
menu_id IN (
select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
)
OR menu_id IN (
select parent_id from blade_menu where is_deleted = 0
and id in ( select menu_id from blade_role_menu where role_id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach> )
)
)
AND menu_id IS NOT NULL
</select>
<select id="authRoutes" resultType="org.springblade.auth.system.dto.MenuDTO">
SELECT
GROUP_CONCAT(r.role_alias) as alias,
m.path
FROM
blade_role_menu rm
LEFT JOIN blade_menu m ON rm.menu_id = m.id
LEFT JOIN blade_role r ON rm.role_id = r.id
WHERE
rm.role_id IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
AND m.path IS NOT NULL and m.is_deleted = 0
GROUP BY m.path
</select>
</mapper>

View File

@ -0,0 +1,51 @@
package org.springblade.auth.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.auth.system.entity.Role;
import org.springblade.auth.system.vo.RoleVO;
import java.util.List;
/**
* Mapper 接口
*
* @author Chill
*/
public interface RoleMapper extends BaseMapper<Role> {
/**
* 自定义分页
*
* @param page
* @param role
* @return
*/
List<RoleVO> selectRolePage(IPage page, RoleVO role);
/**
* 获取树形节点
*
* @param tenantId
* @param excludeRole
* @return
*/
List<RoleVO> tree(String tenantId, String excludeRole);
/**
* 获取角色名
*
* @param ids
* @return
*/
List<String> getRoleNames(Long[] ids);
/**
* 获取角色名
*
* @param ids
* @return
*/
List<String> getRoleAliases(Long[] ids);
}

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.springblade.auth.system.mapper.RoleMapper">
<!-- 通用查询映射结果 -->
<resultMap id="roleResultMap" type="org.springblade.auth.system.entity.Role">
<id column="id" property="id"/>
<result column="parent_id" property="parentId"/>
<result column="role_name" property="roleName"/>
<result column="sort" property="sort"/>
<result column="role_alias" property="roleAlias"/>
<result column="is_deleted" property="isDeleted"/>
</resultMap>
<resultMap id="treeNodeResultMap" type="org.springblade.core.tool.node.TreeNode">
<id column="id" property="id"/>
<result column="parent_id" property="parentId"/>
<result column="title" property="title"/>
<result column="value" property="value"/>
<result column="key" property="key"/>
</resultMap>
<select id="selectRolePage" resultMap="roleResultMap">
select * from blade_role where is_deleted = 0
</select>
<select id="tree" resultMap="treeNodeResultMap">
select id, parent_id, role_name as title, id as "value", id as "key" from blade_role where is_deleted = 0
<if test="param1!=null">
and tenant_id = #{param1}
</if>
<if test="param2!=null">
and role_alias &lt;&gt; #{param2}
</if>
</select>
<select id="getRoleNames" resultType="java.lang.String">
SELECT
role_name
FROM
blade_role
WHERE
id IN
<foreach collection="array" item="ids" index="index" open="(" close=")" separator=",">
#{ids}
</foreach>
and is_deleted = 0
</select>
<select id="getRoleAliases" resultType="java.lang.String">
SELECT
role_alias
FROM
blade_role
WHERE
id IN
<foreach collection="array" item="ids" index="index" open="(" close=")" separator=",">
#{ids}
</foreach>
and is_deleted = 0
</select>
</mapper>

View File

@ -0,0 +1,25 @@
package org.springblade.auth.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.auth.system.entity.RoleMenu;
import org.springblade.auth.system.vo.RoleMenuVO;
import java.util.List;
/**
* Mapper 接口
*
* @author Chill
*/
public interface RoleMenuMapper extends BaseMapper<RoleMenu> {
/**
* 自定义分页
* @param page
* @param roleMenu
* @return
*/
List<RoleMenuVO> selectRoleMenuPage(IPage page, RoleMenuVO roleMenu);
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.springblade.auth.system.mapper.RoleMenuMapper">
<!-- 通用查询映射结果 -->
<resultMap id="roleMenuResultMap" type="org.springblade.auth.system.entity.RoleMenu">
<id column="id" property="id"/>
<result column="menu_id" property="menuId"/>
<result column="role_id" property="roleId"/>
</resultMap>
<select id="selectRoleMenuPage" resultMap="roleMenuResultMap">
select * from blade_role_menu where is_deleted = 0
</select>
</mapper>

View File

@ -0,0 +1,37 @@
package org.springblade.auth.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;
import org.springblade.auth.system.entity.User;
import java.util.List;
/**
* Mapper 接口
*
* @author Chill
*/
public interface UserMapper extends BaseMapper<User> {
/**
* 自定义分页
*
* @param page
* @param user
* @param deptIdList
* @param tenantId
* @return
*/
List<User> selectUserPage(IPage<User> page, @Param("user") User user, @Param("deptIdList") List<Long> deptIdList, @Param("tenantId") String tenantId);
/**
* 获取用户
*
* @param tenantId
* @param account
* @return
*/
User getUser(String tenantId, String account);
}

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.springblade.auth.system.mapper.UserMapper">
<!-- 通用查询映射结果 -->
<resultMap id="userResultMap" type="org.springblade.auth.system.entity.User">
<result column="id" property="id"/>
<result column="tenant_id" property="tenantId"/>
<result column="create_user" property="createUser"/>
<result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/>
<result column="update_time" property="updateTime"/>
<result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/>
<result column="code" property="code"/>
<result column="user_type" property="userType"/>
<result column="id_card" property="idCard"/>
<result column="account" property="account"/>
<result column="password" property="password"/>
<result column="name" property="name"/>
<result column="real_name" property="realName"/>
<result column="email" property="email"/>
<result column="phone" property="phone"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="role_id" property="roleId"/>
<result column="dept_id" property="deptId"/>
<result column="post_id" property="postId"/>
</resultMap>
<sql id="Base_Column_List">
id,tenant_id,code,user_type,id_card,account,password,name,real_name,email,phone,birthday,sex,role_id,dept_id,post_id,
create_user,create_dept,create_time,update_user,update_time,status,is_deleted
</sql>
<select id="selectUserPage" resultMap="userResultMap">
select
<include refid="Base_Column_List"></include>
from blade_user where is_deleted = 0
<if test="tenantId!=null and tenantId != ''">
and tenant_id = #{tenantId}
</if>
<if test="user.tenantId!=null and user.tenantId != ''">
and tenant_id = #{user.tenantId}
</if>
<if test="user.account!=null and user.account != ''">
and account = #{user.account}
</if>
<if test="user.realName!=null and user.realName != ''">
and real_name = #{user.realName}
</if>
<if test="user.userType!=null and user.userType != ''">
and user_type = #{user.userType}
</if>
<if test="user.postId!=null and user.postId != ''">
and post_id like CONCAT('%',#{user.postId},'%')
</if>
<if test="user.notPostId!=null and user.notPostId != ''">
and post_id not like CONCAT('%',#{user.notPostId},'%')
</if>
<if test="deptIdList!=null and deptIdList.size>0">
and id in (
SELECT
user_id
FROM
blade_user_dept
WHERE
dept_id IN
<foreach collection="deptIdList" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
)
</if>
ORDER BY id
</select>
<select id="getUser" resultMap="userResultMap">
SELECT
<include refid="Base_Column_List"></include>
FROM
blade_user
WHERE
tenant_id = #{param1} and (account = #{param2} or email = #{param2} or phone = #{param2}) and is_deleted = 0
</select>
</mapper>

View File

@ -0,0 +1,85 @@
package org.springblade.auth.system.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springblade.core.mp.support.Query;
import org.springblade.auth.system.entity.DictBiz;
import org.springblade.auth.system.vo.DictBizVO;
import java.util.List;
import java.util.Map;
/**
* 服务类
*
* @author Chill
*/
public interface IDictBizService extends IService<DictBiz> {
/**
* 树形结构
*
* @return
*/
List<DictBizVO> tree();
/**
* 树形结构
*
* @return
*/
List<DictBizVO> parentTree();
/**
* 获取字典表对应中文
*
* @param code 字典编号
* @param dictKey 字典序号
* @return
*/
String getValue(String code, String dictKey);
/**
* 获取字典表
*
* @param code 字典编号
* @return
*/
List<DictBiz> getList(String code);
/**
* 新增或修改
*
* @param dict
* @return
*/
boolean submit(DictBiz dict);
/**
* 删除字典
*
* @param ids
* @return
*/
boolean removeDict(String ids);
/**
* 顶级列表
*
* @param dict
* @param query
* @return
*/
IPage<DictBizVO> parentList(Map<String, Object> dict, Query query);
/**
* 子列表
*
* @param dict
* @param parentId
* @return
*/
List<DictBizVO> childList(Map<String, Object> dict, Long parentId);
}

View File

@ -0,0 +1,101 @@
package org.springblade.auth.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.tool.support.Kv;
import org.springblade.auth.system.entity.Menu;
import org.springblade.auth.system.vo.MenuVO;
import java.util.List;
import java.util.Map;
/**
* 服务类
*
* @author Chill
*/
public interface IMenuService extends IService<Menu> {
/**
* 懒加载列表
*
* @param parentId
* @param param
* @return
*/
List<MenuVO> lazyList(Long parentId, Map<String, Object> param);
/**
* 懒加载菜单列表
*
* @param parentId
* @param param
* @return
*/
List<MenuVO> lazyMenuList(Long parentId, Map<String, Object> param);
/**
* 菜单树形结构
*
* @param roleId
* @param topMenuId
* @return
*/
List<MenuVO> routes(String roleId, Long topMenuId);
/**
* 按钮树形结构
*
* @param roleId
* @return
*/
List<MenuVO> buttons(String roleId);
/**
* 树形结构
*
* @return
*/
List<MenuVO> tree();
/**
* 授权树形结构
*
* @param user
* @return
*/
List<MenuVO> grantTree(BladeUser user);
/**
* 默认选中节点
*
* @param roleIds
* @return
*/
List<String> roleTreeKeys(String roleIds);
/**
* 获取配置的角色权限
*
* @param user
* @return
*/
List<Kv> authRoutes(BladeUser user);
/**
* 删除菜单
*
* @param ids
* @return
*/
boolean removeMenu(String ids);
/**
* 提交
*
* @param menu
* @return
*/
boolean submit(Menu menu);
}

View File

@ -0,0 +1,13 @@
package org.springblade.auth.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springblade.auth.system.entity.RoleMenu;
/**
* 服务类
*
* @author Chill
*/
public interface IRoleMenuService extends IService<RoleMenu> {
}

View File

@ -0,0 +1,76 @@
package org.springblade.auth.system.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springblade.auth.system.entity.Role;
import org.springblade.auth.system.vo.RoleVO;
import java.util.List;
/**
* 服务类
*
* @author Chill
*/
public interface IRoleService extends IService<Role> {
/**
* 自定义分页
*
* @param page
* @param role
* @return
*/
IPage<RoleVO> selectRolePage(IPage<RoleVO> page, RoleVO role);
/**
* 树形结构
*
* @param tenantId
* @return
*/
List<RoleVO> tree(String tenantId);
/**
* 获取角色ID
*
* @param tenantId
* @param roleNames
* @return
*/
String getRoleIds(String tenantId, String roleNames);
/**
* 获取角色名
*
* @param roleIds
* @return
*/
List<String> getRoleNames(String roleIds);
/**
* 获取角色名
*
* @param roleIds
* @return
*/
List<String> getRoleAliases(String roleIds);
/**
* 提交
*
* @param role
* @return
*/
boolean submit(Role role);
/**
* 角色信息查询
*
* @param roleName
* @param parentId
* @return
*/
List<RoleVO> search(String roleName, Long parentId);
}

View File

@ -0,0 +1,125 @@
package org.springblade.auth.system.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.auth.system.entity.User;
import org.springblade.auth.system.entity.UserInfo;
import org.springblade.auth.system.vo.UserVO;
import org.springblade.core.mp.base.BaseService;
import org.springblade.core.mp.support.Query;
/**
* 服务类
*
* @author Chill
*/
public interface IUserService extends BaseService<User> {
/**
* 新增用户
*
* @param user
* @return
*/
boolean submit(User user);
/**
* 修改用户
*
* @param user
* @return
*/
boolean updateUser(User user);
/**
* 修改用户基本信息
*
* @param user
* @return
*/
boolean updateUserInfo(User user);
/**
* 自定义分页
*
* @param page
* @param user
* @param deptId
* @param tenantId
* @return
*/
IPage<User> selectUserPage(IPage<User> page, User user, Long deptId, String tenantId);
/**
* 自定义分页
*
* @param user
* @param query
* @return
*/
IPage<UserVO> selectUserSearch(UserVO user, Query query);
/**
* 用户信息
*
* @param userId
* @return
*/
UserInfo userInfo(Long userId);
/**
* 用户信息
*
* @param tenantId
* @param account
* @return
*/
UserInfo userInfo(String tenantId, String account);
/**
* 根据账号获取用户
*
* @param tenantId
* @param account
* @return
*/
User userByAccount(String tenantId, String account);
/**
* 给用户设置角色
*
* @param userIds
* @param roleIds
* @return
*/
boolean grant(String userIds, String roleIds);
/**
* 初始化密码
*
* @param userIds
* @return
*/
boolean resetPassword(String userIds);
/**
* 修改密码
*
* @param userId
* @param oldPassword
* @param newPassword
* @param newPassword1
* @return
*/
boolean updatePassword(Long userId, String oldPassword, String newPassword, String newPassword1);
/**
* 删除用户
*
* @param userIds
* @return
*/
boolean removeUser(String userIds);
}

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springblade.common.constant.CommonConstant;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.auth.system.cache.DictBizCache;
import org.springblade.auth.system.entity.DictBiz;
import org.springblade.auth.system.mapper.DictBizMapper;
import org.springblade.auth.system.service.IDictBizService;
import org.springblade.auth.system.vo.DictBizVO;
import org.springblade.auth.system.wrapper.DictBizWrapper;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.springblade.core.cache.constant.CacheConstant.DICT_CACHE;
/**
* 服务实现类
*
* @author Chill
*/
@Service
public class DictBizServiceImpl extends ServiceImpl<DictBizMapper, DictBiz> implements IDictBizService {
@Override
public List<DictBizVO> tree() {
return ForestNodeMerger.merge(baseMapper.tree());
}
@Override
public List<DictBizVO> parentTree() {
return ForestNodeMerger.merge(baseMapper.parentTree());
}
@Override
public String getValue(String code, String dictKey) {
return Func.toStr(baseMapper.getValue(code, dictKey), StringPool.EMPTY);
}
@Override
public List<DictBiz> getList(String code) {
return baseMapper.getList(code);
}
@Override
public boolean submit(DictBiz dict) {
LambdaQueryWrapper<DictBiz> lqw = Wrappers.<DictBiz>query().lambda().eq(DictBiz::getCode, dict.getCode()).eq(DictBiz::getDictKey, dict.getDictKey());
Integer cnt = baseMapper.selectCount((Func.isEmpty(dict.getId())) ? lqw : lqw.notIn(DictBiz::getId, dict.getId()));
if (cnt > 0) {
throw new RuntimeException("当前字典键值已存在!");
}
// 修改顶级字典后同步更新下属字典的编号
if (Func.isNotEmpty(dict.getId()) && dict.getParentId().longValue() == BladeConstant.TOP_PARENT_ID) {
DictBiz parent = DictBizCache.getById(dict.getId());
this.update(Wrappers.<DictBiz>update().lambda().set(DictBiz::getCode, dict.getCode()).eq(DictBiz::getCode, parent.getCode()).ne(DictBiz::getParentId, BladeConstant.TOP_PARENT_ID));
}
if (Func.isEmpty(dict.getParentId())) {
dict.setParentId(BladeConstant.TOP_PARENT_ID);
}
dict.setIsDeleted(BladeConstant.DB_NOT_DELETED);
CacheUtil.clear(DICT_CACHE);
return saveOrUpdate(dict);
}
@Override
public boolean removeDict(String ids) {
Integer cnt = baseMapper.selectCount(Wrappers.<DictBiz>query().lambda().in(DictBiz::getParentId, Func.toLongList(ids)));
if (cnt > 0) {
throw new RuntimeException("请先删除子节点!");
}
return removeByIds(Func.toLongList(ids));
}
@Override
public IPage<DictBizVO> parentList(Map<String, Object> dict, Query query) {
IPage<DictBiz> page = this.page(Condition.getPage(query), Condition.getQueryWrapper(dict, DictBiz.class).lambda().eq(DictBiz::getParentId, CommonConstant.TOP_PARENT_ID).orderByAsc(DictBiz::getSort));
return DictBizWrapper.build().pageVO(page);
}
@Override
public List<DictBizVO> childList(Map<String, Object> dict, Long parentId) {
if (parentId < 0) {
return new ArrayList<>();
}
dict.remove("parentId");
DictBiz parentDict = DictBizCache.getById(parentId);
List<DictBiz> list = this.list(Condition.getQueryWrapper(dict, DictBiz.class).lambda().ne(DictBiz::getId, parentId).eq(DictBiz::getCode, parentDict.getCode()).orderByAsc(DictBiz::getSort));
return DictBizWrapper.build().listNodeVO(list);
}
}

View File

@ -0,0 +1,187 @@
package org.springblade.auth.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springblade.auth.system.dto.MenuDTO;
import org.springblade.auth.system.entity.Menu;
import org.springblade.auth.system.entity.RoleMenu;
import org.springblade.auth.system.mapper.MenuMapper;
import org.springblade.auth.system.service.IMenuService;
import org.springblade.auth.system.service.IRoleMenuService;
import org.springblade.auth.system.vo.MenuVO;
import org.springblade.auth.system.wrapper.MenuWrapper;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import static org.springblade.core.cache.constant.CacheConstant.MENU_CACHE;
/**
* 服务实现类
*
* @author Chill
*/
@Service
@AllArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IMenuService {
private final IRoleMenuService roleMenuService;
private final static String PARENT_ID = "parentId";
private final static Integer MENU_CATEGORY = 1;
@Override
public List<MenuVO> lazyList(Long parentId, Map<String, Object> param) {
if (Func.isEmpty(Func.toStr(param.get(PARENT_ID)))) {
parentId = null;
}
return baseMapper.lazyList(parentId, param);
}
@Override
public List<MenuVO> lazyMenuList(Long parentId, Map<String, Object> param) {
if (Func.isEmpty(Func.toStr(param.get(PARENT_ID)))) {
parentId = null;
}
return baseMapper.lazyMenuList(parentId, param);
}
@Override
public List<MenuVO> routes(String roleId, Long topMenuId) {
if (StringUtil.isBlank(roleId)) {
return null;
}
List<Menu> allMenus = baseMapper.allMenu();
List<Menu> roleMenus;
// 超级管理员并且不是顶部菜单请求则返回全部菜单
if (AuthUtil.isAdministrator() && Func.isEmpty(topMenuId)) {
roleMenus = allMenus;
}
// 非超级管理员并且不是顶部菜单请求则返回对应角色权限菜单
else if (!AuthUtil.isAdministrator() && Func.isEmpty(topMenuId)) {
roleMenus = baseMapper.roleMenuByRoleId(Func.toLongList(roleId));
}
// 顶部菜单请求返回对应角色权限菜单
else {
// 角色配置对应菜单
List<Menu> roleIdMenus = baseMapper.roleMenuByRoleId(Func.toLongList(roleId));
// 反向递归角色菜单所有父级
List<Menu> routes = new LinkedList<>(roleIdMenus);
roleIdMenus.forEach(roleMenu -> recursion(allMenus, routes, roleMenu));
// 顶部配置对应菜单
List<Menu> topIdMenus = baseMapper.roleMenuByTopMenuId(topMenuId);
// 筛选匹配角色对应的权限菜单
roleMenus = topIdMenus.stream().filter(x ->
routes.stream().anyMatch(route -> route.getId().longValue() == x.getId().longValue())
).collect(Collectors.toList());
}
return buildRoutes(allMenus, roleMenus);
}
private List<MenuVO> buildRoutes(List<Menu> allMenus, List<Menu> roleMenus) {
List<Menu> routes = new LinkedList<>(roleMenus);
roleMenus.forEach(roleMenu -> recursion(allMenus, routes, roleMenu));
routes.sort(Comparator.comparing(Menu::getSort));
MenuWrapper menuWrapper = new MenuWrapper();
List<Menu> collect = routes.stream().filter(x -> Func.equals(x.getCategory(), 1)).collect(Collectors.toList());
return menuWrapper.listNodeVO(collect);
}
private void recursion(List<Menu> allMenus, List<Menu> routes, Menu roleMenu) {
Optional<Menu> menu = allMenus.stream().filter(x -> Func.equals(x.getId(), roleMenu.getParentId())).findFirst();
if (menu.isPresent() && !routes.contains(menu.get())) {
routes.add(menu.get());
recursion(allMenus, routes, menu.get());
}
}
@Override
public List<MenuVO> buttons(String roleId) {
List<Menu> buttons = (AuthUtil.isAdministrator()) ? baseMapper.allButtons() : baseMapper.buttons(Func.toLongList(roleId));
MenuWrapper menuWrapper = new MenuWrapper();
return menuWrapper.listNodeVO(buttons);
}
@Override
public List<MenuVO> tree() {
return ForestNodeMerger.merge(baseMapper.tree());
}
@Override
public List<MenuVO> grantTree(BladeUser user) {
return ForestNodeMerger.merge(user.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID) ? baseMapper.grantTree() : baseMapper.grantTreeByRole(Func.toLongList(user.getRoleId())));
}
@Override
public List<String> roleTreeKeys(String roleIds) {
List<RoleMenu> roleMenus = roleMenuService.list(Wrappers.<RoleMenu>query().lambda().in(RoleMenu::getRoleId, Func.toLongList(roleIds)));
return roleMenus.stream().map(roleMenu -> Func.toStr(roleMenu.getMenuId())).collect(Collectors.toList());
}
@Override
@Cacheable(cacheNames = MENU_CACHE, key = "'auth:routes:' + #user.roleId")
public List<Kv> authRoutes(BladeUser user) {
List<MenuDTO> routes = baseMapper.authRoutes(Func.toLongList(user.getRoleId()));
List<Kv> list = new ArrayList<>();
routes.forEach(route -> list.add(Kv.create().set(route.getPath(), Kv.create().set("authority", Func.toStrArray(route.getAlias())))));
return list;
}
@Override
public boolean removeMenu(String ids) {
Integer cnt = baseMapper.selectCount(Wrappers.<Menu>query().lambda().in(Menu::getParentId, Func.toLongList(ids)));
if (cnt > 0) {
throw new RuntimeException("请先删除子节点!");
}
return removeByIds(Func.toLongList(ids));
}
@Override
public boolean submit(Menu menu) {
LambdaQueryWrapper<Menu> menuQueryWrapper = Wrappers.lambdaQuery();
if (menu.getId() == null) {
menuQueryWrapper.eq(Menu::getCode, menu.getCode()).or(
wrapper -> wrapper.eq(Menu::getName, menu.getName()).eq(Menu::getCategory, MENU_CATEGORY)
);
} else {
menuQueryWrapper.ne(Menu::getId, menu.getId()).and(
wrapper -> wrapper.eq(Menu::getCode, menu.getCode()).or(
o -> o.eq(Menu::getName, menu.getName()).eq(Menu::getCategory, MENU_CATEGORY)
)
);
}
Integer cnt = baseMapper.selectCount(menuQueryWrapper);
if (cnt > 0) {
throw new RuntimeException("菜单名或编号已存在!");
}
if (menu.getParentId() == null && menu.getId() == null) {
menu.setParentId(BladeConstant.TOP_PARENT_ID);
}
if (menu.getParentId() != null && menu.getId() == null) {
Menu parentMenu = baseMapper.selectById(menu.getParentId());
if (parentMenu != null && parentMenu.getCategory() != 1) {
throw new RuntimeException("父节点只可选择菜单类型!");
}
}
menu.setIsDeleted(BladeConstant.DB_NOT_DELETED);
return saveOrUpdate(menu);
}
}

View File

@ -0,0 +1,17 @@
package org.springblade.auth.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springblade.auth.system.entity.RoleMenu;
import org.springblade.auth.system.mapper.RoleMenuMapper;
import org.springblade.auth.system.service.IRoleMenuService;
import org.springframework.stereotype.Service;
/**
* 服务实现类
*
* @author Chill
*/
@Service
public class RoleMenuServiceImpl extends ServiceImpl<RoleMenuMapper, RoleMenu> implements IRoleMenuService {
}

View File

@ -0,0 +1,152 @@
package org.springblade.auth.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springblade.auth.system.entity.Role;
import org.springblade.auth.system.entity.RoleMenu;
import org.springblade.auth.system.mapper.RoleMapper;
import org.springblade.auth.system.service.IRoleMenuService;
import org.springblade.auth.system.service.IRoleService;
import org.springblade.auth.system.vo.RoleVO;
import org.springblade.auth.system.wrapper.RoleWrapper;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.core.tool.utils.Func;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* 服务实现类
*
* @author Chill
*/
@Service
@Validated
@AllArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {
private final IRoleMenuService roleMenuService;
@Override
public IPage<RoleVO> selectRolePage(IPage<RoleVO> page, RoleVO role) {
return page.setRecords(baseMapper.selectRolePage(page, role));
}
@Override
public List<RoleVO> tree(String tenantId) {
String userRole = AuthUtil.getUserRole();
String excludeRole = null;
if (!CollectionUtil.contains(Func.toStrArray(userRole), RoleConstant.ADMIN) && !CollectionUtil.contains(Func.toStrArray(userRole), RoleConstant.ADMINISTRATOR)) {
excludeRole = RoleConstant.ADMINISTRATOR;
}
return ForestNodeMerger.merge(baseMapper.tree(tenantId, excludeRole));
}
private boolean grantRoleMenu(List<Long> roleIds, List<Long> menuIds) {
// 防止越权配置超管角色
int administratorCount = baseMapper.selectCount(Wrappers.<Role>query().lambda().eq(Role::getRoleAlias, RoleConstant.ADMINISTRATOR).in(Role::getId, roleIds));
if (!AuthUtil.isAdministrator() && administratorCount > 0) {
throw new RuntimeException("无权配置超管角色!");
}
// 防止越权配置管理员角色
//int adminCount = baseMapper.selectCount(Wrappers.<Role>query().lambda().eq(Role::getRoleAlias, RoleConstant.ADMIN).in(Role::getId, roleIds));
//if (!AuthUtil.isAdmin() && adminCount > 0) {
// throw new ServiceException("无权配置管理员角色!");
// }
// 删除角色配置的菜单集合
roleMenuService.remove(Wrappers.<RoleMenu>update().lambda().in(RoleMenu::getRoleId, roleIds));
// 组装配置
List<RoleMenu> roleMenus = new ArrayList<>();
roleIds.forEach(roleId -> menuIds.forEach(menuId -> {
RoleMenu roleMenu = new RoleMenu();
roleMenu.setRoleId(roleId);
roleMenu.setMenuId(menuId);
roleMenus.add(roleMenu);
}));
// 新增配置
roleMenuService.saveBatch(roleMenus);
// 递归设置下属角色菜单集合
recursionRoleMenu(roleIds, menuIds);
return true;
}
private void recursionRoleMenu(List<Long> roleIds, List<Long> menuIds) {
roleIds.forEach(roleId -> baseMapper.selectList(Wrappers.<Role>query().lambda().eq(Role::getParentId, roleId)).forEach(role -> {
List<RoleMenu> roleMenuList = roleMenuService.list(Wrappers.<RoleMenu>query().lambda().eq(RoleMenu::getRoleId, role.getId()));
// 子节点过滤出父节点删除的菜单集合
List<Long> collectRoleMenuIds = roleMenuList.stream().map(RoleMenu::getMenuId).filter(menuId -> !menuIds.contains(menuId)).collect(Collectors.toList());
if (collectRoleMenuIds.size() > 0) {
// 删除子节点权限外的菜单集合
roleMenuService.remove(Wrappers.<RoleMenu>update().lambda().eq(RoleMenu::getRoleId, role.getId()).in(RoleMenu::getMenuId, collectRoleMenuIds));
// 递归设置下属角色菜单集合
recursionRoleMenu(Collections.singletonList(role.getId()), menuIds);
}
}));
}
@Override
public String getRoleIds(String tenantId, String roleNames) {
List<Role> roleList = baseMapper.selectList(Wrappers.<Role>query().lambda().eq(Role::getTenantId, tenantId).in(Role::getRoleName, Func.toStrList(roleNames)));
if (roleList != null && roleList.size() > 0) {
return roleList.stream().map(role -> Func.toStr(role.getId())).distinct().collect(Collectors.joining(","));
}
return null;
}
@Override
public List<String> getRoleNames(String roleIds) {
return baseMapper.getRoleNames(Func.toLongArray(roleIds));
}
@Override
public List<String> getRoleAliases(String roleIds) {
return baseMapper.getRoleAliases(Func.toLongArray(roleIds));
}
@Override
public boolean submit(Role role) {
if (!AuthUtil.isAdministrator()) {
if (Func.toStr(role.getRoleAlias()).equals(RoleConstant.ADMINISTRATOR)) {
throw new RuntimeException("无权限创建超管角色!");
}
}
if (Func.isEmpty(role.getParentId())) {
role.setTenantId(AuthUtil.getTenantId());
role.setParentId(BladeConstant.TOP_PARENT_ID);
}
if (role.getParentId() > 0) {
Role parent = getById(role.getParentId());
if (Func.toLong(role.getParentId()) == Func.toLong(role.getId())) {
throw new RuntimeException("父节点不可选择自身!");
}
role.setTenantId(parent.getTenantId());
}
role.setIsDeleted(BladeConstant.DB_NOT_DELETED);
return saveOrUpdate(role);
}
@Override
public List<RoleVO> search(String roleName, Long parentId) {
LambdaQueryWrapper<Role> queryWrapper = Wrappers.<Role>query().lambda();
if (Func.isNotEmpty(roleName)) {
queryWrapper.like(Role::getRoleName, roleName);
}
if (Func.isNotEmpty(parentId) && parentId > 0L) {
queryWrapper.eq(Role::getParentId, parentId);
}
List<Role> roleList = baseMapper.selectList(queryWrapper);
return RoleWrapper.build().listNodeVO(roleList);
}
}

View File

@ -0,0 +1,159 @@
package org.springblade.auth.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springblade.auth.system.cache.SysCache;
import org.springblade.auth.system.entity.User;
import org.springblade.auth.system.entity.UserInfo;
import org.springblade.auth.system.mapper.UserMapper;
import org.springblade.auth.system.service.IRoleService;
import org.springblade.auth.system.service.IUserService;
import org.springblade.auth.system.vo.UserVO;
import org.springblade.auth.system.wrapper.UserWrapper;
import org.springblade.common.constant.CommonConstant;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tenant.BladeTenantProperties;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.DigestUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* 服务实现类
*
* @author Chill
*/
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implements IUserService {
@Override
@Transactional(rollbackFor = Exception.class)
public boolean submit(User user) {
if (StringUtil.isBlank(user.getTenantId())) {
user.setTenantId(BladeConstant.ADMIN_TENANT_ID);
}
if (Func.isNotEmpty(user.getPassword())) {
user.setPassword(DigestUtil.encrypt(user.getPassword()));
}
Integer userCount = baseMapper.selectCount(Wrappers.<User>query().lambda().eq(User::getTenantId, user.getTenantId()).eq(User::getAccount, user.getAccount()));
if (userCount > 0 && Func.isEmpty(user.getId())) {
throw new RuntimeException(StringUtil.format("当前用户 [{}] 已存在!", user.getAccount()));
}
return save(user);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateUser(User user) {
String tenantId = user.getTenantId();
Integer userCount = baseMapper.selectCount(
Wrappers.<User>query().lambda()
.eq(User::getTenantId, tenantId)
.eq(User::getAccount, user.getAccount())
.notIn(User::getId, user.getId())
);
if (userCount > 0) {
throw new RuntimeException(StringUtil.format("当前用户 [{}] 已存在!", user.getAccount()));
}
return updateUserInfo(user);
}
@Override
public boolean updateUserInfo(User user) {
user.setPassword(null);
return updateById(user);
}
@Override
public IPage<User> selectUserPage(IPage<User> page, User user, Long deptId, String tenantId) {
return page.setRecords(baseMapper.selectUserPage(page, user, null, tenantId));
}
@Override
public IPage<UserVO> selectUserSearch(UserVO user, Query query) {
LambdaQueryWrapper<User> queryWrapper = Wrappers.<User>query().lambda();
if (StringUtil.isNotBlank(user.getName())) {
queryWrapper.like(User::getName, user.getName());
}
IPage<User> pages = this.page(Condition.getPage(query), queryWrapper);
return UserWrapper.build().pageVO(pages);
}
@Override
public User userByAccount(String tenantId, String account) {
return baseMapper.selectOne(Wrappers.<User>query().lambda().eq(User::getTenantId, tenantId).eq(User::getAccount, account).eq(User::getIsDeleted, BladeConstant.DB_NOT_DELETED));
}
@Override
public UserInfo userInfo(Long userId) {
User user = baseMapper.selectById(userId);
return buildUserInfo(user);
}
@Override
public UserInfo userInfo(String tenantId, String account) {
User user = baseMapper.getUser(tenantId, account);
return buildUserInfo(user);
}
private UserInfo buildUserInfo(User user) {
UserInfo userInfo = new UserInfo();
userInfo.setUser(user);
if (Func.isNotEmpty(user)) {
userInfo.setRoles(SysCache.getRoleAliases(user.getRoleId()));
}
userInfo.setDetail(Kv.create().set("type", "web"));
return userInfo;
}
@Override
public boolean grant(String userIds, String roleIds) {
User user = new User();
user.setRoleId(roleIds);
return this.update(user, Wrappers.<User>update().lambda().in(User::getId, Func.toLongList(userIds)));
}
@Override
public boolean resetPassword(String userIds) {
User user = new User();
user.setPassword(DigestUtil.encrypt(CommonConstant.DEFAULT_PASSWORD));
user.setUpdateTime(DateUtil.now());
return this.update(user, Wrappers.<User>update().lambda().in(User::getId, Func.toLongList(userIds)));
}
@Override
public boolean updatePassword(Long userId, String oldPassword, String newPassword, String newPassword1) {
User user = getById(userId);
if (!newPassword.equals(newPassword1)) {
throw new RuntimeException("请输入正确的确认密码!");
}
if (!user.getPassword().equals(DigestUtil.hex(oldPassword))) {
throw new RuntimeException("原密码不正确!");
}
return this.update(Wrappers.<User>update().lambda().set(User::getPassword, DigestUtil.hex(newPassword)).eq(User::getId, userId));
}
@Override
public boolean removeUser(String userIds) {
if (Func.contains(Func.toLongArray(userIds), AuthUtil.getUserId())) {
throw new RuntimeException("不能删除本账号!");
}
return deleteLogic(Func.toLongList(userIds));
}
}

View File

@ -0,0 +1,55 @@
package org.springblade.auth.system.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tool.node.INode;
import org.springblade.auth.system.entity.DictBiz;
import java.util.ArrayList;
import java.util.List;
/**
* 视图实体类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "DictBizVO对象", description = "DictBizVO对象")
public class DictBizVO extends DictBiz implements INode<DictBizVO> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 父节点ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long parentId;
/**
* 子孙节点
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<DictBizVO> children;
@Override
public List<DictBizVO> getChildren() {
if (this.children == null) {
this.children = new ArrayList<>();
}
return this.children;
}
/**
* 上级字典
*/
private String parentName;
}

View File

@ -0,0 +1,62 @@
package org.springblade.auth.system.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tool.node.INode;
import org.springblade.auth.system.entity.Menu;
import java.util.ArrayList;
import java.util.List;
/**
* 视图实体类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "MenuVO对象", description = "MenuVO对象")
public class MenuVO extends Menu implements INode<MenuVO> {
private static final long serialVersionUID = 1L;
/**
* 子孙节点
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<MenuVO> children;
/**
* 是否有子孙节点
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Boolean hasChildren;
@Override
public List<MenuVO> getChildren() {
if (this.children == null) {
this.children = new ArrayList<>();
}
return this.children;
}
/**
* 上级菜单
*/
private String parentName;
/**
* 菜单类型
*/
private String categoryName;
/**
* 按钮功能
*/
private String actionName;
/**
* 是否新窗口打开
*/
private String isOpenName;
}

View File

@ -0,0 +1,19 @@
package org.springblade.auth.system.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.auth.system.entity.RoleMenu;
/**
* 视图实体类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "RoleMenuVO对象", description = "RoleMenuVO对象")
public class RoleMenuVO extends RoleMenu {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tool.node.INode;
import org.springblade.auth.system.entity.Role;
import java.util.ArrayList;
import java.util.List;
/**
* 视图实体类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "RoleVO对象", description = "RoleVO对象")
public class RoleVO extends Role implements INode<RoleVO> {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 父节点ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long parentId;
/**
* 子孙节点
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<RoleVO> children;
@Override
public List<RoleVO> getChildren() {
if (this.children == null) {
this.children = new ArrayList<>();
}
return this.children;
}
/**
* 上级角色
*/
private String parentName;
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.vo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.auth.system.entity.User;
/**
* 视图实体类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "UserVO对象", description = "UserVO对象")
public class UserVO extends User {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 密码
*/
@JsonIgnore
private String password;
/**
* 租户名
*/
private String tenantName;
/**
* 角色名
*/
private String roleName;
}

View File

@ -0,0 +1,45 @@
package org.springblade.auth.system.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.auth.system.cache.DictBizCache;
import org.springblade.auth.system.entity.DictBiz;
import org.springblade.auth.system.vo.DictBizVO;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 包装类,返回视图层所需的字段
*
* @author Chill
*/
public class DictBizWrapper extends BaseEntityWrapper<DictBiz, DictBizVO> {
public static DictBizWrapper build() {
return new DictBizWrapper();
}
@Override
public DictBizVO entityVO(DictBiz dict) {
DictBizVO dictVO = Objects.requireNonNull(BeanUtil.copy(dict, DictBizVO.class));
if (Func.equals(dict.getParentId(), BladeConstant.TOP_PARENT_ID)) {
dictVO.setParentName(BladeConstant.TOP_PARENT_NAME);
} else {
DictBiz parent = DictBizCache.getById(dict.getParentId());
dictVO.setParentName(parent.getDictValue());
}
return dictVO;
}
public List<DictBizVO> listNodeVO(List<DictBiz> list) {
List<DictBizVO> collect = list.stream().map(dict -> BeanUtil.copy(dict, DictBizVO.class)).collect(Collectors.toList());
return ForestNodeMerger.merge(collect);
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.system.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.auth.system.cache.SysCache;
import org.springblade.auth.system.entity.Menu;
import org.springblade.auth.system.vo.MenuVO;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 包装类,返回视图层所需的字段
*
* @author Chill
*/
public class MenuWrapper extends BaseEntityWrapper<Menu, MenuVO> {
public static MenuWrapper build() {
return new MenuWrapper();
}
@Override
public MenuVO entityVO(Menu menu) {
MenuVO menuVO = Objects.requireNonNull(BeanUtil.copy(menu, MenuVO.class));
if (Func.equals(menu.getParentId(), BladeConstant.TOP_PARENT_ID)) {
menuVO.setParentName(BladeConstant.TOP_PARENT_NAME);
} else {
Menu parent = SysCache.getMenu(menu.getParentId());
menuVO.setParentName(parent.getName());
}
return menuVO;
}
public List<MenuVO> listNodeVO(List<Menu> list) {
List<MenuVO> collect = list.stream().map(menu -> BeanUtil.copy(menu, MenuVO.class)).collect(Collectors.toList());
return ForestNodeMerger.merge(collect);
}
public List<MenuVO> listNodeLazyVO(List<MenuVO> list) {
return ForestNodeMerger.merge(list);
}
}

View File

@ -0,0 +1,45 @@
package org.springblade.auth.system.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.auth.system.cache.SysCache;
import org.springblade.auth.system.entity.Role;
import org.springblade.auth.system.vo.RoleVO;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 包装类,返回视图层所需的字段
*
* @author Chill
*/
public class RoleWrapper extends BaseEntityWrapper<Role, RoleVO> {
public static RoleWrapper build() {
return new RoleWrapper();
}
@Override
public RoleVO entityVO(Role role) {
RoleVO roleVO = Objects.requireNonNull(BeanUtil.copy(role, RoleVO.class));
if (Func.equals(role.getParentId(), BladeConstant.TOP_PARENT_ID)) {
roleVO.setParentName(BladeConstant.TOP_PARENT_NAME);
} else {
Role parent = SysCache.getRole(role.getParentId());
roleVO.setParentName(parent.getRoleName());
}
return roleVO;
}
public List<RoleVO> listNodeVO(List<Role> list) {
List<RoleVO> collect = list.stream().map(this::entityVO).collect(Collectors.toList());
return ForestNodeMerger.merge(collect);
}
}

View File

@ -0,0 +1,32 @@
package org.springblade.auth.system.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.auth.system.cache.SysCache;
import org.springblade.auth.system.entity.User;
import org.springblade.auth.system.vo.UserVO;
import java.util.List;
import java.util.Objects;
/**
* 包装类,返回视图层所需的字段
*
* @author Chill
*/
public class UserWrapper extends BaseEntityWrapper<User, UserVO> {
public static UserWrapper build() {
return new UserWrapper();
}
@Override
public UserVO entityVO(User user) {
UserVO userVO = Objects.requireNonNull(BeanUtil.copy(user, UserVO.class));
List<String> roleName = SysCache.getRoleNames(user.getRoleId());
userVO.setRoleName(Func.join(roleName));
return userVO;
}
}

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.auth.utils;
import lombok.SneakyThrows;
import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.tenant.BladeTenantProperties;
import org.springblade.core.tool.utils.Charsets;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import java.util.Base64;
import java.util.Calendar;
/**
* 认证工具类
*
* @author Chill
*/
public class TokenUtil {
public final static String AVATAR = TokenConstant.AVATAR;
public final static String ACCOUNT = TokenConstant.ACCOUNT;
public final static String USER_NAME = TokenConstant.USER_NAME;
public final static String NICK_NAME = TokenConstant.NICK_NAME;
public final static String REAL_NAME = TokenConstant.REAL_NAME;
public final static String USER_ID = TokenConstant.USER_ID;
public final static String DEPT_ID = TokenConstant.DEPT_ID;
public final static String POST_ID = TokenConstant.POST_ID;
public final static String ROLE_ID = TokenConstant.ROLE_ID;
public final static String ROLE_NAME = TokenConstant.ROLE_NAME;
public final static String TENANT_ID = TokenConstant.TENANT_ID;
public final static String OAUTH_ID = TokenConstant.OAUTH_ID;
public final static String CLIENT_ID = TokenConstant.CLIENT_ID;
public final static String DETAIL = TokenConstant.DETAIL;
public final static String EMAIL = "email";
public final static String DEPT_HEADER_KEY = "Dept-Id";
public final static String ROLE_HEADER_KEY = "Role-Id";
public final static String MOBILE_HEADER_KEY = "Mobile-Key";
public final static String MOBILE_HEADER_CODE = "Mobile-Code";
public final static String CAPTCHA_HEADER_KEY = "Captcha-Key";
public final static String CAPTCHA_HEADER_CODE = "Captcha-Code";
public final static String CAPTCHA_NOT_CORRECT = "验证码不正确";
public final static String TENANT_HEADER_KEY = "Tenant-Id";
public final static String TENANT_PARAM_KEY = "tenant_id";
public final static String DEFAULT_TENANT_ID = "000000";
public final static String TENANT_NOT_FOUND = "租户ID未找到";
public final static String USER_TYPE_HEADER_KEY = "User-Type";
public final static String DEFAULT_USER_TYPE = "web";
public final static String USER_NOT_FOUND = "用户名或密码错误";
public final static String USER_HAS_NO_ROLE = "未获得用户的角色信息";
public final static String USER_HAS_NO_TENANT = "未获得用户的租户信息";
public final static String USER_HAS_NO_TENANT_PERMISSION = "租户授权已过期,请联系管理员";
public final static String USER_HAS_TOO_MANY_FAILS = "登录错误次数过多,请稍后再试";
public final static String HEADER_KEY = "Authorization";
public final static String HEADER_PREFIX = "Basic ";
public final static String DEFAULT_AVATAR = "";
public final static String PASSWORD_KEY = "password";
public final static String GRANT_TYPE_KEY = "grant_type";
public final static String REFRESH_TOKEN_KEY = "refresh_token";
public final static String LICENSE_NAME = "KeNing";
private static BladeTenantProperties tenantProperties;
/**
* 获取租户配置
*
* @return tenantProperties
*/
private static BladeTenantProperties getTenantProperties() {
if (tenantProperties == null) {
tenantProperties = SpringUtil.getBean(BladeTenantProperties.class);
}
return tenantProperties;
}
/**
* 解码
*/
@SneakyThrows
public static String[] extractAndDecodeHeader() {
String header = WebUtil.getRequest().getHeader(TokenUtil.HEADER_KEY);
if (header == null || !header.startsWith(TokenUtil.HEADER_PREFIX)) {
throw new UnapprovedClientAuthenticationException("请求头中无client信息");
}
byte[] base64Token = header.substring(6).getBytes(Charsets.UTF_8_NAME);
byte[] decoded;
try {
decoded = Base64.getDecoder().decode(base64Token);
} catch (IllegalArgumentException var7) {
throw new BadCredentialsException("Failed to decode basic authentication token");
}
String token = new String(decoded, Charsets.UTF_8_NAME);
int index = token.indexOf(StringPool.COLON);
if (index == -1) {
throw new BadCredentialsException("Invalid basic authentication token");
} else {
return new String[]{token.substring(0, index), token.substring(index + 1)};
}
}
/**
* 获取请求头中的客户端id
*/
public static String getClientIdFromHeader() {
String[] tokens = extractAndDecodeHeader();
return tokens[0];
}
/**
* 获取token过期时间(次日凌晨3点)
*
* @return expire
*/
public static int getTokenValiditySecond() {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 1);
cal.set(Calendar.HOUR_OF_DAY, 3);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.MILLISECOND, 0);
return (int) (cal.getTimeInMillis() - System.currentTimeMillis()) / 1000;
}
/**
* 获取refreshToken过期时间
*
* @return expire
*/
public static int getRefreshTokenValiditySeconds() {
return 60 * 60 * 24 * 15;
}
}

View File

@ -0,0 +1,19 @@
#服务器端口
server:
port: 8100
#数据源配置
spring:
datasource:
url: ${blade.datasource.dev.url}
username: ${blade.datasource.dev.username}
password: ${blade.datasource.dev.password}
#第三方登陆
social:
enabled: true
domain: http://127.0.0.1:1888
mobile:
enabled: true

View File

@ -0,0 +1,18 @@
#服务器端口
server:
port: 8100
#数据源配置
spring:
datasource:
url: ${blade.datasource.prod.url}
username: ${blade.datasource.prod.username}
password: ${blade.datasource.prod.password}
#第三方登陆
social:
enabled: true
domain: http://127.0.0.1:1888
mobile:
enabled: true

View File

@ -0,0 +1,18 @@
#服务器端口
server:
port: 8100
#数据源配置
spring:
datasource:
url: ${blade.datasource.test.url}
username: ${blade.datasource.test.username}
password: ${blade.datasource.test.password}
#第三方登陆
social:
enabled: true
domain: http://127.0.0.1:1888
mobile:
enabled: true

View File

@ -0,0 +1,34 @@
# 在使用Spring默认数据源Hikari的情况下配置以下配置项
spring:
datasource:
hikari:
# 自动提交从池中返回的连接
auto-commit: true
# 连接池中维护的最小空闲连接数
minimum-idle: 10
# 连接池中允许的最大连接数。缺省值10推荐的公式((core_count * 2) + effective_spindle_count)
maximum-pool-size: 60
# 空闲连接超时时间默认值60000010分钟大于等于max-lifetime且max-lifetime>0会被重置为0不等于0且小于10秒会被重置为10秒。
# 只有空闲连接数大于最大连接数且空闲时间超过该值,才会被释放
idle-timeout: 30000
# 连接最大存活时间.不等于0且小于30秒会被重置为默认值30分钟.设置应该比mysql设置的超时时间短
max-lifetime: 1800000
# 等待连接池分配连接的最大时长毫秒超过这个时长还没可用的连接则发生SQLException 缺省:30秒
connection-timeout: 30000
# 连接测试查询
connection-test-query: select 1
#connection-test-query: select 1 from dual
#swagger文档
swagger:
base-packages:
- org.springblade
- org.springframework.security.oauth2.provider.endpoint
#第三方登陆
social:
oauth:
WECHAT_OPEN:
client-id: 233************
client-secret: 233************************************
redirect-uri: ${social.domain}/oauth/redirect/wechat

View File

@ -33,6 +33,7 @@
<module>kn-launcher</module>
<module>kn-service</module>
<module>kn-service-api</module>
<module>kn-sys-manager</module>
</modules>
<dependencyManagement>
@ -70,6 +71,11 @@
<artifactId>kn-launcher</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.kening.platform</groupId>
<artifactId>kn-common</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>