Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

target/
target/

.idea/**

~/maven_repository/**

.vscode/**
63 changes: 37 additions & 26 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<version>3.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zzw</groupId>
Expand All @@ -14,11 +14,10 @@
<name>chatserver</name>
<description>chatserver</description>
<properties>
<java.version>1.8</java.version>
<swagger.version>2.7.0</swagger.version>
<fastjson.version>1.2.28</fastjson.version>
<socketio.version>1.7.11</socketio.version>
<servlet.version>4.0.1</servlet.version>
<java.version>21</java.version>
<fastjson.version>1.2.83</fastjson.version>
<socketio.version>2.0.3</socketio.version>
<jjwt.version>0.12.3</jjwt.version>
</properties>
<dependencies>
<dependency>
Expand All @@ -44,17 +43,11 @@
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<!--swagger-->
<!-- springdoc-openapi for Spring Boot 3 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<!--swagger ui-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -70,24 +63,31 @@
<artifactId>netty-socketio</artifactId>
<version>${socketio.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
<!-- JJWT upgraded -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -97,13 +97,24 @@
<groupId>net.oschina.zcx7878</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27.0.0</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
<version>2.15.1</version>
</dependency>
<!-- For Java 9+ compatibility if needed for fastdfs or others -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>

</dependencies>
<build>
<plugins>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/zzw/chatserver/aspect/SysLogAspect.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/zzw/chatserver/auth/UnAuthEntryPoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

//未认证时执行这个类
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/zzw/chatserver/common/CommonAdvice.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;

@ControllerAdvice
@RestController
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/com/zzw/chatserver/common/R.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.zzw.chatserver.common;

import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.util.HashMap;
Expand All @@ -10,16 +10,16 @@
@Data
public class R {

@ApiModelProperty(value = "是否成功")
@Schema(description = "是否成功")
private Boolean success;

@ApiModelProperty(value = "返回码")
@Schema(description = "返回码")
private Integer code;

@ApiModelProperty(value = "返回消息")
@Schema(description = "返回消息")
private String message;

@ApiModelProperty(value = "返回数据")
@Schema(description = "返回数据")
private Map<String, Object> data = new HashMap<>();

//把构造方法私有
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/com/zzw/chatserver/config/AsyncConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.zzw.chatserver.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

private static final Logger logger = LoggerFactory.getLogger(AsyncConfig.class);

@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10); // 核心线程数
executor.setMaxPoolSize(50); // 最大线程数
executor.setQueueCapacity(100); // 队列容量
executor.setThreadNamePrefix("AsyncExecutor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
executor.initialize();
return executor;
}

@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
logger.error("异步任务执行异常: 方法={}, 参数={}", method.getName(), params, ex);
}
};
}
}
23 changes: 11 additions & 12 deletions src/main/java/com/zzw/chatserver/config/CorsConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,24 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;

import java.util.Arrays;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
//解决跨域
@Bean
public CorsWebFilter corsWebFilter() {
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Arrays.asList("http://localhost:3000", "http://localhost:4000"));
// 允许所有域名进行跨域调用
config.addAllowedOriginPattern("*");
// 允许跨越发送cookie
config.setAllowCredentials(true);
config.addAllowedMethod("*");
// 放行全部原始头信息
config.addAllowedHeader("*");
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
// 允许所有请求方法跨域调用
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
return new CorsFilter(source);
}
}
76 changes: 43 additions & 33 deletions src/main/java/com/zzw/chatserver/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,31 @@
import com.zzw.chatserver.filter.KaptchaFilter;
import com.zzw.chatserver.handler.ChatLogoutSuccessHandler;
import com.zzw.chatserver.service.OnlineUserService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@EnableMethodSecurity
public class SecurityConfig {

@Autowired
@Qualifier("userDetailsServiceImpl")
Expand All @@ -49,37 +51,45 @@ public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}

//加载 userDetailsService,用于从数据库中取用户信息
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}

//不进行认证的路径,可以直接访问
@Override
public void configure(WebSecurity web) throws Exception {
//巨坑,这里不能加上context-path:/chat,不然不能拦截
web.ignoring().antMatchers("/user/getCode", "/sys/getFaceImages", "/user/register", "/sys/downloadFile",
"/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/superuser/login"
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers(
"/user/getCode",
"/sys/getFaceImages",
"/user/register",
"/sys/downloadFile",
"/swagger-resources/**",
"/webjars/**",
"/v2/**",
"/swagger-ui.html/**",
"/swagger-ui/**",
"/v3/api-docs/**",
"/superuser/login"
);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
// 开启跨域资源共享
http.cors()
.and().csrf().disable() // 关闭csrf
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) //关闭session(无状态)
.and().authorizeRequests() //设置认证请求
.antMatchers("/expression/**", "/face/**", "/img/**", "/uploads/**").permitAll() //放行静态资源
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
http
.cors(Customizer.withDefaults())
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/expression/**", "/face/**", "/img/**", "/uploads/**").permitAll()
.anyRequest().authenticated()
.and().logout().logoutSuccessHandler(new ChatLogoutSuccessHandler()).and()
// 添加到过滤链中,放在验证用户密码之前
.addFilterBefore(new KaptchaFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class)
// 先是UsernamePasswordAuthenticationFilter用于login校验
.addFilter(new JwtLoginAuthFilter(authenticationManager(), mongoTemplate, onlineUserService))
// 再通过OncePerRequestFilter,对其它请求过滤
.addFilter(new JwtPreAuthFilter(authenticationManager(), onlineUserService))
.httpBasic().authenticationEntryPoint(new UnAuthEntryPoint()); //没有权限访问
)
.logout(logout -> logout.logoutSuccessHandler(new ChatLogoutSuccessHandler()))
.addFilterBefore(new KaptchaFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class)
.addFilter(new JwtLoginAuthFilter(authenticationManager, mongoTemplate, onlineUserService))
.addFilter(new JwtPreAuthFilter(authenticationManager, onlineUserService))
.httpBasic(basic -> basic.authenticationEntryPoint(new UnAuthEntryPoint()));

return http.build();
}
}
Loading