From 3e20794048c2a520aa17f845b0ae2a84a8db5622 Mon Sep 17 00:00:00 2001 From: MiniDay <372403923@qq.com> Date: Mon, 27 Mar 2023 19:08:01 +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 --- .../BlogExceptionHandler.java} | 10 ++- .../application/blog/config/WebConfig.java | 64 +++++++++++++------ .../security/BlogAuthenticationManager.java | 31 --------- ...ceImpl.java => BlogUserDetailService.java} | 2 +- ...figuration.java => DevSecurityConfig.java} | 2 +- ...Configuration.java => SecurityConfig.java} | 2 +- .../blog/controller/AttachController.java | 2 +- .../blog/controller/UserController.java | 12 ++-- .../blog/service/IUserService.java | 2 +- .../blog/service/impl/BlogService.java | 6 ++ .../blog/service/impl/UserService.java | 41 +++++------- .../application/blog/util/BlogUtils.java | 41 ++++++++++++ .../blog/vo/blog/BlogCreateRequireVO.java | 2 + .../blog/vo/user/UserLoginRequireVO.java | 2 + 14 files changed, 128 insertions(+), 91 deletions(-) rename blog-backend/src/main/java/cn/hamster3/application/blog/{controller/ExceptionController.java => config/BlogExceptionHandler.java} (73%) delete mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogAuthenticationManager.java rename blog-backend/src/main/java/cn/hamster3/application/blog/config/security/{UserDetailServiceImpl.java => BlogUserDetailService.java} (95%) rename blog-backend/src/main/java/cn/hamster3/application/blog/config/security/{DevSecurityConfiguration.java => DevSecurityConfig.java} (97%) rename blog-backend/src/main/java/cn/hamster3/application/blog/config/security/{SecurityConfiguration.java => SecurityConfig.java} (97%) create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/util/BlogUtils.java 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/config/BlogExceptionHandler.java similarity index 73% rename from blog-backend/src/main/java/cn/hamster3/application/blog/controller/ExceptionController.java rename to blog-backend/src/main/java/cn/hamster3/application/blog/config/BlogExceptionHandler.java index 3e8b62f..613af16 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/ExceptionController.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/BlogExceptionHandler.java @@ -1,9 +1,10 @@ -package cn.hamster3.application.blog.controller; +package cn.hamster3.application.blog.config; import cn.hamster3.application.blog.vo.ResponseVO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.core.env.Environment; +import org.springframework.security.authentication.BadCredentialsException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -12,10 +13,15 @@ import java.io.StringWriter; @Slf4j @RestControllerAdvice -public class ExceptionController { +public class BlogExceptionHandler { @Resource private Environment environment; + @ExceptionHandler(BadCredentialsException.class) + public ResponseVO onException(BadCredentialsException e) { + return ResponseVO.failed(e.getMessage()); + } + @ExceptionHandler(Exception.class) public ResponseVO onException(Exception e) { log.error("", e); 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 83b292f..5f6eebd 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,19 +1,26 @@ package cn.hamster3.application.blog.config; -import cn.hamster3.application.blog.config.security.BlogUser; +import cn.hamster3.application.blog.util.BlogUtils; +import jakarta.annotation.Resource; +import org.springframework.cache.concurrent.ConcurrentMapCache; 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.authentication.AuthenticationManager; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.cache.SpringCacheBasedUserCache; 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 { + @Resource + private UserDetailsService userDetailsService; + @Bean public PasswordEncoder getPasswordEncoder() { return new BCryptPasswordEncoder(5); @@ -21,23 +28,38 @@ public class WebConfig { @Bean public AuditorAware getUserIDAuditorAware() { - return () -> { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null || !authentication.isAuthenticated()) { - return Optional.empty(); - } - System.out.println("getUserIDAuditorAware"); - System.out.println(authentication.getName()); - System.out.println(authentication.getPrincipal()); - System.out.println(authentication.getCredentials()); - System.out.println(authentication.getDetails()); - System.out.println(authentication.getAuthorities()); - Object userDetails = authentication.getDetails(); - if (userDetails instanceof BlogUser user) { - return Optional.of(user.getUuid()); - } - return Optional.empty(); - }; + return BlogUtils::currentUserUUID; } + @Bean + public AuthenticationManager getAuthenticationManager() { + DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setPasswordEncoder(getPasswordEncoder()); + provider.setUserDetailsService(userDetailsService); + provider.setUserCache(new SpringCacheBasedUserCache(new ConcurrentMapCache("user-cache"))); + return new ProviderManager(provider); + } + +// @Bean +// public AuthenticationManager getAuthenticationManager() { +// return new AuthenticationManager() { +// @Resource +// private UserDetailsService userDetailsService; +// +// @Override +// public Authentication authenticate(Authentication authentication) throws AuthenticationException { +// if (!(authentication instanceof UsernamePasswordAuthenticationToken)) { +// throw new IllegalArgumentException("BlogAuthenticationManager only support UsernamePasswordAuthenticationToken!"); +// } +// UserDetails user = userDetailsService.loadUserByUsername((String) authentication.getPrincipal()); +// UsernamePasswordAuthenticationToken authenticated = UsernamePasswordAuthenticationToken.authenticated( +// authentication.getPrincipal(), +// authentication.getCredentials(), +// user.getAuthorities() +// ); +// authenticated.setDetails(user); +// return authenticated; +// } +// }; +// } } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogAuthenticationManager.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogAuthenticationManager.java deleted file mode 100644 index 3cfe4a5..0000000 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogAuthenticationManager.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.hamster3.application.blog.config.security; - -import jakarta.annotation.Resource; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.stereotype.Component; - -@Component -public class BlogAuthenticationManager implements AuthenticationManager { - @Resource - private UserDetailsService userDetailsService; - - @Override - public Authentication authenticate(Authentication authentication) throws AuthenticationException { - if (!(authentication instanceof UsernamePasswordAuthenticationToken)) { - throw new IllegalArgumentException("BlogAuthenticationManager only support UsernamePasswordAuthenticationToken!"); - } - UserDetails user = userDetailsService.loadUserByUsername((String) authentication.getPrincipal()); - UsernamePasswordAuthenticationToken authenticated = UsernamePasswordAuthenticationToken.authenticated( - authentication.getPrincipal(), - authentication.getCredentials(), - user.getAuthorities() - ); - authenticated.setDetails(user); - return authenticated; - } -} \ No newline at end of file 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/BlogUserDetailService.java similarity index 95% rename from blog-backend/src/main/java/cn/hamster3/application/blog/config/security/UserDetailServiceImpl.java rename to blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogUserDetailService.java index fc9ced1..db4eb96 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/BlogUserDetailService.java @@ -11,7 +11,7 @@ import org.springframework.stereotype.Component; @Slf4j @Component -public class UserDetailServiceImpl implements UserDetailsService { +public class BlogUserDetailService implements UserDetailsService { @Resource private UserRepository userRepo; 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/DevSecurityConfig.java similarity index 97% rename from blog-backend/src/main/java/cn/hamster3/application/blog/config/security/DevSecurityConfiguration.java rename to blog-backend/src/main/java/cn/hamster3/application/blog/config/security/DevSecurityConfig.java index a13a44c..0f93a74 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/DevSecurityConfig.java @@ -11,7 +11,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @Profile("dev") -public class DevSecurityConfiguration { +public class DevSecurityConfig { @Bean public SecurityFilterChain getSecurityFilterChain(HttpSecurity http) throws Exception { return http.authorizeHttpRequests(request -> request diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfiguration.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfig.java similarity index 97% rename from blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfiguration.java rename to blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfig.java index b0f2cb8..096130e 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfiguration.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfig.java @@ -9,7 +9,7 @@ import org.springframework.security.web.SecurityFilterChain; @Configuration @Profile("prod") -public class SecurityConfiguration { +public class SecurityConfig { @Bean public SecurityFilterChain getSecurityFilterChain(HttpSecurity http) throws Exception { return http.authorizeHttpRequests(request -> request diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/AttachController.java b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/AttachController.java index 69ea09e..4f7c032 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/AttachController.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/AttachController.java @@ -21,7 +21,7 @@ public class AttachController { } @GetMapping("/{attachID}/") - public ResponseVO getAttach() { + public ResponseVO getAttach(@PathVariable String attachID) { return ResponseVO.success(); } 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 95d5321..a1b513b 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 @@ -23,14 +23,14 @@ public class UserController { @Resource private IUserService userService; - @PostMapping("/login") - public ResponseVO loginUser(@RequestBody @Valid UserLoginRequireVO requireVO) { - return userService.loginUser(requireVO); - } +// @PostMapping("/login") +// public ResponseVO loginUser(@RequestBody @Valid UserLoginRequireVO requireVO) { +// return userService.loginUser(requireVO); +// } @GetMapping("/current") - public ResponseVO currentUser() { - return userService.currentUser(); + public ResponseVO getCurrentUserInfo() { + return userService.getCurrentUserInfo(); } @PostMapping("/") 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 fab5ef9..92d7529 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 @@ -14,7 +14,7 @@ import java.util.UUID; public interface IUserService { @NotNull ResponseVO loginUser(@NotNull UserLoginRequireVO requireVO); - @NotNull ResponseVO currentUser(); + @NotNull ResponseVO getCurrentUserInfo(); @NotNull ResponseVO createUser(@NotNull UserCreateRequireVO requireVO); 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 bd8d8b5..2e5b57b 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 @@ -1,9 +1,11 @@ package cn.hamster3.application.blog.service.impl; +import cn.hamster3.application.blog.config.security.BlogUser; import cn.hamster3.application.blog.dao.BlogRepository; import cn.hamster3.application.blog.entity.BlogEntity; import cn.hamster3.application.blog.entity.mapper.BlogMapper; import cn.hamster3.application.blog.service.IBlogService; +import cn.hamster3.application.blog.util.BlogUtils; import cn.hamster3.application.blog.vo.ResponseVO; import cn.hamster3.application.blog.vo.blog.BlogCreateRequireVO; import cn.hamster3.application.blog.vo.blog.BlogInfoResponseVO; @@ -23,6 +25,10 @@ public class BlogService implements IBlogService { @Override public @NotNull ResponseVO createBlog(@NotNull BlogCreateRequireVO requireVO) { + BlogUser user = BlogUtils.currentUser().orElse(null); + if (user == null) { + return ResponseVO.failed("not login."); + } 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 6f3b16d..83e9c23 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 @@ -7,6 +7,7 @@ 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.util.BlogUtils; import cn.hamster3.application.blog.vo.PageableResponseVO; import cn.hamster3.application.blog.vo.ResponseVO; import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO; @@ -15,8 +16,6 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Pageable; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; @@ -40,32 +39,22 @@ public class UserService implements IUserService { @Resource private UserRepository userRepo; - - @Resource - private AuthenticationManager authenticationManager; - @Override public @NotNull ResponseVO loginUser(@NotNull UserLoginRequireVO requireVO) { - Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken( - requireVO.getEmail(), - requireVO.getPassword() - )); - SecurityContextHolder.getContext().setAuthentication(authenticate); return ResponseVO.success(); } @Override - public @NotNull ResponseVO currentUser() { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - Object userDetails = authentication.getDetails(); - if (userDetails instanceof BlogUser user) { - return ResponseVO.success( - userRepo.findById(user.getUuid()) - .map(o -> userMapper.entityToInfoVO(o)) - .orElse(null) - ); + public @NotNull ResponseVO getCurrentUserInfo() { + UUID uuid = BlogUtils.currentUserUUID().orElse(null); + if (uuid == null) { + return ResponseVO.failed("not login."); } - return ResponseVO.failed("not login."); + return ResponseVO.success( + userRepo.findById(uuid) + .map(o -> userMapper.entityToInfoVO(o)) + .orElse(null) + ); } @Override @@ -98,20 +87,20 @@ public class UserService implements IUserService { if (authentication == null) { return ResponseVO.failed("你没有这个权限!"); } - - BlogUser blogUser = (BlogUser) authentication.getPrincipal(); + if (!(authentication.getPrincipal() instanceof BlogUser blogUser)) { + return ResponseVO.failed("你没有这个权限!"); + } if (!blogUser.getUuid().equals(userEntity.getId()) && blogUser.getAuthorities().contains(UserPermissions.MODIFY_USER_INFO.getAuthority())) { return ResponseVO.failed("你没有这个权限!"); } - - if (requireVO.getEmail() != null) { + if (requireVO.getEmail() != null && !requireVO.getEmail().equals(userEntity.getEmail())) { if (userRepo.existsByEmailIgnoreCase(requireVO.getEmail())) { return ResponseVO.failed("已存在相同邮箱的账户!"); } userEntity.setEmail(requireVO.getEmail().toLowerCase()); } - if (requireVO.getNickname() != null) { + if (requireVO.getNickname() != null && !requireVO.getNickname().equals(userEntity.getNickname())) { if (userRepo.existsByNicknameIgnoreCase(requireVO.getNickname())) { return ResponseVO.failed("已存在相同的用户昵称!"); } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/util/BlogUtils.java b/blog-backend/src/main/java/cn/hamster3/application/blog/util/BlogUtils.java new file mode 100644 index 0000000..fcba7a2 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/util/BlogUtils.java @@ -0,0 +1,41 @@ +package cn.hamster3.application.blog.util; + +import cn.hamster3.application.blog.config.security.BlogUser; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.Optional; +import java.util.UUID; + +@Slf4j +public class BlogUtils { + @NotNull + public static Optional currentUser() { + SecurityContext context = SecurityContextHolder.getContext(); + Authentication authentication = context.getAuthentication(); + if (authentication == null) { + return Optional.empty(); + } + log.info("=============================="); + log.info("current user authentication: {}", authentication); + log.info("current user authentication getPrincipal: {}", authentication.getPrincipal()); + log.info("current user authentication getCredentials: {}", authentication.getCredentials()); + log.info("current user authentication getDetails: {}", authentication.getDetails()); + log.info("current user authentication getAuthorities: {}", authentication.getAuthorities()); + if (!authentication.isAuthenticated()) { + return Optional.empty(); + } + if (!(authentication.getPrincipal() instanceof BlogUser user)) { + return Optional.empty(); + } + return Optional.of(user); + } + + @NotNull + public static Optional currentUserUUID() { + return currentUser().map(BlogUser::getUuid); + } +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/blog/BlogCreateRequireVO.java b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/blog/BlogCreateRequireVO.java index 7853aa4..ab3483a 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/blog/BlogCreateRequireVO.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/blog/BlogCreateRequireVO.java @@ -4,9 +4,11 @@ package cn.hamster3.application.blog.vo.blog; import jakarta.annotation.Nullable; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Data; @Data +@AllArgsConstructor public class BlogCreateRequireVO { @Nullable @Max(value = 16, message = "密码最大长度不能超过 16 个字!") 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 index fa9e9a4..3dd46fa 100644 --- 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 @@ -1,5 +1,6 @@ package cn.hamster3.application.blog.vo.user; +import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; import lombok.Data; @@ -7,6 +8,7 @@ import lombok.Data; @Data public class UserLoginRequireVO { @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱不合法!") + @Max(value = 32, message = "邮箱长度不能超过 32 个字符!") private String email; @Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!") private String password;