Преглед на файлове

account 模块和 myblog 项目对齐

reghao преди 2 години
родител
ревизия
3240bf4745

+ 28 - 0
manager/src/main/java/cn/reghao/devops/manager/account/security/ExceptionAuthenticationEntryPoint.java

@@ -0,0 +1,28 @@
+package cn.reghao.devops.manager.account.security;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 在 WebSecurityConfig 中配置的需要认证的接口没有获取到请求中的认证信息时会转到此处进行处理
+ *
+ * @author reghao
+ * @date 2023-07-28 16:43:59
+ */
+@Slf4j
+public class ExceptionAuthenticationEntryPoint implements AuthenticationEntryPoint {
+    @Override
+    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
+            throws IOException, ServletException {
+        String uri = request.getRequestURI();
+        log.error("请求 {} 接口认证失败...", uri);
+        String body = String.format("%s, %s need authenticate", exception.getMessage(), uri);
+        response.sendRedirect("/login");
+    }
+}

+ 52 - 36
manager/src/main/java/cn/reghao/devops/manager/account/security/WebSecurityConfig.java

@@ -11,17 +11,21 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.security.access.expression.SecurityExpressionHandler;
 import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
 import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
+import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.builders.WebSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
 import org.springframework.security.web.FilterInvocation;
 import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
 import org.springframework.security.web.context.SecurityContextPersistenceFilter;
 
 /**
@@ -34,19 +38,26 @@ import org.springframework.security.web.context.SecurityContextPersistenceFilter
 @EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled = true) // 调用方法时检查权限
 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+    private final String loginPage = "/login";
     private final String loginApi = "/login";
+    private final String logoutApi = "/logout";
 
     private final AccountAuthProvider userAuthProvider;
     private final AccountAuthService accountAuthService;
     private final AuthenticationSuccessHandler successHandler;
     private final AuthenticationFailureHandler failureHandler;
+    private final LogoutHandler logoutHandler;
+    private final LogoutSuccessHandler logoutSuccessHandler;
 
     public WebSecurityConfig(AccountAuthProvider userAuthProvider, AccountAuthService accountAuthService,
-                             AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler) {
+                             AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler,
+                             LogoutHandler logoutHandler, LogoutSuccessHandler logoutSuccessHandler) {
         this.userAuthProvider = userAuthProvider;
         this.accountAuthService = accountAuthService;
         this.successHandler = successHandler;
         this.failureHandler = failureHandler;
+        this.logoutHandler = logoutHandler;
+        this.logoutSuccessHandler = logoutSuccessHandler;
     }
 
     /**
@@ -69,35 +80,37 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
     @Override
     protected void configure(HttpSecurity http) throws Exception {
         http.authorizeRequests()
-                .expressionHandler(webExpressionHandler())
                 .antMatchers("/login").permitAll()
-                // TODO 处理 WebSocket 的认证
-                .antMatchers("/webssh").permitAll()
                 // 放行所有以 /api 为前缀的请求
-                .antMatchers("/api/**").permitAll()
+                //.antMatchers("/api/**").permitAll()
                 .anyRequest().authenticated();
-        http.exceptionHandling().accessDeniedPage("/deny");
 
-        // 处理 X-Frame-Options header
-        http.headers().frameOptions().sameOrigin();
-
-        // 在 UsernamePasswordAuthenticationFilter 后添加 filter
+        // 配置 FilterChainProxy 过滤器链
         http.addFilterAfter(new LoginRedirectFilter(), SecurityContextPersistenceFilter.class);
         http.addFilterBefore(accountAuthFilter(), UsernamePasswordAuthenticationFilter.class);
 
-        // 基于表单的认证
-        http.formLogin()
-                // 登录页面(GET 请求)
-                .loginPage("/login")
-                // 登录接口(POST 请求)
-                .loginProcessingUrl("/login")
-                .successHandler(new AuthSuccessHandlerImpl())
-                .failureHandler(new AuthFailHandlerImpl())
-                .and()
-                .logout()
-                .logoutSuccessUrl("/")
-                .and()
-                .httpBasic().disable();
+        // 禁用 UsernamePasswordAuthenticationFilter, 使用自定义的 AccountAuthFilter
+        http.formLogin().disable();
+                /*.loginPage(loginPage)
+                .loginProcessingUrl(loginApi);*/
+
+        // 配置 LogoutFilter
+        http.logout()
+                .logoutUrl(logoutApi)
+                .addLogoutHandler(logoutHandler)
+                //.logoutSuccessUrl(loginPage)
+                .logoutSuccessHandler(logoutSuccessHandler);
+
+        // 配置 ExceptionTranslationFilter, 登录认证接口失败时的处理, 不会重定向到 loginPage
+        http.exceptionHandling()
+                .authenticationEntryPoint(new ExceptionAuthenticationEntryPoint());
+
+        // 配置 SessionManagementFilter 和 ConcurrentSessionFilter
+        http.sessionManagement()
+                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
+                //.sessionAuthenticationStrategy(new MySessionAuthenticationStrategy(sessionRegistry()));
+                .maximumSessions(1)
+                .expiredUrl(loginPage);
 
         // 配置 RememberMeAuthenticationFilter, 禁用 RememberMeAuthenticationFilter
         http.rememberMe().disable();
