From 9949fba3ed87b22a2fa96856927be6648ee90156 Mon Sep 17 00:00:00 2001 From: MiniDay <372403923@qq.com> Date: Fri, 17 Mar 2023 03:55:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BC=80=E5=8F=91=E4=B8=AD...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/blog/config/WebConfig.java | 9 +- .../blog/config/security/BlogUser.java | 18 +++ .../security/DevSecurityConfiguration.java | 3 +- .../security/UserDetailServiceImpl.java | 15 +-- .../blog/constant/UserPermission.java | 5 - .../blog/constant/UserPermissions.java | 17 +++ .../application/blog/constant/UserRole.java | 16 --- .../blog/controller/ExceptionController.java | 13 ++ .../blog/controller/UserController.java | 26 ++-- .../blog/dao/AttachRepository.java | 8 ++ .../application/blog/dao/UserRepository.java | 8 +- .../application/blog/entity/UserEntity.java | 15 ++- .../blog/entity/mapper/AttachMapper.java | 13 ++ .../blog/entity/mapper/UserMapper.java | 7 +- .../blog/service/IBlogService.java | 3 +- .../blog/service/IUserService.java | 18 ++- .../blog/service/impl/BlogService.java | 3 +- .../blog/service/impl/UserService.java | 121 +++++++++++++++++- .../application/blog/vo/ResponseVO.java | 10 ++ .../blog/vo/attach/AttachInfoResponseVO.java | 14 ++ ...equireVO.java => UserCreateRequireVO.java} | 2 +- .../blog/vo/user/UserInfoResponseVO.java | 10 ++ .../blog/vo/user/UserLoginRequireVO.java | 15 +++ .../blog/vo/user/UserRegisterResponseVO.java | 4 +- .../blog/vo/user/UserUpdateRequireVO.java | 19 +++ 25 files changed, 325 insertions(+), 67 deletions(-) create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogUser.java delete mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermission.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermissions.java delete mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserRole.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/controller/ExceptionController.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/dao/AttachRepository.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/entity/mapper/AttachMapper.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/vo/attach/AttachInfoResponseVO.java rename blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/{UserRegisterRequireVO.java => UserCreateRequireVO.java} (94%) create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserLoginRequireVO.java diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/WebConfig.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/WebConfig.java index 551fc7f..a57771c 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/config/WebConfig.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/WebConfig.java @@ -1,15 +1,16 @@ package cn.hamster3.application.blog.config; +import cn.hamster3.application.blog.config.security.BlogUser; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.AuditorAware; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.User; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import java.util.Optional; +import java.util.UUID; @Configuration public class WebConfig { @@ -19,14 +20,14 @@ public class WebConfig { } @Bean - public AuditorAware getUserIDAuditorAware() { + public AuditorAware getUserIDAuditorAware() { return () -> { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || !authentication.isAuthenticated()) { return Optional.empty(); } - User user = (User) authentication.getPrincipal(); - return Optional.of(user.getUsername()); + BlogUser user = (BlogUser) authentication.getPrincipal(); + return Optional.of(user.getUuid()); }; } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogUser.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogUser.java new file mode 100644 index 0000000..bdeb5fb --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogUser.java @@ -0,0 +1,18 @@ +package cn.hamster3.application.blog.config.security; + +import lombok.Getter; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.User; + +import java.util.Collection; +import java.util.UUID; + +@Getter +public class BlogUser extends User { + private final UUID uuid; + + public BlogUser(String username, String password, Collection authorities, UUID uuid) { + super(username, password, authorities); + this.uuid = uuid; + } +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/DevSecurityConfiguration.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/DevSecurityConfiguration.java index 2ec61db..2969124 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/DevSecurityConfiguration.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/DevSecurityConfiguration.java @@ -1,6 +1,7 @@ package cn.hamster3.application.blog.config.security; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @@ -32,7 +33,7 @@ public class DevSecurityConfiguration { log.info("add cors configuration..."); return new WebMvcConfigurer() { @Override - public void addCorsMappings(CorsRegistry registry) { + public void addCorsMappings(@NotNull CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("*") diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/UserDetailServiceImpl.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/UserDetailServiceImpl.java index 51853f2..77d261e 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/UserDetailServiceImpl.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/UserDetailServiceImpl.java @@ -1,10 +1,8 @@ package cn.hamster3.application.blog.config.security; +import cn.hamster3.application.blog.constant.UserPermissions; import cn.hamster3.application.blog.dao.UserRepository; -import cn.hamster3.application.blog.entity.UserEntity; import jakarta.annotation.Resource; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -17,14 +15,15 @@ public class UserDetailServiceImpl implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - return userRepo.findByEmailOrNicknameAllIgnoreCase(username, username, UserEntity.class) - .map(user -> new User( - user.getId().toString(), + return userRepo.findByEmailIgnoreCaseWithPermission(username) + .map(user -> new BlogUser( + user.getEmail(), user.getPassword(), user.getPermissions() .stream() - .map(permission -> new SimpleGrantedAuthority(permission.name())) - .toList() + .map(UserPermissions::getAuthority) + .toList(), + user.getId() )).orElseThrow(() -> new UsernameNotFoundException("user not found.")); } } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermission.java b/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermission.java deleted file mode 100644 index 6423ea2..0000000 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermission.java +++ /dev/null @@ -1,5 +0,0 @@ -package cn.hamster3.application.blog.constant; - -public enum UserPermission { - -} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermissions.java b/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermissions.java new file mode 100644 index 0000000..72740f8 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermissions.java @@ -0,0 +1,17 @@ +package cn.hamster3.application.blog.constant; + +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +public enum UserPermissions { + MODIFY_USER_INFO, + MODIFY_USER_PERMISSION; + private final SimpleGrantedAuthority authority; + + UserPermissions() { + this.authority = new SimpleGrantedAuthority(name()); + } + + public SimpleGrantedAuthority getAuthority() { + return authority; + } +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserRole.java b/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserRole.java deleted file mode 100644 index 10d3ca9..0000000 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserRole.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.hamster3.application.blog.constant; - -public enum UserRole { - /** - * 游客 - */ - GUEST, - /** - * 作者 - */ - AUTHOR, - /** - * 管理员 - */ - ADMINISTRATOR -} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/ExceptionController.java b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/ExceptionController.java new file mode 100644 index 0000000..625bf7c --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/ExceptionController.java @@ -0,0 +1,13 @@ +package cn.hamster3.application.blog.controller; + +import cn.hamster3.application.blog.vo.ResponseVO; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class ExceptionController { + @ExceptionHandler(Exception.class) + public ResponseVO onException(Exception e) { + return ResponseVO.failed(e); + } +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/UserController.java b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/UserController.java index a934204..77092b5 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/UserController.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/UserController.java @@ -2,10 +2,8 @@ package cn.hamster3.application.blog.controller; import cn.hamster3.application.blog.service.IUserService; import cn.hamster3.application.blog.vo.ResponseVO; -import cn.hamster3.application.blog.vo.user.UserInfoResponseVO; -import cn.hamster3.application.blog.vo.user.UserRegisterRequireVO; -import cn.hamster3.application.blog.vo.user.UserRegisterResponseVO; -import cn.hamster3.application.blog.vo.user.UserUpdateRequireVO; +import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO; +import cn.hamster3.application.blog.vo.user.*; import jakarta.annotation.Resource; import jakarta.validation.Valid; import org.springframework.http.MediaType; @@ -13,6 +11,7 @@ import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * 用户相关接口 @@ -23,14 +22,19 @@ public class UserController { @Resource private IUserService userService; + @PostMapping("/login") + public ResponseVO loginUser(@RequestBody @Valid UserLoginRequireVO requireVO) { + return userService.loginUser(requireVO); + } + @PostMapping("/") - public ResponseVO createUser(@RequestBody @Valid UserRegisterRequireVO requireVO) { - return userService.registerUser(requireVO); + public ResponseVO createUser(@RequestBody @Valid UserCreateRequireVO requireVO) { + return userService.createUser(requireVO); } @PutMapping("/") public ResponseVO updateUser(@RequestBody @Valid UserUpdateRequireVO requireVO) { - return ResponseVO.success(); + return userService.updateUser(requireVO); } @GetMapping("/") @@ -39,12 +43,12 @@ public class UserController { } @GetMapping("/{userID}/") - public ResponseVO getUserInfo(@PathVariable String userID) { - return ResponseVO.success(null); + public ResponseVO getUserInfo(@PathVariable UUID userID) { + return userService.getUserInfo(userID); } @GetMapping("/{userID}/attaches") - public ResponseVO getUserAttaches(@PathVariable String userID) { - return ResponseVO.success(null); + public ResponseVO> getUserAttaches(@PathVariable UUID userID) { + return userService.getUserAttaches(userID); } } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/dao/AttachRepository.java b/blog-backend/src/main/java/cn/hamster3/application/blog/dao/AttachRepository.java new file mode 100644 index 0000000..b6723d1 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/dao/AttachRepository.java @@ -0,0 +1,8 @@ +package cn.hamster3.application.blog.dao; + +import cn.hamster3.application.blog.entity.AttachEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface AttachRepository extends JpaRepository, JpaSpecificationExecutor { +} \ No newline at end of file diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/dao/UserRepository.java b/blog-backend/src/main/java/cn/hamster3/application/blog/dao/UserRepository.java index 819a507..929d35a 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/dao/UserRepository.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/dao/UserRepository.java @@ -10,10 +10,14 @@ import java.util.Optional; import java.util.UUID; public interface UserRepository extends JpaRepository, JpaSpecificationExecutor { + + @EntityGraph(attributePaths = {"permissions"}) + Optional findByEmailIgnoreCaseWithPermission(String email); + boolean existsByNicknameIgnoreCase(String nickname); boolean existsByEmailIgnoreCase(String email); - @EntityGraph(attributePaths = {"permissions"}) - Optional findByEmailOrNicknameAllIgnoreCase(String email, String nickname, Class type); + @EntityGraph(attributePaths = {"attachEntities"}) + UserEntity findByIdWithAttach(UUID uuid); } \ No newline at end of file diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/UserEntity.java b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/UserEntity.java index 9420b45..7a8e835 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/UserEntity.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/UserEntity.java @@ -1,7 +1,6 @@ package cn.hamster3.application.blog.entity; -import cn.hamster3.application.blog.constant.UserPermission; -import cn.hamster3.application.blog.constant.UserRole; +import cn.hamster3.application.blog.constant.UserPermissions; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @@ -36,19 +35,21 @@ public class UserEntity { @Column(name = "password", nullable = false, length = 32) private String password; + @Setter + @ToString.Exclude @ElementCollection @Column(name = "permission") @CollectionTable(name = "user_entity_permissions", joinColumns = @JoinColumn(name = "user_id")) - private Set permissions = new HashSet<>(); - - @Enumerated - @Column(name = "role", nullable = false) - private UserRole role; + private Set permissions = new HashSet<>(); + @Setter + @ToString.Exclude @OneToMany(mappedBy = "uploader", orphanRemoval = true) @OrderBy("create_time DESC") private List attachEntities = new ArrayList<>(); + @Setter + @ToString.Exclude @OneToMany(mappedBy = "uploader", orphanRemoval = true) @OrderBy("create_time DESC") private List blogEntities = new ArrayList<>(); diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/mapper/AttachMapper.java b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/mapper/AttachMapper.java new file mode 100644 index 0000000..f022084 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/mapper/AttachMapper.java @@ -0,0 +1,13 @@ +package cn.hamster3.application.blog.entity.mapper; + +import cn.hamster3.application.blog.entity.AttachEntity; +import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ReportingPolicy; + +@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = MappingConstants.ComponentModel.SPRING) +public interface AttachMapper { + AttachInfoResponseVO entityToInfoVO(AttachEntity entity); + +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/mapper/UserMapper.java b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/mapper/UserMapper.java index 7e1cc8f..eec436a 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/mapper/UserMapper.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/mapper/UserMapper.java @@ -1,16 +1,19 @@ package cn.hamster3.application.blog.entity.mapper; import cn.hamster3.application.blog.entity.UserEntity; +import cn.hamster3.application.blog.vo.user.UserCreateRequireVO; import cn.hamster3.application.blog.vo.user.UserInfoResponseVO; -import cn.hamster3.application.blog.vo.user.UserRegisterRequireVO; import cn.hamster3.application.blog.vo.user.UserRegisterResponseVO; +import cn.hamster3.application.blog.vo.user.UserUpdateRequireVO; import org.mapstruct.Mapper; import org.mapstruct.MappingConstants; import org.mapstruct.ReportingPolicy; @Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = MappingConstants.ComponentModel.SPRING) public interface UserMapper { - UserEntity voToEntity(UserRegisterRequireVO requireVO); + UserEntity voToEntity(UserCreateRequireVO requireVO); + + UserEntity voToEntity(UserUpdateRequireVO requireVO); UserInfoResponseVO entityToInfoVO(UserEntity requireVO); diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/service/IBlogService.java b/blog-backend/src/main/java/cn/hamster3/application/blog/service/IBlogService.java index 44daf59..9263df8 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/service/IBlogService.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/service/IBlogService.java @@ -2,7 +2,8 @@ package cn.hamster3.application.blog.service; import cn.hamster3.application.blog.vo.ResponseVO; import cn.hamster3.application.blog.vo.blog.BlogCreateRequireVO; +import org.jetbrains.annotations.NotNull; public interface IBlogService { - ResponseVO createBlog(BlogCreateRequireVO requireVO); + @NotNull ResponseVO createBlog(@NotNull BlogCreateRequireVO requireVO); } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/service/IUserService.java b/blog-backend/src/main/java/cn/hamster3/application/blog/service/IUserService.java index a5be873..f0fddde 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/service/IUserService.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/service/IUserService.java @@ -1,10 +1,22 @@ package cn.hamster3.application.blog.service; import cn.hamster3.application.blog.vo.ResponseVO; -import cn.hamster3.application.blog.vo.user.UserRegisterRequireVO; -import cn.hamster3.application.blog.vo.user.UserRegisterResponseVO; +import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO; +import cn.hamster3.application.blog.vo.user.*; import org.jetbrains.annotations.NotNull; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.List; +import java.util.UUID; public interface IUserService { - @NotNull ResponseVO registerUser(@NotNull UserRegisterRequireVO requireVO); + @NotNull ResponseVO loginUser(@NotNull UserLoginRequireVO requireVO); + + @NotNull ResponseVO createUser(@NotNull UserCreateRequireVO requireVO); + + @NotNull ResponseVO updateUser(@NotNull UserUpdateRequireVO requireVO); + + @NotNull ResponseVO getUserInfo(UUID id); + + @NotNull ResponseVO> getUserAttaches(@PathVariable UUID userID); } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/BlogService.java b/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/BlogService.java index 02acf4e..54dfd40 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/BlogService.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/BlogService.java @@ -7,6 +7,7 @@ import cn.hamster3.application.blog.service.IBlogService; import cn.hamster3.application.blog.vo.ResponseVO; import cn.hamster3.application.blog.vo.blog.BlogCreateRequireVO; import jakarta.annotation.Resource; +import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; @Service @@ -17,7 +18,7 @@ public class BlogService implements IBlogService { private BlogRepository blogRepo; @Override - public ResponseVO createBlog(BlogCreateRequireVO requireVO) { + public @NotNull ResponseVO createBlog(@NotNull BlogCreateRequireVO requireVO) { BlogEntity entity = blogMapper.voToEntity(requireVO); BlogEntity save = blogRepo.save(entity); return ResponseVO.success(save.getId()); diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/UserService.java b/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/UserService.java index 642ce62..a37231e 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/UserService.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/UserService.java @@ -1,28 +1,78 @@ package cn.hamster3.application.blog.service.impl; +import cn.hamster3.application.blog.config.security.BlogUser; +import cn.hamster3.application.blog.constant.UserPermissions; import cn.hamster3.application.blog.dao.UserRepository; import cn.hamster3.application.blog.entity.UserEntity; +import cn.hamster3.application.blog.entity.mapper.AttachMapper; import cn.hamster3.application.blog.entity.mapper.UserMapper; import cn.hamster3.application.blog.service.IUserService; import cn.hamster3.application.blog.vo.ResponseVO; -import cn.hamster3.application.blog.vo.user.UserRegisterRequireVO; -import cn.hamster3.application.blog.vo.user.UserRegisterResponseVO; +import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO; +import cn.hamster3.application.blog.vo.user.*; import jakarta.annotation.Resource; import org.jetbrains.annotations.NotNull; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.List; +import java.util.UUID; @Service public class UserService implements IUserService { @Resource private PasswordEncoder passwordEncoder; + @Resource private UserMapper userMapper; + @Resource + private AttachMapper attachMapper; + @Resource private UserRepository userRepo; + + @Resource + private AuthenticationManager authenticationManager; + @Override - public @NotNull ResponseVO registerUser(@NotNull UserRegisterRequireVO requireVO) { + public @NotNull ResponseVO loginUser(@NotNull UserLoginRequireVO requireVO) { + UserEntity userEntity = userRepo.findByEmailIgnoreCaseWithPermission(requireVO.getEmail()).orElse(null); + if (userEntity == null) { + return ResponseVO.failed("未找到该邮箱!"); + } + if (!passwordEncoder.matches(requireVO.getPassword(), userEntity.getPassword())) { + return ResponseVO.failed("密码错误!"); + } + + List userPermissions = userEntity.getPermissions().stream() + .map(UserPermissions::getAuthority) + .toList(); + + BlogUser blogUser = new BlogUser( + userEntity.getEmail(), + userEntity.getPassword(), + userPermissions, + userEntity.getId() + ); + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( + blogUser, + requireVO.getPassword(), + blogUser.getAuthorities() + ); + authenticationManager.authenticate(token); + SecurityContextHolder.getContext().setAuthentication(token); + return ResponseVO.success(); + } + + @Override + public @NotNull ResponseVO createUser(@NotNull UserCreateRequireVO requireVO) { UserEntity entity = userMapper.voToEntity(requireVO); entity.setEmail(entity.getEmail().toLowerCase()); @@ -39,4 +89,69 @@ public class UserService implements IUserService { return ResponseVO.success("注册成功!", userMapper.entityToRegisterVO(save)); } + + @Override + public @NotNull ResponseVO updateUser(@NotNull UserUpdateRequireVO requireVO) { + UserEntity userEntity = userRepo.findById(requireVO.getId()).orElse(null); + if (userEntity == null) { + return ResponseVO.failed("未找到该用户!"); + } + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + return ResponseVO.failed("你没有这个权限!"); + } + + BlogUser blogUser = (BlogUser) authentication.getPrincipal(); + if (!blogUser.getUuid().equals(userEntity.getId()) + && blogUser.getAuthorities().contains(UserPermissions.MODIFY_USER_INFO.getAuthority())) { + return ResponseVO.failed("你没有这个权限!"); + } + + if (requireVO.getEmail() != null) { + if (userRepo.existsByEmailIgnoreCase(requireVO.getEmail())) { + return ResponseVO.failed("已存在相同邮箱的账户!"); + } + userEntity.setEmail(requireVO.getEmail().toLowerCase()); + } + if (requireVO.getNickname() != null) { + if (userRepo.existsByNicknameIgnoreCase(requireVO.getNickname())) { + return ResponseVO.failed("已存在相同的用户昵称!"); + } + userEntity.setNickname(requireVO.getNickname()); + } + if (requireVO.getPassword() != null) { + userEntity.setPassword(passwordEncoder.encode(requireVO.getPassword())); + } + + if (requireVO.getPermissions() != null) { + if (!blogUser.getAuthorities().contains(UserPermissions.MODIFY_USER_PERMISSION.getAuthority())) { + return ResponseVO.failed("你没有这个权限!"); + } + // 用户必须具有 MODIFY_USER_PERMISSION 权限,且操作对象不为用户自己时才能更改权限 + if (blogUser.getUuid().equals(userEntity.getId())) { + return ResponseVO.failed("你不能更改自己的权限!"); + } + userEntity.setPermissions(requireVO.getPermissions()); + } + return ResponseVO.success(); + } + + @Override + public @NotNull ResponseVO getUserInfo(UUID id) { + return userRepo.findById(id) + .map(o -> ResponseVO.success(userMapper.entityToInfoVO(o))) + .orElse(ResponseVO.failed("未找到该用户!")); + } + + @Override + public @NotNull ResponseVO> getUserAttaches(@PathVariable UUID userID) { + UserEntity userEntity = userRepo.findByIdWithAttach(userID); + if (userEntity == null) { + return ResponseVO.failed("未找到该用户!"); + } + List list = userEntity.getAttachEntities() + .stream().map(o -> attachMapper.entityToInfoVO(o)) + .toList(); + return ResponseVO.success(list); + } } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/ResponseVO.java b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/ResponseVO.java index 10f4ca9..ed0796b 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/ResponseVO.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/ResponseVO.java @@ -5,6 +5,9 @@ import lombok.Data; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.PrintWriter; +import java.io.StringWriter; + @Data @AllArgsConstructor public class ResponseVO { @@ -31,4 +34,11 @@ public class ResponseVO { return new ResponseVO<>(403, msg, null); } + public static ResponseVO failed(Exception e) { + StringWriter writer = new StringWriter(); + e.printStackTrace(new PrintWriter(writer)); + // StringWriter 不需要 close() + return new ResponseVO<>(403, e.getMessage(), writer.toString()); + } + } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/attach/AttachInfoResponseVO.java b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/attach/AttachInfoResponseVO.java new file mode 100644 index 0000000..79f9e20 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/attach/AttachInfoResponseVO.java @@ -0,0 +1,14 @@ +package cn.hamster3.application.blog.vo.attach; + +import lombok.Data; + +import java.util.Date; +import java.util.UUID; + +@Data +public class AttachInfoResponseVO { + private Long id; + private UUID uploader; + private Date createTime; + private Date updateTime; +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterRequireVO.java b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserCreateRequireVO.java similarity index 94% rename from blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterRequireVO.java rename to blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserCreateRequireVO.java index 4db82de..9b6e8bc 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterRequireVO.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserCreateRequireVO.java @@ -7,7 +7,7 @@ import lombok.Data; @Data @AllArgsConstructor -public class UserRegisterRequireVO { +public class UserCreateRequireVO { @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱配置不合法!") private String email; @Size(min = 3, max = 16, message = "用户昵称必须包含 3~16 个字符!") diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserInfoResponseVO.java b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserInfoResponseVO.java index c7fd54c..9a32163 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserInfoResponseVO.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserInfoResponseVO.java @@ -1,4 +1,14 @@ package cn.hamster3.application.blog.vo.user; +import cn.hamster3.application.blog.constant.UserPermissions; + +import java.util.Set; +import java.util.UUID; + public class UserInfoResponseVO { + private UUID id; + private String email; + private String nickname; + private String password; + private Set permissions; } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserLoginRequireVO.java b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserLoginRequireVO.java new file mode 100644 index 0000000..9f261d7 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserLoginRequireVO.java @@ -0,0 +1,15 @@ +package cn.hamster3.application.blog.vo.user; + +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class UserLoginRequireVO { + @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱不合法!") + private String email; + @Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!") + private String password; +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterResponseVO.java b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterResponseVO.java index 248dc68..d5cc5ac 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterResponseVO.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterResponseVO.java @@ -1,6 +1,6 @@ package cn.hamster3.application.blog.vo.user; -import cn.hamster3.application.blog.constant.UserPermission; +import cn.hamster3.application.blog.constant.UserPermissions; import lombok.AllArgsConstructor; import lombok.Data; @@ -14,7 +14,7 @@ public class UserRegisterResponseVO { private UUID id; private String email; private String nickname; - private List permissions; + private List permissions; private Date createTime; private Date updateTime; } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserUpdateRequireVO.java b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserUpdateRequireVO.java index d73eba2..95e85ce 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserUpdateRequireVO.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserUpdateRequireVO.java @@ -1,4 +1,23 @@ package cn.hamster3.application.blog.vo.user; +import cn.hamster3.application.blog.constant.UserPermissions; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.util.Set; +import java.util.UUID; + +@Data public class UserUpdateRequireVO { + @NotNull(message = "用户id不能为空!") + private UUID id; + @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱配置不合法!") + private String email; + @Size(min = 3, max = 16, message = "用户昵称必须包含 3~16 个字符!") + private String nickname; + @Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!") + private String password; + private Set permissions; }