From 6841e2f32eb9b551b4d48fd33a56bab787921959 Mon Sep 17 00:00:00 2001 From: wu <303054730@qq.com> Date: Wed, 4 Dec 2024 08:18:11 +0800 Subject: [PATCH] add --- .../java/com/lk/paopao/conf/CorsConfig.java | 42 ++++++++ .../lk/paopao/controller/AuthController.java | 44 +++++++++ .../lk/paopao/controller/UserController.java | 31 ++++++ src/main/java/com/lk/paopao/entity/User.java | 95 +++++++++++++++++++ .../java/com/lk/paopao/jwt/JwtConfig.java | 36 +++++++ .../java/com/lk/paopao/jwt/JwtFilter.java | 69 ++++++++++++++ .../java/com/lk/paopao/jwt/JwtService.java | 87 +++++++++++++++++ .../lk/paopao/repository/UserRepository.java | 10 ++ .../com/lk/paopao/service/AuthService.java | 39 ++++++++ .../com/lk/paopao/service/UserService.java | 16 ++++ src/main/resources/application.yml | 25 +++++ 11 files changed, 494 insertions(+) create mode 100644 src/main/java/com/lk/paopao/conf/CorsConfig.java create mode 100644 src/main/java/com/lk/paopao/controller/AuthController.java create mode 100644 src/main/java/com/lk/paopao/controller/UserController.java create mode 100644 src/main/java/com/lk/paopao/entity/User.java create mode 100644 src/main/java/com/lk/paopao/jwt/JwtConfig.java create mode 100644 src/main/java/com/lk/paopao/jwt/JwtFilter.java create mode 100644 src/main/java/com/lk/paopao/jwt/JwtService.java create mode 100644 src/main/java/com/lk/paopao/repository/UserRepository.java create mode 100644 src/main/java/com/lk/paopao/service/AuthService.java create mode 100644 src/main/java/com/lk/paopao/service/UserService.java create mode 100644 src/main/resources/application.yml diff --git a/src/main/java/com/lk/paopao/conf/CorsConfig.java b/src/main/java/com/lk/paopao/conf/CorsConfig.java new file mode 100644 index 0000000..7a5cd7f --- /dev/null +++ b/src/main/java/com/lk/paopao/conf/CorsConfig.java @@ -0,0 +1,42 @@ +package com.lk.paopao.conf; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import java.util.List; + +/** + * 配置类,用于设置跨域请求 + */ +@Configuration +public class CorsConfig { + + /** + * 创建并配置CorsFilter bean + * + * @return CorsFilter bean实例,用于处理跨域请求 + */ + @Bean + public CorsFilter corsFilter() { + // 创建URL基于的Cors配置源 + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + // 创建Cors配置实例 + CorsConfiguration config = new CorsConfiguration(); + + // 配置允许的源 + config.setAllowedOrigins(List.of("http://localhost","http://localhost:8880")); + // 配置允许的方法 + config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); + // 配置允许的头部 + config.setAllowedHeaders(List.of("*")); + // 允许凭据 + config.setAllowCredentials(true); + + // 在配置源中注册全局跨域配置 + source.registerCorsConfiguration("/**", config); + // 返回CorsFilter实例 + return new CorsFilter(source); + } +} diff --git a/src/main/java/com/lk/paopao/controller/AuthController.java b/src/main/java/com/lk/paopao/controller/AuthController.java new file mode 100644 index 0000000..4074e30 --- /dev/null +++ b/src/main/java/com/lk/paopao/controller/AuthController.java @@ -0,0 +1,44 @@ +package com.lk.paopao.controller; + +import com.lk.paopao.entity.User; +import com.lk.paopao.service.AuthService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/v1/auth") +public class AuthController { + + @Autowired + private AuthService authService; + + @PostMapping("register") + public Map register(@RequestBody User user){ + User newUser = authService.register(user); + return Map.of("code", 0, "msg", "success", "data", Map.of("id", newUser.getId(),"username",newUser.getUsername())); + } + + @PostMapping("login") + public Map login(@RequestBody User user){ + String token = authService.login(user.getUsername(), user.getPassword()); +// Map tokenMap = Map.of("token", token); +// return Map.of("code", 0, "msg", "success", "data", tokenMap); + + Map token2 = new HashMap<>(); + token2.put("token", token); + + Map result= new HashMap<>(); + result.put("code", 0); + result.put("msg", "success"); + result.put("data", token2); + return result; + } + + @GetMapping("abc") + public void abc(@RequestAttribute("username") String username){ + System.out.println("abc"); + } +} diff --git a/src/main/java/com/lk/paopao/controller/UserController.java b/src/main/java/com/lk/paopao/controller/UserController.java new file mode 100644 index 0000000..243cd35 --- /dev/null +++ b/src/main/java/com/lk/paopao/controller/UserController.java @@ -0,0 +1,31 @@ +package com.lk.paopao.controller; + +import com.lk.paopao.entity.User; +import com.lk.paopao.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/v1/user") +public class UserController { + + @Autowired + private UserService userService; + + @GetMapping("info") + public Map info(@RequestAttribute("username") String username) { + User user = userService.getUserName(username); + Map result= new HashMap<>(); + result.put("code", 0); + result.put("msg", "success"); + result.put("data", user); + user.setPassword(""); + return result; + } +} diff --git a/src/main/java/com/lk/paopao/entity/User.java b/src/main/java/com/lk/paopao/entity/User.java new file mode 100644 index 0000000..6eb35ec --- /dev/null +++ b/src/main/java/com/lk/paopao/entity/User.java @@ -0,0 +1,95 @@ +package com.lk.paopao.entity; + +import jakarta.persistence.*; + +@Entity +@Table(name = "users") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(unique = true, nullable = false) + private String username; + + @Column(nullable = false) + private String password; + + @Column(nullable = false) + String nickname; + + Integer status=1; + + @Column(nullable = false) + String avatar; + + String phone; + + + Integer isAdmin=0; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public int getIsAdmin() { + return isAdmin; + } + + public void setIsAdmin(int isAdmin) { + this.isAdmin = isAdmin; + } +} diff --git a/src/main/java/com/lk/paopao/jwt/JwtConfig.java b/src/main/java/com/lk/paopao/jwt/JwtConfig.java new file mode 100644 index 0000000..915dcb1 --- /dev/null +++ b/src/main/java/com/lk/paopao/jwt/JwtConfig.java @@ -0,0 +1,36 @@ +package com.lk.paopao.jwt; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 配置类,用于在Spring Boot应用中注册JWT过滤器 + */ +@Configuration +public class JwtConfig { + + /** + * 自动注入JwtFilter,用于处理JWT相关的请求 + */ + @Autowired + private JwtFilter jwtFilter; + + /** + * 创建并配置JwtFilter的FilterRegistrationBean + * + * @return FilterRegistrationBean 配置了JwtFilter的FilterRegistrationBean实例 + */ + @Bean + public FilterRegistrationBean loggingFilter() { + // 创建FilterRegistrationBean对象,用于注册JwtFilter + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + // 设置过滤器实例 + registrationBean.setFilter(jwtFilter); + // 添加需要过滤的URL模式 + registrationBean.addUrlPatterns("/v1/user/*","/v1/post/*"); + // 返回配置好的FilterRegistrationBean + return registrationBean; + } +} diff --git a/src/main/java/com/lk/paopao/jwt/JwtFilter.java b/src/main/java/com/lk/paopao/jwt/JwtFilter.java new file mode 100644 index 0000000..ec63910 --- /dev/null +++ b/src/main/java/com/lk/paopao/jwt/JwtFilter.java @@ -0,0 +1,69 @@ +package com.lk.paopao.jwt; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; +import java.io.IOException; + +/** + * JWT过滤器,用于处理每次请求,验证JWT令牌并设置用户认证信息。 + */ +@Component +public class JwtFilter extends OncePerRequestFilter { + + @Autowired + private JwtService jwtService; + + /** + * 核心过滤方法,处理每次请求。 + * + * @param request 请求对象,用于获取请求头中的JWT令牌。 + * @param response 响应对象,用于处理响应。 + * @param filterChain 过滤链,用于继续处理请求链。 + * @throws ServletException 如果过滤过程中发生Servlet异常。 + * @throws IOException 如果过滤过程中发生IO异常。 + */ + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + try { + // 解析JWT令牌。 + String jwt = parseJwt(request); + if (jwt != null && jwtService.validateToken(jwt)) { + // 从JWT令牌中获取用户名。 + String username = jwtService.getUserNameFromJwtToken(jwt); + + // 将用户名设置为请求属性,以便后续处理使用。 + request.setAttribute("username", username); + } + } catch (Exception e) { + // 记录无法设置用户认证的错误。 + logger.error("Cannot set user authentication:", e); + } + + // 继续处理请求链。 + filterChain.doFilter(request, response); + } + + /** + * 解析请求中的JWT令牌。 + * + * @param request 请求对象,用于获取请求头中的JWT令牌。 + * @return 如果解析成功,则返回JWT令牌字符串;否则返回null。 + */ + private String parseJwt(HttpServletRequest request) { + // 从请求头中获取"Authorization"字段。 + String headerAuth = request.getHeader("Authorization"); + // 如果存在且以"Bearer "开头,则提取并返回令牌字符串。 + if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) { + return headerAuth.substring(7); + } + + // 如果不符合条件,则返回null。 + return null; + } +} diff --git a/src/main/java/com/lk/paopao/jwt/JwtService.java b/src/main/java/com/lk/paopao/jwt/JwtService.java new file mode 100644 index 0000000..2bef99f --- /dev/null +++ b/src/main/java/com/lk/paopao/jwt/JwtService.java @@ -0,0 +1,87 @@ +package com.lk.paopao.jwt; + +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import org.springframework.stereotype.Component; +import io.jsonwebtoken.Jwts; + +import javax.crypto.SecretKey; +import java.util.Date; + +/** + * JWT服务类,用于生成和验证JWT Token + */ +@Component +public class JwtService { + + // JWT密钥,用于签名和验证 + private static final String SECRET = "uYuVw0mke38MfLhO19wUQyRgwrmYo89ibpQTXPHi4vg="; + + // JWT过期时间,单位:毫秒 + private static final long JWT_EXPIRATION_MS = 1000 * 3600 * 24; + + /** + * 生成JWT Token + * + * @param username 用户名,作为JWT的主题 + * @return 生成的JWT Token字符串 + */ + public String generateJwtToken(String username) { + // 创建JWT,设置主题、签发时间、过期时间和签名密钥 + return Jwts.builder().subject(username) + .issuedAt(new Date()) + .expiration(new Date(new Date().getTime() + JWT_EXPIRATION_MS)) + .signWith(getSigningKey()) + .compact(); + } + + /** + * 获取签名密钥 + * + * @return 签名所用的SecretKey + */ + private SecretKey getSigningKey() { + // 解码JWT密钥 + byte[] keyBytes = Decoders.BASE64.decode(SECRET); + return Keys.hmacShaKeyFor(keyBytes); + } + + /** + * 从JWT Token中提取用户名 + * + * @param token JWT Token字符串 + * @return 提取的用户名 + */ + public String getUserNameFromJwtToken(String token) { + // 解析JWT Token并提取主题(用户名) + return Jwts.parser() + .verifyWith(getSigningKey()) + .build() + .parseSignedClaims(token) + .getPayload() + .getSubject(); + } + + /** + * 验证JWT Token的有效性 + * + * @param authToken JWT Token字符串 + * @return 如果Token有效返回true,否则返回false + */ + public boolean validateToken(String authToken) { + try { + // 尝试解析JWT Token,如无异常则表示Token有效 + Jwts.parser() + .verifyWith(getSigningKey()) + .build() + .parseSignedClaims(authToken); + return true; + } catch (Exception e) { + // 记录JWT签名异常 + System.out.println("Invalid JWT signature: " + e.getMessage()); + } + + return false; + } + +} diff --git a/src/main/java/com/lk/paopao/repository/UserRepository.java b/src/main/java/com/lk/paopao/repository/UserRepository.java new file mode 100644 index 0000000..07662c6 --- /dev/null +++ b/src/main/java/com/lk/paopao/repository/UserRepository.java @@ -0,0 +1,10 @@ +package com.lk.paopao.repository; + +import com.lk.paopao.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { + User findByUsername(String username); +} diff --git a/src/main/java/com/lk/paopao/service/AuthService.java b/src/main/java/com/lk/paopao/service/AuthService.java new file mode 100644 index 0000000..ca69ed3 --- /dev/null +++ b/src/main/java/com/lk/paopao/service/AuthService.java @@ -0,0 +1,39 @@ +package com.lk.paopao.service; + +import com.lk.paopao.entity.User; +import com.lk.paopao.jwt.JwtService; +import com.lk.paopao.repository.UserRepository; +import org.hibernate.boot.model.process.internal.UserTypeResolution; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class AuthService { + + @Autowired + UserRepository userRepository; + + @Autowired + JwtService jwtService; + + final String AVATAR="https://assets.paopao.info/public/avatar/default/jackson.png"; + + public User register(User user){ + //TODO: + user.setAvatar(AVATAR); + user.setNickname(user.getUsername()); + return userRepository.save(user); + } + + public String login(String username, String password){ + // 根据用户账号,获取用户信息 + User user = userRepository.findByUsername(username); + if(user!=null){ + if(user.getPassword().equals(password)){ + // 返回token + return jwtService.generateJwtToken(username); + } + } + return null; + } +} diff --git a/src/main/java/com/lk/paopao/service/UserService.java b/src/main/java/com/lk/paopao/service/UserService.java new file mode 100644 index 0000000..94b90e5 --- /dev/null +++ b/src/main/java/com/lk/paopao/service/UserService.java @@ -0,0 +1,16 @@ +package com.lk.paopao.service; + +import com.lk.paopao.entity.User; +import com.lk.paopao.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class UserService { + @Autowired + private UserRepository userRepository; + public User getUserName(String username) { + return userRepository.findByUsername(username); + + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..37af03c --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,25 @@ + +spring: + application: + name: paopao + jackson: + property-naming-strategy: SNAKE_CASE # 驼峰转下划线,以适应数据库字段命名规则 + datasource: + url: jdbc:h2:file:./db.h2 # 使用文件存储,配置数据库连接URL + driverClassName: org.h2.Driver # 指定数据库驱动类 + username: root # 数据库用户名 + password: root # 数据库密码 + h2: + console: # 开启console访问 默认false,提供数据库管理界面 + enabled: true # 启用H2控制台访问功能 + settings: + trace: true # 开启h2 console 跟踪 方便调试 默认 false + web-allow-others: true # 允许console 远程访问 默认false,提高可用性 + path: /h2 # h2 访问路径上下文,定义访问路由 + jpa: + show-sql: true # 显示SQL查询,便于调试和性能优化 + open-in-view: false # 禁用Open SessionInView,避免性能问题和资源泄露 + defer-datasource-initialization: true # 延迟数据源初始化,确保配置加载完成 + database-platform: org.hibernate.dialect.H2Dialect # 指定数据库方言,优化SQL生成 + hibernate: + ddl-auto: update # 自动更新数据库结构,适应实体模型变化