From eaf234d06231ab3c338a98072873a9edde43932e Mon Sep 17 00:00:00 2001 From: MiniDay <372403923@qq.com> Date: Fri, 31 Mar 2023 15:22:02 +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 --- .../blog/config/AuthTokenFilter.java | 49 +++++++++++++++++++ .../application/blog/config/WebConfig.java | 24 ++++----- .../security/BlogUserDetailService.java | 7 +-- .../blog/config/security/SecurityConfig.java | 1 - .../blog/controller/UserController.java | 5 +- .../blog/service/IUserService.java | 3 +- .../blog/service/impl/UserService.java | 22 ++++++++- .../application/blog/util/BlogUtils.java | 6 ++- .../application/blog/vo/ResponseVO.java | 2 + blog-frontend/index.html | 2 +- blog-frontend/src/App.vue | 17 ++----- blog-frontend/src/router/index.ts | 5 ++ blog-frontend/src/views/LoginView.vue | 6 +-- blog-frontend/src/views/TagsView.vue | 13 +++++ 14 files changed, 123 insertions(+), 39 deletions(-) create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/config/AuthTokenFilter.java create mode 100644 blog-frontend/src/views/TagsView.vue diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/AuthTokenFilter.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/AuthTokenFilter.java new file mode 100644 index 0000000..7e1ea07 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/AuthTokenFilter.java @@ -0,0 +1,49 @@ +package cn.hamster3.application.blog.config; + +import jakarta.annotation.Resource; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.springframework.cache.Cache; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +@Slf4j +@Component +public class AuthTokenFilter extends OncePerRequestFilter { + @Resource(name = "userCache") + private Cache userCache; + + public AuthTokenFilter() { + } + + @Override + protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException { + String token = request.getHeader("token"); + log.info("request token: {}", token); + if (token == null || token.isBlank()) { + filterChain.doFilter(request, response); + return; + } + UserDetails user = userCache.get(token, UserDetails.class); + if (user == null) { + filterChain.doFilter(request, response); + return; + } + SecurityContext context = SecurityContextHolder.getContext(); + UsernamePasswordAuthenticationToken authentication = UsernamePasswordAuthenticationToken.authenticated( + user, "", user.getAuthorities() + ); + context.setAuthentication(authentication); + filterChain.doFilter(request, response); + } +} 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 388c743..7ec8fd9 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,13 +1,10 @@ package cn.hamster3.application.blog.config; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.annotation.Resource; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cache.Cache; import org.springframework.cache.concurrent.ConcurrentMapCache; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; @@ -21,6 +18,11 @@ public class WebConfig { @Resource private UserDetailsService userDetailsService; + @Bean(name = "userCache") + public Cache getUserCache() { + return new ConcurrentMapCache("user-cache"); + } + @Bean public PasswordEncoder getPasswordEncoder() { return new BCryptPasswordEncoder(5); @@ -35,12 +37,12 @@ public class WebConfig { return new ProviderManager(provider); } - @Bean - @ConditionalOnMissingBean(ObjectMapper.class) - public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { - ObjectMapper objectMapper = builder.createXmlMapper(false).build(); - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - return objectMapper; - } +// @Bean +// @ConditionalOnMissingBean(ObjectMapper.class) +// public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { +// ObjectMapper objectMapper = builder.createXmlMapper(false).build(); +// objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); +// return objectMapper; +// } } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogUserDetailService.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogUserDetailService.java index fbc4eff..e9a5f47 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogUserDetailService.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/BlogUserDetailService.java @@ -2,23 +2,20 @@ package cn.hamster3.application.blog.config.security; import cn.hamster3.application.blog.entity.repo.UserRepository; import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; import java.util.Collections; -@Slf4j -@Component +@Service public class BlogUserDetailService implements UserDetailsService { @Resource private UserRepository userRepo; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - log.info("find user by email: {}", username); return userRepo.findByEmailIgnoreCase(username) .map(user -> new BlogUser( user.getEmail(), diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfig.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfig.java index a1d118e..5dc6e5c 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfig.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfig.java @@ -21,7 +21,6 @@ public class SecurityConfig { .anyRequest().authenticated()) .cors().and() .csrf().disable() - .formLogin().and() .httpBasic().and() .build(); } 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 0e65e19..b983699 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 @@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.data.domain.PageRequest; import org.springframework.http.MediaType; @@ -29,8 +30,8 @@ public class UserController { @PostMapping("/login") @Operation(summary = "登录用户") - public ResponseVO loginUser(@RequestBody @Valid UserLoginRequireVO requireVO) { - return userService.loginUser(requireVO); + public ResponseVO loginUser(@RequestBody @Valid UserLoginRequireVO requireVO, HttpServletResponse response) { + return userService.loginUser(requireVO, response); } @GetMapping("/current") 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 b55dba8..eb4293e 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 @@ -8,13 +8,14 @@ import cn.hamster3.application.blog.vo.user.UserCreateRequireVO; import cn.hamster3.application.blog.vo.user.UserInfoResponseVO; import cn.hamster3.application.blog.vo.user.UserLoginRequireVO; import cn.hamster3.application.blog.vo.user.UserUpdateRequireVO; +import jakarta.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Pageable; import java.util.UUID; public interface IUserService { - @NotNull ResponseVO loginUser(@NotNull UserLoginRequireVO requireVO); + @NotNull ResponseVO loginUser(@NotNull UserLoginRequireVO requireVO, @NotNull HttpServletResponse response); @NotNull ResponseVO getCurrentUserInfo(); 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 658a6ba..8f9bb0f 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 @@ -20,9 +20,14 @@ import cn.hamster3.application.blog.vo.user.UserInfoResponseVO; import cn.hamster3.application.blog.vo.user.UserLoginRequireVO; import cn.hamster3.application.blog.vo.user.UserUpdateRequireVO; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; +import org.springframework.cache.Cache; 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.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @@ -48,8 +53,23 @@ public class UserService implements IUserService { @Resource private AttachRepository attachRepo; + @Resource(name = "userCache") + private Cache userCache; + @Resource + private AuthenticationManager authenticationManager; + @Override - public @NotNull ResponseVO loginUser(@NotNull UserLoginRequireVO requireVO) { + public @NotNull ResponseVO loginUser(@NotNull UserLoginRequireVO requireVO, @NotNull HttpServletResponse response) { + Authentication authenticate = authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken(requireVO.getEmail(), requireVO.getPassword()) + ); + log.info("authenticate: {}", authenticate); + if (!authenticate.isAuthenticated()) { + return ResponseVO.failed("login failed."); + } + UUID uuid = UUID.randomUUID(); + userCache.put(uuid.toString(), authenticate.getPrincipal()); + response.addHeader("token", uuid.toString()); return ResponseVO.success(); } 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 index 8a3eddd..3d3b6b7 100644 --- 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 @@ -14,7 +14,7 @@ import java.util.UUID; @Slf4j public class BlogUtils { - @NotNull + @Nullable public static Authentication getCurrentAuthentication() { return SecurityContextHolder.getContext().getAuthentication(); } @@ -23,6 +23,10 @@ public class BlogUtils { public static Optional getCurrentUser() { Authentication authentication = getCurrentAuthentication(); log.info("=============================="); + if (authentication == null) { + log.info("current user authentication: null"); + return Optional.empty(); + } log.info("current user authentication: {}", authentication); log.info("current user authentication getPrincipal: {}", authentication.getPrincipal()); log.info("current user authentication getCredentials: {}", authentication.getCredentials()); 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 475fe79..b23c9dd 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 @@ -1,5 +1,6 @@ package cn.hamster3.application.blog.vo; +import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import org.jetbrains.annotations.NotNull; @@ -7,6 +8,7 @@ import org.jetbrains.annotations.Nullable; @Data @AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) public class ResponseVO { @NotNull private Integer code; diff --git a/blog-frontend/index.html b/blog-frontend/index.html index 1743805..b2514fd 100644 --- a/blog-frontend/index.html +++ b/blog-frontend/index.html @@ -6,7 +6,7 @@ - Vite App + 网站标题 diff --git a/blog-frontend/src/App.vue b/blog-frontend/src/App.vue index e3ab6a1..2501eb9 100644 --- a/blog-frontend/src/App.vue +++ b/blog-frontend/src/App.vue @@ -3,7 +3,7 @@ import { ref, onMounted } from 'vue'; import { RouterLink, RouterView } from 'vue-router' import { SettingControllerApiFactory, UserControllerApiFactory, UserInfoResponseVORoleEnum, type UserInfoResponseVO } from '@/api-base'; -let title = ref() +let title = ref("网站标题") let navigationMenu = ref([{ url: "/about", text: "关于我" @@ -14,10 +14,9 @@ onMounted(() => { SettingControllerApiFactory().getSettingContent("site.title") .then(response => { let vo = response.data; - title.value = vo.data ?? "网站标题" - }) - .catch(err => { - console.error(err); + let siteTitle: string = vo.data ?? "网站标题" + title.value = siteTitle + document.title = siteTitle }) SettingControllerApiFactory().getSettingContent("site.navigation.menus") @@ -28,14 +27,6 @@ onMounted(() => { navigationMenu.value = navigationMenuObject } }) - - UserControllerApiFactory().getCurrentUserInfo() - .then(response => { - let vo = response.data; - if (vo.code === 200) { - console.log(vo.data); - } - }) }); diff --git a/blog-frontend/src/router/index.ts b/blog-frontend/src/router/index.ts index 6be8fa6..e647556 100644 --- a/blog-frontend/src/router/index.ts +++ b/blog-frontend/src/router/index.ts @@ -13,6 +13,11 @@ const router = createRouter({ name: 'register', component: () => import('@/views/RegisterView.vue') }, + { + path: '/tags', + name: 'tags', + component: () => import('@/views/TagsView.vue') + }, { path: '/login', name: 'login', diff --git a/blog-frontend/src/views/LoginView.vue b/blog-frontend/src/views/LoginView.vue index 107866a..e670975 100644 --- a/blog-frontend/src/views/LoginView.vue +++ b/blog-frontend/src/views/LoginView.vue @@ -2,6 +2,7 @@ import { UserControllerApiFactory } from '@/api-base'; import type UserLoginRequireVO from '@/api-base'; import { reactive } from 'vue'; + const form = reactive({ email: '', password: '' @@ -13,15 +14,14 @@ const onSubmit = () => { let vo = resp.data; if (vo.data === 200) { console.log('login success!') - }else{ - + } else { + console.log('login failed!') } }) }