From 3570e6799f9219a6e35bccbd8049f82098519592 Mon Sep 17 00:00:00 2001 From: HeTianci Date: Sat, 28 Mar 2026 00:39:47 +0800 Subject: [PATCH 1/7] TEST --- frontend/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/README.md b/frontend/README.md index 00ffd16..51fa816 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -95,4 +95,4 @@ npm run preview ## 📄 许可证 -本项目为个人学习项目,仅供学习使用。 +本项目为个人学习项目,仅供学习使用 -- 2.34.1 From afca8793196cef3cc0f276875122120e4b93d839 Mon Sep 17 00:00:00 2001 From: HeTianci Date: Sat, 28 Mar 2026 00:40:56 +0800 Subject: [PATCH 2/7] TEST --- frontend/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/README.md b/frontend/README.md index 51fa816..00ffd16 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -95,4 +95,4 @@ npm run preview ## 📄 许可证 -本项目为个人学习项目,仅供学习使用 +本项目为个人学习项目,仅供学习使用。 -- 2.34.1 From 5463ddc917d2d8f935bd5fe7cdc5155437b7133a Mon Sep 17 00:00:00 2001 From: HeTianci Date: Sat, 28 Mar 2026 00:51:27 +0800 Subject: [PATCH 3/7] TEST --- backend/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/.gitignore b/backend/.gitignore index ac29085..7ff13af 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,5 +1,5 @@ # Maven -target/ +./target/ pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup -- 2.34.1 From b07cf5df960e8c7f68223a5c66bb665c7ebd0fee Mon Sep 17 00:00:00 2001 From: HeTianci Date: Sat, 28 Mar 2026 00:53:30 +0800 Subject: [PATCH 4/7] TESt' --- backend/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/.gitignore b/backend/.gitignore index 7ff13af..1b3fd91 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,5 +1,5 @@ # Maven -./target/ +./target pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup -- 2.34.1 From 104b9ecfaf3bbcd6b3862ad81769f8de3257c10a Mon Sep 17 00:00:00 2001 From: HeTianci Date: Sat, 28 Mar 2026 00:57:01 +0800 Subject: [PATCH 5/7] TEST --- backend/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/.gitignore b/backend/.gitignore index 7ff13af..1b3fd91 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,5 +1,5 @@ # Maven -./target/ +./target pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup -- 2.34.1 From daf92dc704a3f850fb432d79a979962c55a8a087 Mon Sep 17 00:00:00 2001 From: HeTianci Date: Sat, 28 Mar 2026 01:07:16 +0800 Subject: [PATCH 6/7] TEST --- backend/src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 350fe99..fa8b5f8 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -4,7 +4,7 @@ server: spring: application: name: studyingspace-backend - +#数据库账号密码 datasource: driver-class-name: org.postgresql.Driver url: jdbc:postgresql://localhost:5432/StudyingSystem -- 2.34.1 From 0d1dca5945d7b36c36a6f51293c835977802285f Mon Sep 17 00:00:00 2001 From: HeTianci Date: Tue, 31 Mar 2026 21:41:48 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../studyingspace/config/SecurityConfig.java | 5 ++ .../controller/AuthController.java | 56 +++++++++++++++++ .../controller/HelloController.java | 1 + .../com/studyingspace/dto/LoginRequest.java | 9 +++ .../com/studyingspace/dto/LoginResponse.java | 14 +++++ .../studyingspace/dto/RegisterRequest.java | 9 +++ .../java/com/studyingspace/entity/User.java | 36 +++++++++++ .../repository/UserRepository.java | 11 ++++ .../com/studyingspace/utils/JwtUtils.java | 60 +++++++++++++++++++ frontend/package.json | 3 +- frontend/src/api/auth.js | 17 ++++++ frontend/src/main.js | 3 + frontend/src/views/login/Login.vue | 19 +++++- frontend/src/views/login/Register.vue | 28 ++++++++- frontend/vite.config.js | 6 ++ 15 files changed, 272 insertions(+), 5 deletions(-) create mode 100644 backend/src/main/java/com/studyingspace/controller/AuthController.java create mode 100644 backend/src/main/java/com/studyingspace/dto/LoginRequest.java create mode 100644 backend/src/main/java/com/studyingspace/dto/LoginResponse.java create mode 100644 backend/src/main/java/com/studyingspace/dto/RegisterRequest.java create mode 100644 backend/src/main/java/com/studyingspace/entity/User.java create mode 100644 backend/src/main/java/com/studyingspace/repository/UserRepository.java create mode 100644 backend/src/main/java/com/studyingspace/utils/JwtUtils.java create mode 100644 frontend/src/api/auth.js diff --git a/backend/src/main/java/com/studyingspace/config/SecurityConfig.java b/backend/src/main/java/com/studyingspace/config/SecurityConfig.java index f78056f..d371069 100644 --- a/backend/src/main/java/com/studyingspace/config/SecurityConfig.java +++ b/backend/src/main/java/com/studyingspace/config/SecurityConfig.java @@ -49,4 +49,9 @@ public class SecurityConfig { source.registerCorsConfiguration("/**", configuration); return source; } + + @Bean + public org.springframework.security.crypto.password.PasswordEncoder passwordEncoder() { + return new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder(); + } } diff --git a/backend/src/main/java/com/studyingspace/controller/AuthController.java b/backend/src/main/java/com/studyingspace/controller/AuthController.java new file mode 100644 index 0000000..ccb1656 --- /dev/null +++ b/backend/src/main/java/com/studyingspace/controller/AuthController.java @@ -0,0 +1,56 @@ +package com.studyingspace.controller; + +import com.studyingspace.common.Result; +import com.studyingspace.dto.LoginRequest; +import com.studyingspace.dto.LoginResponse; +import com.studyingspace.dto.RegisterRequest; +import com.studyingspace.entity.User; +import com.studyingspace.repository.UserRepository; +import com.studyingspace.utils.JwtUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/auth") +@Tag(name = "用户认证", description = "登录注册接口") +@RequiredArgsConstructor +public class AuthController { + + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + private final JwtUtils jwtUtils; + + @PostMapping("/register") + @Operation(summary = "用户注册", description = "注册新用户") + public Result register(@RequestBody RegisterRequest request) { + if (userRepository.existsByUsername(request.getUsername())) { + return Result.error("用户名已存在"); + } + + User user = new User(); + user.setUsername(request.getUsername()); + user.setPassword(passwordEncoder.encode(request.getPassword())); + userRepository.save(user); + + return Result.success("注册成功"); + } + + @PostMapping("/login") + @Operation(summary = "用户登录", description = "登录并返回 JWT token") + public Result login(@RequestBody LoginRequest request) { + User user = userRepository.findByUsername(request.getUsername()).orElse(null); + if (user == null) { + return Result.error(401, "用户名不存在"); + } + + if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) { + return Result.error(401, "密码错误"); + } + + String token = jwtUtils.generateToken(user.getUsername()); + return Result.success(new LoginResponse(token, user.getUsername())); + } +} diff --git a/backend/src/main/java/com/studyingspace/controller/HelloController.java b/backend/src/main/java/com/studyingspace/controller/HelloController.java index f183ae3..fba0bc3 100644 --- a/backend/src/main/java/com/studyingspace/controller/HelloController.java +++ b/backend/src/main/java/com/studyingspace/controller/HelloController.java @@ -16,5 +16,6 @@ public class HelloController { @Operation(summary = "欢迎接口", description = "返回欢迎信息") public Result hello() { return Result.success("Hello StudyingSpace!"); + } } diff --git a/backend/src/main/java/com/studyingspace/dto/LoginRequest.java b/backend/src/main/java/com/studyingspace/dto/LoginRequest.java new file mode 100644 index 0000000..4c0aa00 --- /dev/null +++ b/backend/src/main/java/com/studyingspace/dto/LoginRequest.java @@ -0,0 +1,9 @@ +package com.studyingspace.dto; + +import lombok.Data; + +@Data +public class LoginRequest { + private String username; + private String password; +} diff --git a/backend/src/main/java/com/studyingspace/dto/LoginResponse.java b/backend/src/main/java/com/studyingspace/dto/LoginResponse.java new file mode 100644 index 0000000..4552be0 --- /dev/null +++ b/backend/src/main/java/com/studyingspace/dto/LoginResponse.java @@ -0,0 +1,14 @@ +package com.studyingspace.dto; + +import lombok.Data; + +@Data +public class LoginResponse { + private String token; + private String username; + + public LoginResponse(String token, String username) { + this.token = token; + this.username = username; + } +} diff --git a/backend/src/main/java/com/studyingspace/dto/RegisterRequest.java b/backend/src/main/java/com/studyingspace/dto/RegisterRequest.java new file mode 100644 index 0000000..719d054 --- /dev/null +++ b/backend/src/main/java/com/studyingspace/dto/RegisterRequest.java @@ -0,0 +1,9 @@ +package com.studyingspace.dto; + +import lombok.Data; + +@Data +public class RegisterRequest { + private String username; + private String password; +} diff --git a/backend/src/main/java/com/studyingspace/entity/User.java b/backend/src/main/java/com/studyingspace/entity/User.java new file mode 100644 index 0000000..5375977 --- /dev/null +++ b/backend/src/main/java/com/studyingspace/entity/User.java @@ -0,0 +1,36 @@ +package com.studyingspace.entity; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@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; + + private LocalDateTime createTime; + + private LocalDateTime updateTime; + + @PrePersist + protected void onCreate() { + createTime = LocalDateTime.now(); + updateTime = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + updateTime = LocalDateTime.now(); + } +} diff --git a/backend/src/main/java/com/studyingspace/repository/UserRepository.java b/backend/src/main/java/com/studyingspace/repository/UserRepository.java new file mode 100644 index 0000000..0f10fad --- /dev/null +++ b/backend/src/main/java/com/studyingspace/repository/UserRepository.java @@ -0,0 +1,11 @@ +package com.studyingspace.repository; + +import com.studyingspace.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface UserRepository extends JpaRepository { + Optional findByUsername(String username); + boolean existsByUsername(String username); +} diff --git a/backend/src/main/java/com/studyingspace/utils/JwtUtils.java b/backend/src/main/java/com/studyingspace/utils/JwtUtils.java new file mode 100644 index 0000000..0c6c6df --- /dev/null +++ b/backend/src/main/java/com/studyingspace/utils/JwtUtils.java @@ -0,0 +1,60 @@ +package com.studyingspace.utils; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.security.Key; +import java.util.Date; +import java.nio.charset.StandardCharsets; + +@Component +public class JwtUtils { + + @Value("${jwt.secret}") + private String secret; + + @Value("${jwt.expiration}") + private Long expiration; + + private Key getSigningKey() { + return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)); + } + + public String generateToken(String username) { + Date now = new Date(); + Date expiryDate = new Date(now.getTime() + expiration); + + return Jwts.builder() + .setSubject(username) + .setIssuedAt(now) + .setExpiration(expiryDate) + .signWith(getSigningKey(), SignatureAlgorithm.HS256) + .compact(); + } + + public String getUsernameFromToken(String token) { + Claims claims = Jwts.parserBuilder() + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token) + .getBody(); + + return claims.getSubject(); + } + + public boolean validateToken(String token) { + try { + Jwts.parserBuilder() + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token); + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/frontend/package.json b/frontend/package.json index 9e15316..8ef59a5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,7 +11,8 @@ "vue": "^3.4.0", "vue-router": "^4.2.5", "pinia": "^2.1.7", - "axios": "^1.6.2" + "axios": "^1.6.2", + "element-plus": "^2.4.4" }, "devDependencies": { "@vitejs/plugin-vue": "^4.5.2", diff --git a/frontend/src/api/auth.js b/frontend/src/api/auth.js new file mode 100644 index 0000000..ce3c76c --- /dev/null +++ b/frontend/src/api/auth.js @@ -0,0 +1,17 @@ +import request from '@/utils/request' + +export function login(data) { + return request({ + url: '/auth/login', + method: 'post', + data + }) +} + +export function register(data) { + return request({ + url: '/auth/register', + method: 'post', + data + }) +} diff --git a/frontend/src/main.js b/frontend/src/main.js index a320789..7804c01 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -2,11 +2,14 @@ import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' import router from './router' +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' import './styles/main.css' const app = createApp(App) app.use(createPinia()) app.use(router) +app.use(ElementPlus) app.mount('#app') diff --git a/frontend/src/views/login/Login.vue b/frontend/src/views/login/Login.vue index 64ba85d..1785dd4 100644 --- a/frontend/src/views/login/Login.vue +++ b/frontend/src/views/login/Login.vue @@ -21,6 +21,8 @@