diff --git a/src/main/java/edu/situ/stlserver/config/AuthInterceptor.java b/src/main/java/edu/situ/stlserver/config/AuthInterceptor.java new file mode 100644 index 0000000..07a0567 --- /dev/null +++ b/src/main/java/edu/situ/stlserver/config/AuthInterceptor.java @@ -0,0 +1,37 @@ +package edu.situ.stlserver.config; + +import edu.situ.stlserver.util.JwtUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.servlet.HandlerInterceptor; + +public class AuthInterceptor implements HandlerInterceptor { + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + // 放行登录接口 + if (request.getRequestURI().contains("/auth/login")) { + return true; + } + // 放行静态资源和Swagger + if (request.getRequestURI().contains("/index.html") + || request.getRequestURI().contains("/v3/api-docs") + || request.getRequestURI().contains("/swagger-ui")) { + return true; + } + + String authHeader = request.getHeader("Authorization"); + if (authHeader == null || !authHeader.startsWith("Bearer ")) { + response.setStatus(401); + return false; + } + + String token = authHeader.replace("Bearer ", ""); + if (!JwtUtil.isTokenValid(token)) { + response.setStatus(401); + return false; + } + + return true; + } +} diff --git a/src/main/java/edu/situ/stlserver/config/WebConfig.java b/src/main/java/edu/situ/stlserver/config/WebConfig.java new file mode 100644 index 0000000..157181f --- /dev/null +++ b/src/main/java/edu/situ/stlserver/config/WebConfig.java @@ -0,0 +1,16 @@ +package edu.situ.stlserver.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new AuthInterceptor()) + .addPathPatterns("/**") + .excludePathPatterns("/auth/login"); + } +} diff --git a/src/main/java/edu/situ/stlserver/controller/AuthController.java b/src/main/java/edu/situ/stlserver/controller/AuthController.java new file mode 100644 index 0000000..b390131 --- /dev/null +++ b/src/main/java/edu/situ/stlserver/controller/AuthController.java @@ -0,0 +1,54 @@ +package edu.situ.stlserver.controller; + +import edu.situ.stlserver.dao.UserMapper; +import edu.situ.stlserver.model.dto.LoginDTO; +import edu.situ.stlserver.model.entity.User; +import edu.situ.stlserver.model.vo.HttpResult; +import edu.situ.stlserver.util.JwtUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/auth") +public class AuthController { + + @Autowired + private UserMapper userMapper; + + @PostMapping("/login") + public HttpResult login(@RequestBody LoginDTO loginDTO) { + User user = userMapper.selectByUsername(loginDTO.getUsername()); + if (user == null) { + return HttpResult.error("用户名或密码错误"); + } + if (!user.getPassword().equals(loginDTO.getPassword())) { + return HttpResult.error("用户名或密码错误"); + } + String token = JwtUtil.generateToken(user.getId(), user.getUsername()); + Map data = new HashMap<>(); + data.put("token", token); + data.put("nickname", user.getNickname()); + return HttpResult.success(data); + } + + @GetMapping("/info") + public HttpResult info(@RequestHeader("Authorization") String authHeader) { + String token = authHeader.replace("Bearer ", ""); + if (!JwtUtil.isTokenValid(token)) { + return HttpResult.unauthorized(); + } + String username = JwtUtil.getUsername(token); + User user = userMapper.selectByUsername(username); + if (user == null) { + return HttpResult.error("用户不存在"); + } + Map data = new HashMap<>(); + data.put("id", user.getId()); + data.put("username", user.getUsername()); + data.put("nickname", user.getNickname()); + return HttpResult.success(data); + } +} diff --git a/src/main/java/edu/situ/stlserver/dao/UserMapper.java b/src/main/java/edu/situ/stlserver/dao/UserMapper.java new file mode 100644 index 0000000..db117a2 --- /dev/null +++ b/src/main/java/edu/situ/stlserver/dao/UserMapper.java @@ -0,0 +1,12 @@ +package edu.situ.stlserver.dao; + +import edu.situ.stlserver.model.entity.User; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +@Mapper +public interface UserMapper { + + @Select("SELECT * FROM users WHERE username = #{username}") + User selectByUsername(String username); +} diff --git a/src/main/java/edu/situ/stlserver/model/dto/LoginDTO.java b/src/main/java/edu/situ/stlserver/model/dto/LoginDTO.java new file mode 100644 index 0000000..464a9dc --- /dev/null +++ b/src/main/java/edu/situ/stlserver/model/dto/LoginDTO.java @@ -0,0 +1,11 @@ +package edu.situ.stlserver.model.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class LoginDTO { + private String username; + private String password; +} diff --git a/src/main/java/edu/situ/stlserver/model/entity/User.java b/src/main/java/edu/situ/stlserver/model/entity/User.java new file mode 100644 index 0000000..47d414f --- /dev/null +++ b/src/main/java/edu/situ/stlserver/model/entity/User.java @@ -0,0 +1,15 @@ +package edu.situ.stlserver.model.entity; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@ToString +@NoArgsConstructor +@Data +public class User { + private Integer id; + private String username; + private String password; + private String nickname; +} diff --git a/src/main/java/edu/situ/stlserver/util/JwtUtil.java b/src/main/java/edu/situ/stlserver/util/JwtUtil.java new file mode 100644 index 0000000..0cbc874 --- /dev/null +++ b/src/main/java/edu/situ/stlserver/util/JwtUtil.java @@ -0,0 +1,51 @@ +package edu.situ.stlserver.util; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; + +import javax.crypto.SecretKey; +import java.util.Date; + +public class JwtUtil { + private static final String SECRET = "stl-gym-secret-key-2024-very-long-string"; + private static final long EXPIRE = 24 * 60 * 60 * 1000; // 24小时 + + private static SecretKey getKey() { + return Keys.hmacShaKeyFor(SECRET.getBytes()); + } + + public static String generateToken(Integer userId, String username) { + return Jwts.builder() + .subject(String.valueOf(userId)) + .claim("username", username) + .issuedAt(new Date()) + .expiration(new Date(System.currentTimeMillis() + EXPIRE)) + .signWith(getKey()) + .compact(); + } + + public static Claims parseToken(String token) { + return Jwts.parser() + .verifyWith(getKey()) + .build() + .parseSignedClaims(token) + .getPayload(); + } + + public static Integer getUserId(String token) { + return Integer.parseInt(parseToken(token).getSubject()); + } + + public static String getUsername(String token) { + return parseToken(token).get("username", String.class); + } + + public static boolean isTokenValid(String token) { + try { + return parseToken(token).getExpiration().after(new Date()); + } catch (Exception e) { + return false; + } + } +} diff --git a/src/main/resources/schema-user.sql b/src/main/resources/schema-user.sql new file mode 100644 index 0000000..b47fe81 --- /dev/null +++ b/src/main/resources/schema-user.sql @@ -0,0 +1,11 @@ +-- 用户表(用于登录) +CREATE TABLE IF NOT EXISTS `users` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `username` VARCHAR(50) NOT NULL UNIQUE, + `password` VARCHAR(100) NOT NULL, + `nickname` VARCHAR(50) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- 插入默认管理员账号 +INSERT INTO `users` (`username`, `password`, `nickname`) VALUES +('admin', '123456', '管理员');