@@ -115,14 +128,27 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
     }
 
     /**
-     * 使用数据库存储
+     * 配置认证管理器
      *
      * @param
      * @return
-     * @date 2019-07-05 上午11:25
+     * @date 2021-07-25 下午2:28
      */
+    @Bean
     @Override
-    public void configure(AuthenticationManagerBuilder auth) throws Exception {
+    public AuthenticationManager authenticationManagerBean() throws Exception {
+        return super.authenticationManagerBean();
+    }
+
+    /**
+     * 配置认证使用的 provider
+     *
+     * @param
+     * @return
+     * @date 2021-07-25 下午2:31
+     */
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
         auth.authenticationProvider(userAuthProvider);
     }
 
@@ -145,8 +171,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
      * 角色继承
      * ADMIN 可以访问 USER 的权限,反之不可
      *
-     * @param
-     * @return
      * @date 2019-07-05 上午11:18
      */
     @Bean
@@ -155,12 +179,4 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
         roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
         return roleHierarchy;
     }
-
-    private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() {
-        DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler =
-                new DefaultWebSecurityExpressionHandler();
-        defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
-
-        return defaultWebSecurityExpressionHandler;
-    }
 }

+ 27 - 0
manager/src/main/java/cn/reghao/devops/manager/account/security/handler/LogoutHandlerImpl.java

@@ -0,0 +1,27 @@
+package cn.reghao.devops.manager.account.security.handler;
+
+import cn.reghao.devops.manager.account.service.AccountAuthService;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author reghao
+ * @date 2023-08-03 14:32:07
+ */
+@Component
+public class LogoutHandlerImpl implements LogoutHandler {
+    private final AccountAuthService accountAuthService;
+
+    public LogoutHandlerImpl(AccountAuthService accountAuthService) {
+        this.accountAuthService = accountAuthService;
+    }
+
+    @Override
+    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
+        accountAuthService.logout();
+    }
+}

+ 32 - 0
manager/src/main/java/cn/reghao/devops/manager/account/security/handler/LogoutSuccessHandlerImpl.java

@@ -0,0 +1,32 @@
+package cn.reghao.devops.manager.account.security.handler;
+
+import cn.reghao.jutil.jdk.result.WebResult;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * 账号注销成功后的处理, 使用此类后不再调用 logoutSuccessUrl, 在此类中直接返回给客户端
+ * 账号注销的调用顺序 LogoutHandlerImpl -> LogoutSuccessHandlerImpl
+ *
+ * @author reghao
+ * @date 2023-02-14 16:11:48
+ */
+@Component
+public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
+    @Override
+    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth)
+            throws IOException, ServletException {
+        String redirectPath = "/login";
+        String retJson = WebResult.success(redirectPath);
+        response.setContentType("application/json; charset=utf-8");
+        PrintWriter printWriter = response.getWriter();
+        printWriter.write(retJson);
+    }
+}

+ 0 - 21
manager/src/main/java/cn/reghao/devops/manager/account/security/session/MySessionAuthenticationStrategy.java

@@ -1,21 +0,0 @@
-package cn.reghao.devops.manager.account.security.session;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.session.SessionRegistry;
-import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * 配置 SessionManagementFilter 中的 SessionAuthenticationStrategy
- *
- * @author reghao
- * @date 2023-08-09 16:19:50
- */
-public class MySessionAuthenticationStrategy implements SessionAuthenticationStrategy {
-    private SessionRegistry sessionRegistry;
-
-    public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
-    }
-}

+ 0 - 23
manager/src/main/java/cn/reghao/devops/manager/config/ScheduledConfig.java

@@ -1,23 +0,0 @@
-package cn.reghao.devops.manager.config;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.scheduling.TaskScheduler;
-import org.springframework.scheduling.annotation.EnableScheduling;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
-
-/**
- * @author reghao
- * @date 2023-02-27 14:29:52
- */
-@Configuration
-@EnableScheduling
-public class ScheduledConfig {
-    @Bean
-    public TaskScheduler taskScheduler() {
-        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
-        taskScheduler.setPoolSize(10);
-        taskScheduler.initialize();
-        return taskScheduler;
-    }
-}

+ 37 - 0
manager/src/main/java/cn/reghao/devops/manager/config/tomcat/TomcatConfig.java

@@ -0,0 +1,37 @@
+package cn.reghao.devops.manager.config.tomcat;
+
+import org.apache.catalina.Context;
+import org.apache.tomcat.util.http.Rfc6265CookieProcessor;
+import org.apache.tomcat.util.http.SameSiteCookies;
+import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author reghao
+ * @date 2024-02-01 13:15:13
+ */
+@Configuration
+public class TomcatConfig {
+    @Bean
+    public ServletWebServerFactory servletContainer(){
+        return new TomcatServletWebServerFactory() {
+            @Override
+            protected void postProcessContext(Context context) {
+                context.setSessionCookieName("SESSDATA");
+            }
+        };
+    }
+
+    @Bean
+    public TomcatContextCustomizer sameSiteCookiesConfig() {
+        return context -> {
+            final Rfc6265CookieProcessor cookieProcessor = new Rfc6265CookieProcessor();
+            // 设置 Cookie 的 SameSite
+            cookieProcessor.setSameSiteCookies(SameSiteCookies.NONE.getValue());
+            context.setCookieProcessor(cookieProcessor);
+        };
+    }
+}