Commit 7e91925a by 袁伟铭

修改pom

parent 419dbaa0
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.zq</groupId> <groupId>com.zq</groupId>
<artifactId>common-utils</artifactId> <artifactId>civil-common-utils</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
</dependency> </dependency>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>common-utils</artifactId> <artifactId>civil-common-utils</artifactId>
<properties> <properties>
<http.client.version>4.5.12</http.client.version> <http.client.version>4.5.12</http.client.version>
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
<dependency> <dependency>
<groupId>com.github.pagehelper</groupId> <groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId> <artifactId>pagehelper</artifactId>
<version>5.2.0</version> <version>5.2.1</version>
</dependency> </dependency>
<!--spring boot 集成redis所需common-pool2--> <!--spring boot 集成redis所需common-pool2-->
......
package com.zq.common.config.mybatis; package com.zq.common.config.mybatis;
import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.github.pagehelper.PageInterceptor; import com.github.pagehelper.PageInterceptor;
...@@ -10,6 +9,10 @@ import org.springframework.context.annotation.Configuration; ...@@ -10,6 +9,10 @@ import org.springframework.context.annotation.Configuration;
import java.util.Properties; import java.util.Properties;
/**
* @author wilmiam
* @since 2021-08-09 15:59
*/
@Configuration @Configuration
public class MybatisConfig { public class MybatisConfig {
...@@ -24,18 +27,10 @@ public class MybatisConfig { ...@@ -24,18 +27,10 @@ public class MybatisConfig {
} }
/** /**
* 官方原话 * PageHelper分页插件
* MybatisPlus新的分页插件,一缓和二缓遵循mybatis的规则, *
* 需要设置 MybatisConfiguration#useDeprecatedExecutor = false * @return
* 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/ */
@SuppressWarnings(value = {"deprecation"})
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
// pagehelper分页插件
@Bean @Bean
public PageInterceptor pageInterceptor() { public PageInterceptor pageInterceptor() {
PageInterceptor pageInterceptor = new PageInterceptor(); PageInterceptor pageInterceptor = new PageInterceptor();
......
...@@ -16,6 +16,9 @@ portal.name: PORTAL-SERVER ...@@ -16,6 +16,9 @@ portal.name: PORTAL-SERVER
user.port: 9800 user.port: 9800
user.name: USER-SERVER user.name: USER-SERVER
resource.port: 9900
resource.name: RESOURCE-SERVER
gateway.port: 9888 gateway.port: 9888
gateway.name: GATEWAY-SERVER gateway.name: GATEWAY-SERVER
......
...@@ -16,6 +16,9 @@ portal.name: PORTAL-SERVER ...@@ -16,6 +16,9 @@ portal.name: PORTAL-SERVER
user.port: 9800 user.port: 9800
user.name: USER-SERVER user.name: USER-SERVER
resource.port: 9900
resource.name: RESOURCE-SERVER
gateway.port: 9888 gateway.port: 9888
gateway.name: GATEWAY-SERVER gateway.name: GATEWAY-SERVER
......
...@@ -19,6 +19,9 @@ user.name: USER-SERVER ...@@ -19,6 +19,9 @@ user.name: USER-SERVER
gateway.port: 9888 gateway.port: 9888
gateway.name: GATEWAY-SERVER gateway.name: GATEWAY-SERVER
resource.port: 9900
resource.name: RESOURCE-SERVER
redis.url: 127.0.0.1 redis.url: 127.0.0.1
redis.port: 6379 redis.port: 6379
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.zq</groupId> <groupId>com.zq</groupId>
<artifactId>common-utils</artifactId> <artifactId>civil-common-utils</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
<swagger.version>2.9.2</swagger.version> <swagger.version>2.9.2</swagger.version>
<alibaba.druid.version>1.1.22</alibaba.druid.version> <alibaba.druid.version>1.1.22</alibaba.druid.version>
<mybatis.plus.version>3.4.0</mybatis.plus.version> <mybatis.plus.version>3.4.3</mybatis.plus.version>
<pagehelper.version>5.2.0</pagehelper.version> <pagehelper.version>5.2.0</pagehelper.version>
<jjwt.version>0.9.1</jjwt.version> <jjwt.version>0.9.1</jjwt.version>
<fastjson.version>1.2.76</fastjson.version> <fastjson.version>1.2.76</fastjson.version>
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
<module>portal-server</module> <module>portal-server</module>
<module>sync-server</module> <module>sync-server</module>
<module>user-server</module> <module>user-server</module>
<module>resource-server</module>
</modules> </modules>
<profiles> <profiles>
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.zq</groupId> <groupId>com.zq</groupId>
<artifactId>common-utils</artifactId> <artifactId>civil-common-utils</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
......
<?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>resource-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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--Spring boot 安全框架-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 连接配置中心 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</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-test</artifactId>
<scope>test</scope>
</dependency>
<!--Spring devtools 热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
</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.resource;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author wilmiam
* @since 2021/8/9 14:46
*/
@MapperScan("com.zq.resource.dao")
@EnableDiscoveryClient
@SpringBootApplication(scanBasePackages = {"com.zq.resource", "com.zq.common.config"})
public class ResourceApplication {
public static void main(String[] args) {
SpringApplication.run(ResourceApplication.class, args);
}
}
/*
* 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.resource.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.resource.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.resource.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> apiSet = new HashSet<>();
//不使用注解的时候在这添加url放行
apiSet.add("/user/app/**");
anonymousUrls.put("API", apiSet);
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(anonymousUrls.get(RequestMethodEnum.ALL.getType()).toArray(new String[0])).permitAll()
// API接口放行
.antMatchers(anonymousUrls.get("API").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.resource.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.resource.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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
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.hasText(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.hasText(bearerToken) && bearerToken.startsWith(properties.getTokenStartWith())) {
// 去掉令牌前缀
return bearerToken.replace(properties.getTokenStartWith(), "");
} else {
log.debug("非法Token:{}", bearerToken);
}
return null;
}
}
package com.zq.resource.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;
}
}
server:
port: ${resource.port}
#配置数据源
spring:
application:
name: ${resource.name}
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: ${redis.url}
port: ${redis.port}
# password: ${redis.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.url}
username: ${jdbc.username}
password: ${jdbc.password}
driver-class-name: ${jdbc.driver-class-name}
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
filters: stat
stat:
merge-sql: true
log-slow-sql: true
slow-sql-millis: 2000
# mybatis plus 配置
mybatis-plus:
global-config:
db-config:
select-strategy: not_empty
update-strategy: not_empty
spring:
cloud:
config:
name: config
profile: @profiles.active@
discovery:
enabled: true
service-id: CONFIG-SERVER
uri: http://127.0.0.1:8300/
eureka:
client:
serviceUrl:
defaultZone: http://admin:123456@127.0.0.1:8800/eureka/
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.zq</groupId> <groupId>com.zq</groupId>
<artifactId>common-utils</artifactId> <artifactId>civil-common-utils</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
</dependency> </dependency>
<!--Spring boot Web容器--> <!--Spring boot Web容器-->
......
...@@ -2,9 +2,7 @@ package com.zq.sync.config; ...@@ -2,9 +2,7 @@ package com.zq.sync.config;
import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.zq</groupId> <groupId>com.zq</groupId>
<artifactId>common-utils</artifactId> <artifactId>civil-common-utils</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.zq</groupId> <groupId>com.zq</groupId>
<artifactId>common-utils</artifactId> <artifactId>civil-common-utils</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
......
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