From 40970c136407a327317ac483d42007568649c1bb Mon Sep 17 00:00:00 2001 From: wzp Date: Thu, 19 Dec 2024 12:59:36 +0800 Subject: [PATCH] feat: adding deps and adding base framework --- build.gradle.kts | 10 +- .../java/org/blue/club/ClubApplication.java | 7 ++ .../java/org/blue/club/annotation/Auth.java | 22 +++++ .../club/configuration/AuthConfiguration.java | 18 ++++ .../CustomAuthorizationHandler.java | 39 ++++++++ .../blue/club/controller/UserController.java | 97 +++++++++++++++++-- src/main/java/org/blue/club/dao/UserDao.java | 9 ++ .../java/org/blue/club/entities/dto/User.java | 29 ++++++ .../club/entities/dto/req/LoginRequest.java | 8 ++ .../club/entities/vo/AuthPermissionVo.java | 16 +++ .../org/blue/club/entities/vo/AuthVo.java | 27 ++++++ .../org/blue/club/entities/vo/BaseVo.java | 12 +++ .../blue/club/entities/vo/ClubUserAuthVo.java | 18 ++++ .../org/blue/club/entities/vo/ClubVo.java | 16 +++ .../blue/club/entities/vo/PermissionVo.java | 15 +++ .../org/blue/club/entities/vo/UserVo.java | 30 ++++++ .../org/blue/club/services/UserServices.java | 28 ++++++ src/main/resources/application.properties | 3 + 18 files changed, 391 insertions(+), 13 deletions(-) create mode 100644 src/main/java/org/blue/club/annotation/Auth.java create mode 100644 src/main/java/org/blue/club/configuration/AuthConfiguration.java create mode 100644 src/main/java/org/blue/club/configuration/CustomAuthorizationHandler.java create mode 100644 src/main/java/org/blue/club/dao/UserDao.java create mode 100644 src/main/java/org/blue/club/entities/dto/User.java create mode 100644 src/main/java/org/blue/club/entities/dto/req/LoginRequest.java create mode 100644 src/main/java/org/blue/club/entities/vo/AuthPermissionVo.java create mode 100644 src/main/java/org/blue/club/entities/vo/AuthVo.java create mode 100644 src/main/java/org/blue/club/entities/vo/BaseVo.java create mode 100644 src/main/java/org/blue/club/entities/vo/ClubUserAuthVo.java create mode 100644 src/main/java/org/blue/club/entities/vo/ClubVo.java create mode 100644 src/main/java/org/blue/club/entities/vo/PermissionVo.java create mode 100644 src/main/java/org/blue/club/entities/vo/UserVo.java create mode 100644 src/main/java/org/blue/club/services/UserServices.java diff --git a/build.gradle.kts b/build.gradle.kts index 7907feb..ad09f21 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,11 +28,11 @@ repositories { dependencies { implementation("org.springframework.boot:spring-boot-starter-actuator") - implementation("org.springframework.boot:spring-boot-starter-data-redis") - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter-websocket") - implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.4") - implementation("org.mmga:make-minecraft-great-again-spring-boot-starter:0.0.2-20241217.115150-5") + implementation("org.mmga:make-minecraft-great-again-spring-boot-starter:0.0.5-20241219.044545-4") + implementation("com.mybatis-flex:mybatis-flex-spring-boot-starter:1.10.2") + annotationProcessor("com.mybatis-flex:mybatis-flex-processor:1.10.2") + // https://mvnrepository.com/artifact/commons-codec/commons-codec + implementation("commons-codec:commons-codec:1.16.1") compileOnly("org.projectlombok:lombok") runtimeOnly("com.mysql:mysql-connector-j") annotationProcessor("org.projectlombok:lombok") diff --git a/src/main/java/org/blue/club/ClubApplication.java b/src/main/java/org/blue/club/ClubApplication.java index 7ee5221..dce0250 100644 --- a/src/main/java/org/blue/club/ClubApplication.java +++ b/src/main/java/org/blue/club/ClubApplication.java @@ -1,5 +1,8 @@ package org.blue.club; +import com.mybatisflex.core.audit.AuditManager; +import com.mybatisflex.core.audit.ConsoleMessageCollector; +import com.mybatisflex.core.audit.MessageCollector; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -7,6 +10,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; public class ClubApplication { public static void main(String[] args) { + //开启审计功能 + AuditManager.setAuditEnable(true); + MessageCollector collector = new ConsoleMessageCollector(); + AuditManager.setMessageCollector(collector); SpringApplication.run(ClubApplication.class, args); } diff --git a/src/main/java/org/blue/club/annotation/Auth.java b/src/main/java/org/blue/club/annotation/Auth.java new file mode 100644 index 0000000..55b895c --- /dev/null +++ b/src/main/java/org/blue/club/annotation/Auth.java @@ -0,0 +1,22 @@ +package org.blue.club.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.PARAMETER, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Auth { + long[] permissions() default {}; + + LogicType permissionType() default LogicType.ANY; + + long[] auths() default {}; + + LogicType authType() default LogicType.ANY; + + enum LogicType { + ANY, ALL + } +} diff --git a/src/main/java/org/blue/club/configuration/AuthConfiguration.java b/src/main/java/org/blue/club/configuration/AuthConfiguration.java new file mode 100644 index 0000000..94ea3d4 --- /dev/null +++ b/src/main/java/org/blue/club/configuration/AuthConfiguration.java @@ -0,0 +1,18 @@ +package org.blue.club.configuration; + +import lombok.RequiredArgsConstructor; +import org.blue.club.annotation.Auth; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.lang.annotation.Annotation; + +@Configuration +@RequiredArgsConstructor +public class AuthConfiguration { + + @Bean + public Class authAnnotation() { + return Auth.class; + } +} diff --git a/src/main/java/org/blue/club/configuration/CustomAuthorizationHandler.java b/src/main/java/org/blue/club/configuration/CustomAuthorizationHandler.java new file mode 100644 index 0000000..ca8791e --- /dev/null +++ b/src/main/java/org/blue/club/configuration/CustomAuthorizationHandler.java @@ -0,0 +1,39 @@ +package org.blue.club.configuration; + +import lombok.RequiredArgsConstructor; +import org.blue.club.annotation.Auth; +import org.blue.club.dao.UserDao; +import org.blue.club.entities.dto.User; +import org.blue.club.entities.vo.UserVo; +import org.mmga.spring.boot.starter.componet.AuthorizationHandler; +import org.mmga.spring.boot.starter.componet.JwtUtils; +import org.mmga.spring.boot.starter.entities.Result; +import org.mmga.spring.boot.starter.exception.AuthorizationException; +import org.mmga.spring.boot.starter.utils.VoUtils; +import org.springframework.stereotype.Component; + +import java.lang.annotation.Annotation; +import java.util.Optional; + +@Component +@RequiredArgsConstructor +public class CustomAuthorizationHandler implements AuthorizationHandler { + private final JwtUtils jwtUtils; + private final UserDao userDao; + private final VoUtils voUtils; + + @Override + public Optional auth(String token, Annotation ann) { + if (ann instanceof Auth auth) { + Optional i = jwtUtils.verifyToken(token); + if (i.isEmpty()) throw new AuthorizationException(Result.failed("token错误!")); + Long userId = i.get(); + UserVo userVo = userDao.selectOneWithRelationsById(userId); + if (userVo == null) throw new AuthorizationException(Result.failed("用户不存在!")); + User user = voUtils.vo2DtoSafe(userVo, User.class); + + return Optional.ofNullable(user); + } + return Optional.empty(); + } +} diff --git a/src/main/java/org/blue/club/controller/UserController.java b/src/main/java/org/blue/club/controller/UserController.java index 2ba4e40..541d7af 100644 --- a/src/main/java/org/blue/club/controller/UserController.java +++ b/src/main/java/org/blue/club/controller/UserController.java @@ -1,19 +1,100 @@ package org.blue.club.controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; -import org.mmga.spring.boot.starter.componet.JwtUtils; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import lombok.extern.slf4j.Slf4j; +import org.blue.club.annotation.Auth; +import org.blue.club.entities.dto.User; +import org.blue.club.services.UserServices; +import org.mmga.spring.boot.starter.entities.PagerData; +import org.mmga.spring.boot.starter.entities.Result; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +@Slf4j @RestController @RequestMapping("/api/user") @RequiredArgsConstructor +@Tag(name = "用户相关接口") public class UserController { - private final JwtUtils jwtUtils; + private final UserServices userServices; - @GetMapping("/demo") - public String demo() { - return jwtUtils.createToken(111); + @PostMapping("/login") + @Operation(description = "用户登录", responses = {@ApiResponse(description = "返回是否登录成功", responseCode = "200")}) + public Result login(@RequestBody UserLoginVo user, HttpServletResponse response) { + return userServices.login(user, response); + } + + @PutMapping("/create") + @Operation(description = "创建用户", responses = {@ApiResponse(description = "返回创建后的用户")}) + public Result createUser(@RequestBody UserRegVo user, HttpServletResponse response) { + return userServices.createUser(user, response); + } + + @GetMapping("/info") + @Operation(description = "获取用户信息") + public Result getUserInfo(@RequestAttribute("user") int userId) { + return userServices.getUserInfo(userId); + } + + @GetMapping("/all") + @Operation(description = "获取所有用户信息(分页)") + @Auth(permissions = {4}) + public Result> getAllUserInfo(@RequestParam("num") int num, @RequestParam("page") int page) { + return userServices.getAllUserInfo(num, page); + } + + @PutMapping("/rename") + @Operation(description = "修改用户名") + @Auth + public Result changeUsername(@RequestBody UserRenameVo renameVo, @Auth User user) { + return userServices.changeUsername(renameVo, user); + } + + @PutMapping("/password") + @Operation(description = "修改密码") + public Result changePassword(@RequestBody UserChangePasswordVo changePasswordVo, @Auth User user) { + return userServices.changePassword(changePasswordVo, user); + } + + @PutMapping("/auth") + @Operation(description = "修改用户权限组") + @Auth(permissions = {4}) + public Result changeAuth(@RequestBody UserChangeAuthVo userChangeAuthVo) { + return userServices.changeAuth(userChangeAuthVo); + } + + @PostMapping("/avatar") + @Operation(description = "上传头像") + public Result changeAvatar(MultipartFile file, @Auth User user) { + return userServices.changeAvatar(file, userId); + } + + @PutMapping("/avatar") + @Operation(description = "修改用户头像") + public Result changeAvatar(@RequestParam("code") @Schema(description = "修改头像操作码,可以通过将图片文件上传至") String avatarOperationCode, @Auth User user) { + return userServices.changeAvatar(avatarOperationCode, user); + } + + @GetMapping("/verify") + @Operation(description = "获取验证码") + public Result generatorVerifyCode() { + return userServices.getVerifyCode(); + } + + @GetMapping("/avatar/{sha1}") + @Operation(description = "获取头像文件") + public void getAvatar(HttpServletResponse response, @Schema(description = "头像文件SHA1值") @PathVariable("sha1") String sha1) { + userServices.getAvatar(response, sha1); + } + + @GetMapping("/info/{id}") + @Operation(description = "获取简略用户信息") + public Result getSimpleInfo(@PathVariable("id") int userId) { + return userServices.getUserInfo(userId); } } diff --git a/src/main/java/org/blue/club/dao/UserDao.java b/src/main/java/org/blue/club/dao/UserDao.java new file mode 100644 index 0000000..27a8d92 --- /dev/null +++ b/src/main/java/org/blue/club/dao/UserDao.java @@ -0,0 +1,9 @@ +package org.blue.club.dao; + +import com.mybatisflex.core.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.blue.club.entities.vo.UserVo; + +@Mapper +public interface UserDao extends BaseMapper { +} diff --git a/src/main/java/org/blue/club/entities/dto/User.java b/src/main/java/org/blue/club/entities/dto/User.java new file mode 100644 index 0000000..dc7c0a1 --- /dev/null +++ b/src/main/java/org/blue/club/entities/dto/User.java @@ -0,0 +1,29 @@ +package org.blue.club.entities.dto; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.RelationManyToOne; +import jakarta.annotation.Nullable; +import lombok.Data; +import org.blue.club.entities.vo.AuthVo; +import org.blue.club.entities.vo.ClubVo; +import org.mmga.spring.boot.starter.interfaces.IdHolder; + +@Data +public class User implements IdHolder { + @Id + private Long id; + private String name; + @Nullable + private String avatar; + private AuthVo auths; + private ClubVo club; + private AuthVo clubAuth; + + public boolean hasPermission(Long permissionId) { + return clubAuth.hasPermission(permissionId) || auths.hasPermission(permissionId); + } + + public boolean isAuth(Long authId) { + return (auths != null && authId.equals(auths.getId())) || (clubAuth != null && authId.equals(clubAuth.getId())); + } +} diff --git a/src/main/java/org/blue/club/entities/dto/req/LoginRequest.java b/src/main/java/org/blue/club/entities/dto/req/LoginRequest.java new file mode 100644 index 0000000..d79761d --- /dev/null +++ b/src/main/java/org/blue/club/entities/dto/req/LoginRequest.java @@ -0,0 +1,8 @@ +package org.blue.club.entities.dto.req; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(name = "登录请求体") +public record LoginRequest(@Schema(description = "用户名") String username, + @Schema(description = "使用MD5摘要过后的密码hex") String password) { +} diff --git a/src/main/java/org/blue/club/entities/vo/AuthPermissionVo.java b/src/main/java/org/blue/club/entities/vo/AuthPermissionVo.java new file mode 100644 index 0000000..c3f7813 --- /dev/null +++ b/src/main/java/org/blue/club/entities/vo/AuthPermissionVo.java @@ -0,0 +1,16 @@ +package org.blue.club.entities.vo; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Table; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +@Table("auth_permission") +public class AuthPermissionVo extends BaseVo { + @Column("auth_id") + private Long authId; + @Column("permission_id") + private Long permissionId; +} diff --git a/src/main/java/org/blue/club/entities/vo/AuthVo.java b/src/main/java/org/blue/club/entities/vo/AuthVo.java new file mode 100644 index 0000000..febe110 --- /dev/null +++ b/src/main/java/org/blue/club/entities/vo/AuthVo.java @@ -0,0 +1,27 @@ +package org.blue.club.entities.vo; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.RelationManyToMany; +import com.mybatisflex.annotation.Table; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Table("auth") +@Data +public class AuthVo extends BaseVo { + @Id + private Long id; + private String name; + @RelationManyToMany(joinTable = "auth_permission", + selfField = "id", joinSelfColumn = "auth_id", + targetField = "id", joinTargetColumn = "permission_id" + ) + private List permissions; + + public boolean hasPermission(Long permissionId) { + return permissions.stream().anyMatch(p -> permissionId.equals(p.getId())); + } +} diff --git a/src/main/java/org/blue/club/entities/vo/BaseVo.java b/src/main/java/org/blue/club/entities/vo/BaseVo.java new file mode 100644 index 0000000..c1a8a3e --- /dev/null +++ b/src/main/java/org/blue/club/entities/vo/BaseVo.java @@ -0,0 +1,12 @@ +package org.blue.club.entities.vo; + +import com.mybatisflex.annotation.Column; + +import java.util.Date; + +public class BaseVo { + @Column(value = "create_time", onUpdateValue = "now()", onInsertValue = "now()") + protected Date createTime; + @Column(value = "update_time", onUpdateValue = "now()", onInsertValue = "now()") + protected Date updateTime; +} diff --git a/src/main/java/org/blue/club/entities/vo/ClubUserAuthVo.java b/src/main/java/org/blue/club/entities/vo/ClubUserAuthVo.java new file mode 100644 index 0000000..808f9a4 --- /dev/null +++ b/src/main/java/org/blue/club/entities/vo/ClubUserAuthVo.java @@ -0,0 +1,18 @@ +package org.blue.club.entities.vo; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Table; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Table("club_user_auth") +@Data +public class ClubUserAuthVo extends BaseVo { + @Column("user_id") + private Long userId; + @Column("club_id") + private Long clubId; + @Column("auth_id") + private Long authId; +} diff --git a/src/main/java/org/blue/club/entities/vo/ClubVo.java b/src/main/java/org/blue/club/entities/vo/ClubVo.java new file mode 100644 index 0000000..36125dd --- /dev/null +++ b/src/main/java/org/blue/club/entities/vo/ClubVo.java @@ -0,0 +1,16 @@ +package org.blue.club.entities.vo; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.Table; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +@Table("club") +public class ClubVo extends BaseVo { + @Id + private Long id; + private String name; + private String commit; +} diff --git a/src/main/java/org/blue/club/entities/vo/PermissionVo.java b/src/main/java/org/blue/club/entities/vo/PermissionVo.java new file mode 100644 index 0000000..7a0f690 --- /dev/null +++ b/src/main/java/org/blue/club/entities/vo/PermissionVo.java @@ -0,0 +1,15 @@ +package org.blue.club.entities.vo; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.Table; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Table("permission") +@Data +public class PermissionVo extends BaseVo { + @Id + private Long id; + private String name; +} diff --git a/src/main/java/org/blue/club/entities/vo/UserVo.java b/src/main/java/org/blue/club/entities/vo/UserVo.java new file mode 100644 index 0000000..a0235ba --- /dev/null +++ b/src/main/java/org/blue/club/entities/vo/UserVo.java @@ -0,0 +1,30 @@ +package org.blue.club.entities.vo; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.RelationManyToOne; +import com.mybatisflex.annotation.Table; +import jakarta.annotation.Nullable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.mmga.spring.boot.starter.annotation.VoIgnore; + +@EqualsAndHashCode(callSuper = true) +@Data +@Table("user") +public class UserVo extends BaseVo { + @Id + private Long id; + private String name; + @VoIgnore + private String password; + @VoIgnore + private Integer auth; + @Nullable + private String avatar; + @RelationManyToOne(selfField = "auth", targetField = "id") + private AuthVo auths; + @RelationManyToOne(joinTable = "club_user_auth", selfField = "id", joinSelfColumn = "user_id", targetField = "id", joinTargetColumn = "club_id") + private ClubVo club; + @RelationManyToOne(joinTable = "club_user_auth", selfField = "id", joinSelfColumn = "user_id", targetField = "id", joinTargetColumn = "auth_id") + private AuthVo clubAuth; +} diff --git a/src/main/java/org/blue/club/services/UserServices.java b/src/main/java/org/blue/club/services/UserServices.java new file mode 100644 index 0000000..2ffdb0a --- /dev/null +++ b/src/main/java/org/blue/club/services/UserServices.java @@ -0,0 +1,28 @@ +package org.blue.club.services; + +import lombok.RequiredArgsConstructor; +import org.apache.commons.codec.digest.DigestUtils; +import org.blue.club.dao.UserDao; +import org.blue.club.entities.dto.User; +import org.blue.club.entities.dto.req.LoginRequest; +import org.blue.club.entities.vo.UserVo; +import org.mmga.spring.boot.starter.entities.Result; +import org.mmga.spring.boot.starter.utils.VoUtils; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import static org.blue.club.entities.vo.table.UserVoTableDef.USER_VO; + +@Service +@RequiredArgsConstructor +public class UserServices { + private final UserDao userDao; + private final VoUtils voUtils; + + public Result login(LoginRequest loginRequest, String address) { + UserVo userVo = userDao.selectOneWithRelationsByCondition(USER_VO.NAME.eq(loginRequest.username()).and(USER_VO.PASSWORD.eq(DigestUtils.sha1Hex(loginRequest.password())))); + if (userVo == null) return Result.failed(HttpStatus.NOT_FOUND, "用户不存在!"); + User user = voUtils.vo2DtoSafe(userVo, User.class); + return Result.success(user); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2f504d4..9e90715 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,4 @@ spring.application.name=club +springdoc.swagger-ui.path=/docs +mmga.auth.keySave=DISK +mmga.auth.keySaveFilename=key.pem \ No newline at end of file