feat: 添加JWT登录功能 - AuthController、JwtUtil、登录拦截器
This commit is contained in:
parent
6e9535bd89
commit
69ef12aa2b
8 changed files with 207 additions and 0 deletions
37
src/main/java/edu/situ/stlserver/config/AuthInterceptor.java
Normal file
37
src/main/java/edu/situ/stlserver/config/AuthInterceptor.java
Normal file
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
16
src/main/java/edu/situ/stlserver/config/WebConfig.java
Normal file
16
src/main/java/edu/situ/stlserver/config/WebConfig.java
Normal file
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, Object> 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<String, Object> data = new HashMap<>();
|
||||
data.put("id", user.getId());
|
||||
data.put("username", user.getUsername());
|
||||
data.put("nickname", user.getNickname());
|
||||
return HttpResult.success(data);
|
||||
}
|
||||
}
|
||||
12
src/main/java/edu/situ/stlserver/dao/UserMapper.java
Normal file
12
src/main/java/edu/situ/stlserver/dao/UserMapper.java
Normal file
|
|
@ -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);
|
||||
}
|
||||
11
src/main/java/edu/situ/stlserver/model/dto/LoginDTO.java
Normal file
11
src/main/java/edu/situ/stlserver/model/dto/LoginDTO.java
Normal file
|
|
@ -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;
|
||||
}
|
||||
15
src/main/java/edu/situ/stlserver/model/entity/User.java
Normal file
15
src/main/java/edu/situ/stlserver/model/entity/User.java
Normal file
|
|
@ -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;
|
||||
}
|
||||
51
src/main/java/edu/situ/stlserver/util/JwtUtil.java
Normal file
51
src/main/java/edu/situ/stlserver/util/JwtUtil.java
Normal file
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/main/resources/schema-user.sql
Normal file
11
src/main/resources/schema-user.sql
Normal file
|
|
@ -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', '管理员');
|
||||
Loading…
Add table
Add a link
Reference in a new issue