This commit is contained in:
wu 2024-12-04 08:18:11 +08:00
parent 98f5e98d65
commit 6841e2f32e
11 changed files with 494 additions and 0 deletions

View File

@ -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);
}
}

View File

@ -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<String, Object> 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<String, Object> login(@RequestBody User user){
String token = authService.login(user.getUsername(), user.getPassword());
// Map<String, String> tokenMap = Map.of("token", token);
// return Map.of("code", 0, "msg", "success", "data", tokenMap);
Map<String,String> token2 = new HashMap<>();
token2.put("token", token);
Map<String, Object> 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");
}
}

View File

@ -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<String,Object> info(@RequestAttribute("username") String username) {
User user = userService.getUserName(username);
Map<String, Object> result= new HashMap<>();
result.put("code", 0);
result.put("msg", "success");
result.put("data", user);
user.setPassword("");
return result;
}
}

View File

@ -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;
}
}

View File

@ -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> 配置了JwtFilter的FilterRegistrationBean实例
*/
@Bean
public FilterRegistrationBean<JwtFilter> loggingFilter() {
// 创建FilterRegistrationBean对象用于注册JwtFilter
FilterRegistrationBean<JwtFilter> registrationBean = new FilterRegistrationBean<>();
// 设置过滤器实例
registrationBean.setFilter(jwtFilter);
// 添加需要过滤的URL模式
registrationBean.addUrlPatterns("/v1/user/*","/v1/post/*");
// 返回配置好的FilterRegistrationBean
return registrationBean;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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, Long> {
User findByUsername(String username);
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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 # 自动更新数据库结构,适应实体模型变化