Commit 3ecb3294 by 韦华德

更新

parent 6752714f
...@@ -44,7 +44,6 @@ ...@@ -44,7 +44,6 @@
<module>resource-server</module> <module>resource-server</module>
<module>open-server</module> <module>open-server</module>
<module>oauth-server</module> <module>oauth-server</module>
<module>single-server</module>
</modules> </modules>
<profiles> <profiles>
......
<?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">
<parent>
<artifactId>civil-bigdata</artifactId>
<groupId>com.zq</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>single-server</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.zq</groupId>
<artifactId>civil-common-utils</artifactId>
<version>1.0.0</version>
</dependency>
<!-- &lt;!&ndash; 注册中心 &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; 连接配置中心 &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-config</artifactId>-->
<!-- </dependency>-->
<!--Spring boot 测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Spring boot Web容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Spring boot 安全框架-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--Spring devtools 热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<!--Spring boot Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--Mybatis plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!--Mybatis plus多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<!-- druid数据源驱动 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${alibaba.druid.version}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- oracle8 -->
<dependency>
<groupId>org.oracle</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.1.0.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.oracle.database.nls/orai18n -->
<dependency>
<groupId>com.oracle.database.nls</groupId>
<artifactId>orai18n</artifactId>
<version>21.1.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<!-- 使用@profiles.active@需要添加以下内容 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<!--开启过滤,用指定的参数替换directory下的文件中的参数-->
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
\ No newline at end of file
package com.zq.single;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* @author wilmiam
* @since 2021/11/22 10:14
*/
@EnableScheduling
@MapperScan("com.zq.single.mapper")
// @EnableDiscoveryClient
@SpringBootApplication(scanBasePackages = {"com.zq.single", "com.zq.common.config"})
public class SingleApplication {
public static void main(String[] args) {
SpringApplication.run(SingleApplication.class, args);
}
}
package com.zq.single;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @author wilmiam
* @since 2021-07-29 11:32
*/
@Configuration
@EnableSwagger2
public class Swagger {
@Value("${spring.profiles.active}")
private String profile;
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("admin")
.enable(!"product".equals(profile)) //生产环境关闭
.select()
.apis(RequestHandlerSelectors.basePackage("com.zq.single.controller"))
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("后台接口文档")
.description("查看接口文档")
.build();
}
}
/*
* Copyright 2019-2020 Zheng Jie
*
* 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
*
* http://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 com.zq.single.config;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author Zheng Jie
*/
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
//当用户在没有授权的情况下访问受保护的REST资源时,将调用此方法发送403 Forbidden响应
response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
}
}
/*
* Copyright 2019-2020 Zheng Jie
*
* 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
*
* http://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 com.zq.single.config;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author Zheng Jie
*/
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
// 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException == null ? "Unauthorized" : authException.getMessage());
}
}
/*
* Copyright 2019-2020 Zheng Jie
*
* 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
*
* http://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 com.zq.single.config;
import com.zq.common.annotation.AnonymousAccess;
import com.zq.common.config.redis.RedisUtils;
import com.zq.common.config.security.SecurityProperties;
import com.zq.common.utils.RequestMethodEnum;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.util.*;
/**
* @author Zheng Jie
*/
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
private final TokenProvider tokenProvider;
private final JwtAuthenticationEntryPoint authenticationErrorHandler;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
private final ApplicationContext applicationContext;
private final SecurityProperties properties;
private final RedisUtils redisUtils;
@Bean
public GrantedAuthorityDefaults grantedAuthorityDefaults() {
// 去除 ROLE_ 前缀
return new GrantedAuthorityDefaults("");
}
@Bean
public PasswordEncoder passwordEncoder() {
// 密码加密方式
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// 搜寻匿名标记 url: @AnonymousAccess
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping");
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
// 获取匿名标记
Map<String, Set<String>> anonymousUrls = getAnonymousUrl(handlerMethodMap);
Set<String> allType = anonymousUrls.get(RequestMethodEnum.ALL.getType());
//不使用注解的时候在这添加url放行
allType.add("/single/**");
httpSecurity
// 禁用 CSRF
.csrf().disable()
// .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
// 授权异常
.exceptionHandling()
.authenticationEntryPoint(authenticationErrorHandler)
.accessDeniedHandler(jwtAccessDeniedHandler)
// 防止iframe 造成跨域
.and()
.headers()
.frameOptions()
.disable()
// 不创建会话
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 静态资源等等
.antMatchers(
HttpMethod.GET,
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/webSocket/**"
).permitAll()
// swagger 文档
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").permitAll()
// 文件
.antMatchers("/avatar/**").permitAll()
.antMatchers("/file/**").permitAll()
// 阿里巴巴 druid
.antMatchers("/druid/**").permitAll()
// 放行OPTIONS请求
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// 自定义匿名访问所有url放行:允许匿名和带Token访问,细腻化到每个 Request 类型
// GET
.antMatchers(HttpMethod.GET, anonymousUrls.get(RequestMethodEnum.GET.getType()).toArray(new String[0])).permitAll()
// POST
.antMatchers(HttpMethod.POST, anonymousUrls.get(RequestMethodEnum.POST.getType()).toArray(new String[0])).permitAll()
// PUT
.antMatchers(HttpMethod.PUT, anonymousUrls.get(RequestMethodEnum.PUT.getType()).toArray(new String[0])).permitAll()
// PATCH
.antMatchers(HttpMethod.PATCH, anonymousUrls.get(RequestMethodEnum.PATCH.getType()).toArray(new String[0])).permitAll()
// DELETE
.antMatchers(HttpMethod.DELETE, anonymousUrls.get(RequestMethodEnum.DELETE.getType()).toArray(new String[0])).permitAll()
// 所有类型的接口都放行
.antMatchers(allType.toArray(new String[0])).permitAll()
// 所有请求都需要认证
.anyRequest().authenticated()
.and().apply(securityConfigurerAdapter());
}
private TokenConfigurer securityConfigurerAdapter() {
return new TokenConfigurer(tokenProvider, properties, redisUtils);
}
private Map<String, Set<String>> getAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) {
Map<String, Set<String>> anonymousUrls = new HashMap<>(6);
Set<String> get = new HashSet<>();
Set<String> post = new HashSet<>();
Set<String> put = new HashSet<>();
Set<String> patch = new HashSet<>();
Set<String> delete = new HashSet<>();
Set<String> all = new HashSet<>();
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
HandlerMethod handlerMethod = infoEntry.getValue();
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
if (null != anonymousAccess) {
List<RequestMethod> requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods());
RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name());
switch (Objects.requireNonNull(request)) {
case GET:
get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case POST:
post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case PUT:
put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case PATCH:
patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case DELETE:
delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
default:
all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
}
}
}
anonymousUrls.put(RequestMethodEnum.GET.getType(), get);
anonymousUrls.put(RequestMethodEnum.POST.getType(), post);
anonymousUrls.put(RequestMethodEnum.PUT.getType(), put);
anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch);
anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete);
anonymousUrls.put(RequestMethodEnum.ALL.getType(), all);
return anonymousUrls;
}
}
/*
* Copyright 2019-2020 Zheng Jie
*
* 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
*
* http://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 com.zq.single.config;
import com.zq.common.config.redis.RedisUtils;
import com.zq.common.config.security.SecurityProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* @author /
*/
@RequiredArgsConstructor
public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private final TokenProvider tokenProvider;
private final SecurityProperties properties;
private final RedisUtils redisUtils;
@Override
public void configure(HttpSecurity http) {
TokenFilter customFilter = new TokenFilter(tokenProvider, properties, redisUtils);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}
/*
* Copyright 2019-2020 Zheng Jie
*
* 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
*
* http://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 com.zq.single.config;
import cn.hutool.core.util.StrUtil;
import com.zq.common.config.redis.RedisUtils;
import com.zq.common.config.security.SecurityProperties;
import com.zq.common.context.ContextUtils;
import com.zq.common.vo.OnlineUserDto;
import io.jsonwebtoken.ExpiredJwtException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Objects;
/**
* @author /
*/
public class TokenFilter extends GenericFilterBean {
private static final Logger log = LoggerFactory.getLogger(TokenFilter.class);
private final TokenProvider tokenProvider;
private final SecurityProperties properties;
private final RedisUtils redisUtils;
/**
* @param tokenProvider Token
* @param properties JWT
* @param redisUtils redis
*/
public TokenFilter(TokenProvider tokenProvider, SecurityProperties properties, RedisUtils redisUtils) {
this.properties = properties;
this.tokenProvider = tokenProvider;
this.redisUtils = redisUtils;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String token = resolveToken(httpServletRequest);
// 对于 Token 为空的不需要去查 Redis
if (StrUtil.isNotBlank(token)) {
OnlineUserDto onlineUserDto = null;
boolean cleanUserCache = false;
try {
onlineUserDto = redisUtils.getObj(properties.getOnlineKey() + token, OnlineUserDto.class);
} catch (ExpiredJwtException e) {
log.error(e.getMessage());
cleanUserCache = true;
} finally {
if (cleanUserCache || Objects.isNull(onlineUserDto)) {
// userCacheClean.cleanUserCache(String.valueOf(tokenProvider.getClaims(token).get(TokenProvider.AUTHORITIES_KEY)));
}
}
if (onlineUserDto != null && StringUtils.isNotBlank(token)) {
Authentication authentication = tokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
// Token 续期
tokenProvider.checkRenewal(token);
// 设置当前用户
ContextUtils.setAdminContext(onlineUserDto);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
/**
* 初步检测Token
*
* @param request /
* @return /
*/
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(properties.getHeader());
if (StringUtils.isBlank(bearerToken)) {
return null;
}
if (bearerToken.startsWith(properties.getTokenStartWith())) {
// 去掉令牌前缀
return bearerToken.replace(properties.getTokenStartWith(), "");
} else {
log.debug("非法Token:{}", bearerToken);
}
return null;
}
}
package com.zq.single.config;/*
* Copyright 2019-2020 Zheng Jie
*
* 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
*
* http://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.
*/
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.zq.common.config.redis.RedisUtils;
import com.zq.common.config.security.SecurityProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @author /
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class TokenProvider implements InitializingBean {
private final RedisUtils redisUtils;
private final SecurityProperties properties;
public static final String AUTHORITIES_KEY = "auth";
private static Key key;
private static SignatureAlgorithm signatureAlgorithm;
@Override
public void afterPropertiesSet() {
signatureAlgorithm = SignatureAlgorithm.HS512;
byte[] keyBytes = DatatypeConverter.parseBase64Binary(properties.getBase64Secret());
key = new SecretKeySpec(keyBytes, signatureAlgorithm.getJcaName());
}
public static String createToken(Authentication authentication) {
String authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
return Jwts.builder()
.setSubject(authentication.getName())
.claim(AUTHORITIES_KEY, authorities)
.signWith(signatureAlgorithm, key)
// 加入ID确保生成的 Token 都不一致
.setId(IdUtil.simpleUUID())
.compact();
}
public Claims getClaims(String token) {
return Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(properties.getBase64Secret()))
.parseClaimsJws(token)
.getBody();
}
public Authentication getAuthentication(String token) {
Claims claims = Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(properties.getBase64Secret()))
.parseClaimsJws(token)
.getBody();
// fix bug: 当前用户如果没有任何权限时,在输入用户名后,刷新验证码会抛IllegalArgumentException
Object authoritiesStr = claims.get(AUTHORITIES_KEY);
Collection<? extends GrantedAuthority> authorities =
ObjectUtil.isNotEmpty(authoritiesStr) ?
Arrays.stream(authoritiesStr.toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList()) : Collections.emptyList();
User principal = new User(claims.getSubject(), "******", authorities);
return new UsernamePasswordAuthenticationToken(principal, token, authorities);
}
/**
* @param token 需要检查的token
*/
public void checkRenewal(String token) {
// 判断是否续期token,计算token的过期时间
long time = redisUtils.getExpire(properties.getOnlineKey() + token) * 1000;
Date expireDate = DateUtil.offset(new Date(), DateField.MILLISECOND, (int) time);
// 判断当前时间与过期时间的时间差
long differ = expireDate.getTime() - System.currentTimeMillis();
// 如果在续期检查的范围内,则续期
if (differ <= properties.getDetect()) {
long renew = time + properties.getRenew();
redisUtils.expire(properties.getOnlineKey() + token, renew, TimeUnit.MILLISECONDS);
}
}
public String getToken(HttpServletRequest request) {
String bearerToken = request.getHeader(properties.getHeader());
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(properties.getTokenStartWith())) {
// 去掉令牌前缀
return bearerToken.replace(properties.getTokenStartWith(), "");
}
return null;
}
}
package com.zq.single.config;
import com.zq.single.config.interceptor.ApiInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@RequiredArgsConstructor
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
private final ApiInterceptor apiInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(apiInterceptor)
.addPathPatterns("/single/**")
.excludePathPatterns("/single/auth/login")
.excludePathPatterns("/single/user/login")
;
}
}
package com.zq.single.config.interceptor;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONUtil;
import com.zq.common.config.redis.BaseCacheKeys;
import com.zq.common.config.redis.RedisUtils;
import com.zq.common.config.security.SecurityProperties;
import com.zq.common.context.ContextUtils;
import com.zq.common.vo.ApiTokenVo;
import com.zq.common.vo.ResultVo;
import com.zq.single.vo.UserInfoVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
@Component
@RequiredArgsConstructor
public class ApiInterceptor implements HandlerInterceptor {
private final RedisUtils redisUtils;
private final SecurityProperties properties;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String ip = ServletUtil.getClientIP(request);
log.debug("{}请求URI: {}", ip, request.getRequestURL());
String token = request.getHeader(properties.getHeader());
if (StringUtils.isNotBlank(token)) {
token= token.replace(properties.getTokenStartWith(), "");
}
UserInfoVo tokenVo = (UserInfoVo) redisUtils.getObj(BaseCacheKeys.appTokenKey(token), ApiTokenVo.class);
if (tokenVo == null) {
response.setStatus(HttpStatus.HTTP_UNAUTHORIZED);
ServletUtil.write(response, JSONUtil.toJsonStr(ResultVo.fail(401, "Unauthorized")), ContentType.JSON.getValue());
return false;
}
ContextUtils.setUserContext(tokenVo);
return true;
}
}
package com.zq.single.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zq.common.annotation.AnonymousAccess;
import com.zq.common.config.redis.BaseCacheKeys;
import com.zq.common.config.redis.RedisUtils;
import com.zq.common.config.security.ApiTokenUtils;
import com.zq.common.config.security.SecurityProperties;
import com.zq.common.vo.ApiTokenVo;
import com.zq.common.vo.ResultVo;
import com.zq.single.entity.CasSystem;
import com.zq.single.entity.CasUserInfo;
import com.zq.single.entity.SysUser;
import com.zq.single.service.ICasSystemService;
import com.zq.single.service.ICasUserInfoService;
import com.zq.single.service.ISysUserService;
import com.zq.single.vo.UserInfoVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 前端控制器
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@Api(tags = "登录认证相关接口")
@RequiredArgsConstructor
@RestController
@RequestMapping(value = "/single/auth")
public class AuthController {
private final ISysUserService iSysUserService;
private final ICasSystemService iCasSystemService;
private final ICasUserInfoService iCasUserInfoService;
private final RedisUtils redisUtils;
private final SecurityProperties properties;
@RequestMapping("/login")
@AnonymousAccess
public ResultVo login(@RequestBody SysUser sysUser, HttpServletRequest request, HttpServletResponse response) throws IOException {
LambdaQueryWrapper<SysUser> sysUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
sysUserLambdaQueryWrapper.eq(SysUser::getUsername, sysUser.getUsername());
List<SysUser> users = iSysUserService.list(sysUserLambdaQueryWrapper);
// AssertUtils.isTrue(users != null && users.size() > 0 && users.get(0).getPassword().equals(sysUser.getPassword()), "用户名或密码错误");
SysUser thisUser = users.get(0);
//业务系统Id
String systemId = request.getParameter("systemId");
String serverDomain = "";
if (StrUtil.isNotBlank(systemId)) {
CasSystem byId = iCasSystemService.getById(Long.parseLong(systemId));
if (byId != null) {
serverDomain = byId.getSystemInfo();
}
}
//查出该用户绑定业务系统的信息
LambdaQueryWrapper<CasUserInfo> casUserInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
casUserInfoLambdaQueryWrapper.eq(CasUserInfo::getUserId, thisUser.getUserId());
List<CasUserInfo> infoList = iCasUserInfoService.list(casUserInfoLambdaQueryWrapper);
UserInfoVo userToken = new UserInfoVo();
userToken.setUserId(thisUser.getUserId());
userToken.setUsername(thisUser.getUsername());
List<Map<String, String>> sonInfoList = new ArrayList<>();
for (CasUserInfo casUserInfo : infoList) {
Map<String, String> map = new HashMap<>();
map.put("systemName", casUserInfo.getSystemName());
map.put("systemUserId", casUserInfo.getSystemUserId().toString());
map.put("systemUserName", casUserInfo.getSystemUserName());
sonInfoList.add(map);
}
userToken.setSonInfoList(sonInfoList);
/* ApiTokenVo tokenVo = ApiTokenVo.builder()
.userId(thisUser.getUserId())
.build();*/
String token = ApiTokenUtils.createToken(userToken, BaseCacheKeys.APP_TOKEN_EXPIRE_MINUTES);
response.setHeader(properties.getHeader(), token);
redisUtils.setObj(BaseCacheKeys.appTokenKey(token), userToken, BaseCacheKeys.APP_TOKEN_EXPIRE_MINUTES);
/* String redirectUrl = "http://192.168.11.103:8080/#/login?" + properties.getHeader() + "=" + token + "&JSESSIONID=" + request.getSession().getId();
// response.sendRedirect("" + "/#/verifyLogin?" + properties.getHeader() + "=" + token + "&JSESSIONID=" + request.getSession().getId());
response.sendRedirect("http://192.168.11.103:8080/#/manage?" + properties.getHeader() + "=" + token + "&JSESSIONID=" + request.getSession().getId());*/
return ResultVo.success();
}
@ApiOperation("获取用户信息")
@GetMapping(value = "/info")
public ResultVo<Object> getUserInfo(HttpServletRequest request) {
String token = request.getHeader(properties.getHeader());
if (StringUtils.isNotBlank(token)) {
token= token.replace(properties.getTokenStartWith(), "");
}
Object obj = redisUtils.getObj(BaseCacheKeys.appTokenKey(token));
return ResultVo.success(obj);
}
}
package com.zq.single.controller;
import cn.hutool.core.util.IdcardUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zq.common.annotation.AnonymousAccess;
import com.zq.common.config.redis.BaseCacheKeys;
import com.zq.common.config.redis.RedisUtils;
import com.zq.common.config.security.ApiTokenUtils;
import com.zq.common.config.security.SecurityProperties;
import com.zq.common.context.ContextUtils;
import com.zq.common.utils.AssertUtils;
import com.zq.common.vo.OnlineUserDto;
import com.zq.common.vo.ResultVo;
import com.zq.single.entity.CasUserInfo;
import com.zq.single.entity.SysUser;
import com.zq.single.service.ISysUserService;
import com.zq.single.vo.CasUserInfoVo;
import com.zq.single.vo.UserInfoVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 系统用户 前端控制器
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@Api(value = "SysUserController", tags = "账号管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/single/user")
public class SysUserController {
@Autowired
private ISysUserService sysUserService;
private final RedisUtils redisUtils;
private final SecurityProperties properties;
@ApiOperation("注册查用户名是否已存在")
@AnonymousAccess
@GetMapping("/userNameIsExist/{userName}")
public ResultVo userNameIsExist(@PathVariable("userName") String userName) {
Boolean isSuccess = sysUserService.userNameIsExist(userName);
AssertUtils.isTrue(isSuccess, "用户名已存在");
return ResultVo.success();
}
@ApiOperation("注册用户")
@AnonymousAccess
@PostMapping("/register")
public ResultVo register(@RequestBody SysUser sysUser) {
/*String password= MD5PasswordEncoderUtil.encode(sysUser.getPassword());
sysUser.setPassword(password.trim());*/
Boolean isSuccess = sysUserService.save(sysUser);
AssertUtils.isTrue(isSuccess, "服务器繁忙请稍后再试");
return ResultVo.success();
}
@ApiOperation("更改用户信息")
@PostMapping("/update")
public ResultVo update(@RequestBody SysUser sysUser) {
/* String password= MD5PasswordEncoderUtil.encode(sysUser.getPassword().trim());
sysUser.setPassword(password);*/
Boolean isSuccess = sysUserService.updateById(sysUser);
AssertUtils.isTrue(isSuccess, "服务器繁忙请稍后再试");
return ResultVo.success();
}
@ApiOperation("删除用户信息")
@PostMapping("/delete/{userId}")
public ResultVo delete(@PathVariable("userId") Long userId) {
SysUser sysUser=new SysUser();
sysUser.setUserId(userId);
sysUser.setEnabled(0L);
Boolean isSuccess = sysUserService.updateById(sysUser);
AssertUtils.isTrue(isSuccess, "服务器繁忙请稍后再试");
return ResultVo.success();
}
@ApiOperation("用户详情")
@GetMapping("/detail/{userName}")
public ResultVo detail(@PathVariable("userName") String userName) {
LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
List<SysUser> list = sysUserService.list(lambdaQueryWrapper.eq(SysUser::getUsername, userName));
AssertUtils.isTrue(list.size() > 0, "服务器繁忙请稍后再试");
return ResultVo.success(list.get(0));
}
@ApiOperation("登录管理系统")
@AnonymousAccess
@PostMapping("/login")
public ResultVo login(@RequestBody SysUser sysUser, HttpServletResponse response) {
LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
List<SysUser> list = sysUserService.list(lambdaQueryWrapper.eq(SysUser::getUsername, sysUser.getUsername()));
AssertUtils.isTrue(list.size() > 0, "用户名或密码错误");
SysUser thisUser=list.get(0);
String password = thisUser.getPassword().trim();
AssertUtils.isTrue(password.equals(sysUser.getPassword()), "用户名或密码错误");
UserInfoVo userToken = new UserInfoVo();
userToken.setUserId(thisUser.getUserId());
userToken.setUsername(thisUser.getUsername());
userToken.setIsAdmin(thisUser.getIsAdmin());
String token = ApiTokenUtils.createToken(userToken, BaseCacheKeys.APP_TOKEN_EXPIRE_MINUTES);
response.setHeader(properties.getHeader(), token);
redisUtils.setObj(BaseCacheKeys.appTokenKey(token), userToken, BaseCacheKeys.APP_TOKEN_EXPIRE_MINUTES);
return ResultVo.success(token);
}
@ApiOperation("单点登录用户绑定业务系统用户")
@PostMapping("/blind")
public ResultVo blind(@RequestBody CasUserInfoVo vo) {
int blind = sysUserService.blind(vo);
AssertUtils.isTrue(blind > 0, "服务器繁忙请稍后再试");
return ResultVo.success();
}
@ApiOperation("单点登录用户管理列表")
@PostMapping("/manageList")
public ResultVo manageList(@RequestBody SysUser sysUser) {
LambdaQueryWrapper<SysUser> lambdaQueryWrapper=new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(SysUser::getUsername,sysUser.getUsername());
List<SysUser> users=sysUserService.list(lambdaQueryWrapper);
AssertUtils.isTrue(users!=null && users.size()>0, "服务器繁忙请稍后再试");
SysUser thisUser=users.get(0);
if(!thisUser.getIsAdmin()){
return ResultVo.fail("不是管理员");
}
List<SysUser> userList=sysUserService.list();
return ResultVo.success(userList);
}
}
package com.zq.single.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value = "CasSystem对象", description = "")
public class CasSystem implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
@ApiModelProperty(value = "业务系统表名")
private String systemName;
@ApiModelProperty(value = "业务系统信息")
private String systemInfo;
}
package com.zq.single.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value = "CasUserInfo对象", description = "")
public class CasUserInfo implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
@ApiModelProperty(value = "单点登录用户id")
private Long userId;
@ApiModelProperty(value = "绑定系统id")
private Long systemId;
@ApiModelProperty(value = "绑定系统名")
private String systemName;
@ApiModelProperty(value = "绑定系统用户id")
private Long systemUserId;
@ApiModelProperty(value = "绑定系统用户名")
private String systemUserName;
}
package com.zq.single.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 系统用户
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value = "SysUser对象", description = "系统用户")
public class SysUser implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "ID")
@TableId(value = "user_id", type = IdType.AUTO)
private Long userId;
@ApiModelProperty(value = "部门名称")
private Long deptId;
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "昵称")
private String nickName;
@ApiModelProperty(value = "性别")
private String gender;
@ApiModelProperty(value = "手机号码")
private String phone;
@ApiModelProperty(value = "邮箱")
private String email;
@ApiModelProperty(value = "头像地址")
private String avatarName;
@ApiModelProperty(value = "头像真实路径")
private String avatarPath;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "是否为admin账号")
private Boolean isAdmin;
@ApiModelProperty(value = "状态:1启用、0禁用")
private Long enabled;
@ApiModelProperty(value = "创建者")
private String createBy;
@ApiModelProperty(value = "更新着")
private String updateBy;
@ApiModelProperty(value = "修改密码的时间")
private LocalDateTime pwdResetTime;
@ApiModelProperty(value = "创建日期")
private LocalDateTime createTime;
@ApiModelProperty(value = "更新时间")
private LocalDateTime updateTime;
}
package com.zq.single.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zq.single.entity.CasSystem;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
/**
* <p>
* Mapper 接口
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@Mapper
@Repository
public interface CasSystemMapper extends BaseMapper<CasSystem> {
}
package com.zq.single.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zq.single.entity.CasUserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
/**
* <p>
* Mapper 接口
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@Mapper
@Repository
public interface CasUserInfoMapper extends BaseMapper<CasUserInfo> {
}
package com.zq.single.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zq.single.entity.SysUser;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
/**
* <p>
* 系统用户 Mapper 接口
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@Mapper
@Repository
public interface SysUserMapper extends BaseMapper<SysUser> {
}
package com.zq.single.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zq.single.entity.CasSystem;
/**
* <p>
* 服务类
* </p>
*
* @author Bill
* @since 2021-11-18
*/
public interface ICasSystemService extends IService<CasSystem> {
}
package com.zq.single.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zq.single.entity.CasUserInfo;
import com.zq.single.vo.CasUserInfoVo;
/**
* <p>
* 服务类
* </p>
*
* @author Bill
* @since 2021-11-18
*/
public interface ICasUserInfoService extends IService<CasUserInfo> {
int blind(CasUserInfoVo vo);
}
package com.zq.single.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zq.single.entity.SysUser;
import com.zq.single.vo.CasUserInfoVo;
/**
* <p>
* 系统用户 服务类
* </p>
*
* @author Bill
* @since 2021-11-18
*/
public interface ISysUserService extends IService<SysUser> {
Boolean userNameIsExist(String userName);
int blind(CasUserInfoVo vo);
}
package com.zq.single.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zq.single.entity.CasSystem;
import com.zq.single.mapper.CasSystemMapper;
import com.zq.single.service.ICasSystemService;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@Service
public class CasSystemServiceImpl extends ServiceImpl<CasSystemMapper, CasSystem> implements ICasSystemService {
}
package com.zq.single.service.impl;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zq.common.utils.AssertUtils;
import com.zq.common.vo.ResultVo;
import com.zq.single.entity.CasUserInfo;
import com.zq.single.mapper.CasUserInfoMapper;
import com.zq.single.service.ICasUserInfoService;
import com.zq.single.vo.CasUserInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* 服务实现类
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@Service
public class CasUserInfoServiceImpl extends ServiceImpl<CasUserInfoMapper, CasUserInfo> implements ICasUserInfoService {
@Autowired
private CasUserInfoMapper casUserInfoMapper;
RestTemplate restTemplate = new RestTemplate();
String sysServer = "http://127.0.0.1:9888/admin";
public int blind(CasUserInfoVo vo) {
Map<String, Object> params = new HashMap<>();
params.put("username", vo.getSystemUserName());
String s = SecureUtil.md5(vo.getSystemPassword());
System.out.println(s);
params.put("password", SecureUtil.md5(vo.getSystemPassword().trim()));
ResultVo resultVo = restTemplate.postForObject(sysServer + "/oauth/blindTest", params, ResultVo.class);
AssertUtils.isTrue(resultVo.isSuccess(), "绑定失败");
CasUserInfo info = new CasUserInfo();
info.setSystemId(vo.getSystemId());
info.setSystemId(vo.getSystemId());
info.setSystemUserId(vo.getSystemUserId());
info.setSystemUserName(vo.getSystemUserName());
return casUserInfoMapper.insert(info);
}
}
package com.zq.single.service.impl;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zq.common.utils.AssertUtils;
import com.zq.common.vo.ResultVo;
import com.zq.single.entity.CasUserInfo;
import com.zq.single.entity.SysUser;
import com.zq.single.mapper.CasUserInfoMapper;
import com.zq.single.mapper.SysUserMapper;
import com.zq.single.service.ISysUserService;
import com.zq.single.vo.CasUserInfoVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* 系统用户 服务实现类
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
private final SysUserMapper sysUserMapper;
private final CasUserInfoMapper casUserInfoMapper;
private RestTemplate restTemplate = new RestTemplate();
private String sysServer = "http://127.0.0.1:9888/admin";
@Override
public Boolean userNameIsExist(String userName) {
LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
Integer count = sysUserMapper.selectCount(lambdaQueryWrapper.eq(SysUser::getUsername, userName));
if (count > 0) {
return false;
} else {
return true;
}
}
@Override
public int blind(CasUserInfoVo vo) {
Map<String, Object> params = new HashMap<>();
params.put("username", vo.getSystemUserName());
String s = SecureUtil.md5(vo.getSystemPassword());
System.out.println(s);
params.put("password", SecureUtil.md5(vo.getSystemPassword().trim()));
ResultVo resultVo = restTemplate.postForObject(sysServer + "/oauth/blindTest", params, ResultVo.class);
AssertUtils.isTrue(resultVo.isSuccess(), "绑定失败");
CasUserInfo info = new CasUserInfo();
info.setSystemId(vo.getSystemId());
info.setSystemId(vo.getSystemId());
info.setSystemUserId(vo.getSystemUserId());
info.setSystemUserName(vo.getSystemUserName());
return casUserInfoMapper.insert(info);
}
}
package com.zq.single.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* <p>
*
* </p>
*
* @author Bill
* @since 2021-11-18
*/
@ApiModel(description = "绑定用户Vo")
@Data
public class CasUserInfoVo {
private Long id;
@ApiModelProperty(value = "单点登录用户id")
private Long userId;
@ApiModelProperty(value = "绑定系统id")
private Long systemId;
@ApiModelProperty(value = "绑定系统用户id")
private Long systemUserId;
@ApiModelProperty(value = "绑定系统用户名")
private String systemUserName;
@ApiModelProperty(value = "绑定系统用户密码")
private String systemPassword;
}
package com.zq.single.vo;
import com.zq.common.vo.ApiTokenVo;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* @author wilmiam
* @since 2021/11/22 11:46
*/
@Data
public class UserInfoVo extends ApiTokenVo {
private Boolean isAdmin;
private List<Map<String,String>> sonInfoList;
}
server:
port: 9878
#配置数据源
spring:
profiles:
active: @profiles.active@
application:
name: SINGLE-SERVER
servlet:
#上传文件限制
multipart:
#单个文件大小
max-file-size: 20MB
#设置总上传的数据大小
max-request-size: 50MB
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
redis:
#数据库索引
database: 0
host: 127.0.0.1
port: 6379
password:
#连接超时时间
timeout: 5000
datasource:
dynamic: # mybatis plus多数据源插件
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
master:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://47.107.148.253:3306/cloud?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: Dk2019!23456
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
# 初始连接数
initial-size: 10
# 最小连接数
min-idle: 20
# 最大连接数
max-active: 50
# 获取连接超时时间
max-wait: 5000
# 连接有效性检测时间
time-between-eviction-runs-millis: 60000
# 连接在池中最小生存的时间
min-evictable-idle-time-millis: 300000
# 连接在池中最大生存的时间
max-evictable-idle-time-millis: 900000
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 检测连接是否有效
validation-query: SELECT 1 FROM DUAL
filters: stat
stat:
merge-sql: true
log-slow-sql: true
slow-sql-millis: 2000
# mybatis plus 配置
mybatis-plus:
configuration:
#打印sql,生产环境可已去掉
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
select-strategy: not_empty
update-strategy: not_empty
mapper-locations: classpath:/mapper/**.xml
#jwt
jwt:
header: Authorization
# 令牌前缀
token-start-with: Bearer
# 必须使用最少88位的Base64对该令牌进行编码
base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=
# 令牌过期时间 此处单位/毫秒 ,默认2小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html
token-validity-in-seconds: 7200000
# 在线用户key
online-key: online-token-
# 验证码
code-key: code-key-
# token 续期检查时间范围(默认30分钟,单位默认毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期
detect: 1800000
# 续期时间范围,默认 1小时,这里单位毫秒
renew: 3600000
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment