主页 > 互联网  > 

SpringSecurity简介与使用

SpringSecurity简介与使用

Spring Security 是 Spring 框架中用于处理认证和授权的强大模块。本文将介绍 Spring Security 的基本使用方法以及其内部工作原理。

目录 Spring Security 简介基本配置认证流程过滤器链工作原理自定义认证授权管理实战示例 Spring Security 简介

Spring Security 提供了全面的安全解决方案,适用于企业级应用程序。它主要关注两个方面:

认证(Authentication): 验证用户的身份授权(Authorization): 确定用户能够访问的资源 #mermaid-svg-RHSEoxnb5ZVHjFT6 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .error-icon{fill:#552222;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .marker.cross{stroke:#333333;}#mermaid-svg-RHSEoxnb5ZVHjFT6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .cluster-label text{fill:#333;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .cluster-label span{color:#333;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .label text,#mermaid-svg-RHSEoxnb5ZVHjFT6 span{fill:#333;color:#333;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .node rect,#mermaid-svg-RHSEoxnb5ZVHjFT6 .node circle,#mermaid-svg-RHSEoxnb5ZVHjFT6 .node ellipse,#mermaid-svg-RHSEoxnb5ZVHjFT6 .node polygon,#mermaid-svg-RHSEoxnb5ZVHjFT6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .node .label{text-align:center;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .node.clickable{cursor:pointer;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .arrowheadPath{fill:#333333;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .cluster text{fill:#333;}#mermaid-svg-RHSEoxnb5ZVHjFT6 .cluster span{color:#333;}#mermaid-svg-RHSEoxnb5ZVHjFT6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RHSEoxnb5ZVHjFT6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户端 过滤器链 认证管理器 访问决策管理器 认证提供者 用户详情服务 用户存储 安全元数据源 投票器 基本配置

首先,我们需要添加 Spring Security 依赖到项目中:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>

然后创建一个基本的 Security 配置类:

@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authorize) -> authorize .requestMatchers("/public/**").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated() ) .formLogin(form -> form .loginPage("/login") .permitAll() ) .logout(logout -> logout .permitAll()); return http.build(); } @Bean public UserDetailsService userDetailsService() { UserDetails user = User.withDefaultPasswordEncoder() .username("user") .password("password") .roles("USER") .build(); UserDetails admin = User.withDefaultPasswordEncoder() .username("admin") .password("password") .roles("ADMIN", "USER") .build(); return new InMemoryUserDetailsManager(user, admin); } } 认证流程

Spring Security 的认证流程是其核心部分。当用户尝试访问受保护的资源时,系统会要求用户进行身份验证。

#mermaid-svg-V7KJ9GNacTzUKZfv {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-V7KJ9GNacTzUKZfv .error-icon{fill:#552222;}#mermaid-svg-V7KJ9GNacTzUKZfv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-V7KJ9GNacTzUKZfv .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-V7KJ9GNacTzUKZfv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-V7KJ9GNacTzUKZfv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-V7KJ9GNacTzUKZfv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-V7KJ9GNacTzUKZfv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-V7KJ9GNacTzUKZfv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-V7KJ9GNacTzUKZfv .marker.cross{stroke:#333333;}#mermaid-svg-V7KJ9GNacTzUKZfv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-V7KJ9GNacTzUKZfv .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-V7KJ9GNacTzUKZfv text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-V7KJ9GNacTzUKZfv .actor-line{stroke:grey;}#mermaid-svg-V7KJ9GNacTzUKZfv .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-V7KJ9GNacTzUKZfv .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-V7KJ9GNacTzUKZfv #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-V7KJ9GNacTzUKZfv .sequenceNumber{fill:white;}#mermaid-svg-V7KJ9GNacTzUKZfv #sequencenumber{fill:#333;}#mermaid-svg-V7KJ9GNacTzUKZfv #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-V7KJ9GNacTzUKZfv .messageText{fill:#333;stroke:#333;}#mermaid-svg-V7KJ9GNacTzUKZfv .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-V7KJ9GNacTzUKZfv .labelText,#mermaid-svg-V7KJ9GNacTzUKZfv .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-V7KJ9GNacTzUKZfv .loopText,#mermaid-svg-V7KJ9GNacTzUKZfv .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-V7KJ9GNacTzUKZfv .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-V7KJ9GNacTzUKZfv .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-V7KJ9GNacTzUKZfv .noteText,#mermaid-svg-V7KJ9GNacTzUKZfv .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-V7KJ9GNacTzUKZfv .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-V7KJ9GNacTzUKZfv .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-V7KJ9GNacTzUKZfv .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-V7KJ9GNacTzUKZfv .actorPopupMenu{position:absolute;}#mermaid-svg-V7KJ9GNacTzUKZfv .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-V7KJ9GNacTzUKZfv .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-V7KJ9GNacTzUKZfv .actor-man circle,#mermaid-svg-V7KJ9GNacTzUKZfv line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-V7KJ9GNacTzUKZfv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户端 过滤器链 AuthenticationManager AuthenticationProvider UserDetailsService UserDetails 请求受保护资源 创建Authentication对象,请求认证 委托认证 加载用户信息 获取用户信息 返回用户详情 返回用户信息 验证密码 认证结果 认证结果 根据认证结果返回响应 客户端 过滤器链 AuthenticationManager AuthenticationProvider UserDetailsService UserDetails

认证流程主要涉及以下组件:

AuthenticationFilter:接收认证请求并创建 Authentication 对象AuthenticationManager:管理认证过程,委托给 AuthenticationProviderAuthenticationProvider:验证 Authentication 对象UserDetailsService:加载用户数据PasswordEncoder:加密和验证密码 过滤器链工作原理

Spring Security 使用一系列过滤器来处理请求。每个过滤器都有特定的职责,它们按照预定义的顺序执行。

#mermaid-svg-9YAOWDV0hT0izWM4 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-9YAOWDV0hT0izWM4 .error-icon{fill:#552222;}#mermaid-svg-9YAOWDV0hT0izWM4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9YAOWDV0hT0izWM4 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-9YAOWDV0hT0izWM4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9YAOWDV0hT0izWM4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9YAOWDV0hT0izWM4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9YAOWDV0hT0izWM4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9YAOWDV0hT0izWM4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9YAOWDV0hT0izWM4 .marker.cross{stroke:#333333;}#mermaid-svg-9YAOWDV0hT0izWM4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9YAOWDV0hT0izWM4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9YAOWDV0hT0izWM4 .cluster-label text{fill:#333;}#mermaid-svg-9YAOWDV0hT0izWM4 .cluster-label span{color:#333;}#mermaid-svg-9YAOWDV0hT0izWM4 .label text,#mermaid-svg-9YAOWDV0hT0izWM4 span{fill:#333;color:#333;}#mermaid-svg-9YAOWDV0hT0izWM4 .node rect,#mermaid-svg-9YAOWDV0hT0izWM4 .node circle,#mermaid-svg-9YAOWDV0hT0izWM4 .node ellipse,#mermaid-svg-9YAOWDV0hT0izWM4 .node polygon,#mermaid-svg-9YAOWDV0hT0izWM4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9YAOWDV0hT0izWM4 .node .label{text-align:center;}#mermaid-svg-9YAOWDV0hT0izWM4 .node.clickable{cursor:pointer;}#mermaid-svg-9YAOWDV0hT0izWM4 .arrowheadPath{fill:#333333;}#mermaid-svg-9YAOWDV0hT0izWM4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9YAOWDV0hT0izWM4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9YAOWDV0hT0izWM4 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-9YAOWDV0hT0izWM4 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-9YAOWDV0hT0izWM4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9YAOWDV0hT0izWM4 .cluster text{fill:#333;}#mermaid-svg-9YAOWDV0hT0izWM4 .cluster span{color:#333;}#mermaid-svg-9YAOWDV0hT0izWM4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9YAOWDV0hT0izWM4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} HTTP请求 SecurityContextPersistenceFilter LogoutFilter UsernamePasswordAuthenticationFilter DefaultLoginPageGeneratingFilter BasicAuthenticationFilter RequestCacheAwareFilter SecurityContextHolderAwareRequestFilter AnonymousAuthenticationFilter SessionManagementFilter ExceptionTranslationFilter FilterSecurityInterceptor 控制器方法

主要过滤器及其职责:

SecurityContextPersistenceFilter:在请求之间维护 SecurityContextUsernamePasswordAuthenticationFilter:处理表单登录认证BasicAuthenticationFilter:处理 HTTP Basic 认证ExceptionTranslationFilter:处理认证和授权异常FilterSecurityInterceptor:执行最终的授权决策 自定义认证

要实现自定义认证,可以通过以下步骤:

实现 UserDetailsService 接口加载用户数据创建自定义 AuthenticationProvider配置 AuthenticationManager @Service public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found")); return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, getAuthorities(user.getRoles()) ); } private Collection<? extends GrantedAuthority> getAuthorities(Set<Role> roles) { return roles.stream() .map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName())) .collect(Collectors.toList()); } } 授权管理

Spring Security 的授权系统决定用户是否有权访问特定资源。

#mermaid-svg-zZCwTQdMLiWO902g {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-zZCwTQdMLiWO902g .error-icon{fill:#552222;}#mermaid-svg-zZCwTQdMLiWO902g .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zZCwTQdMLiWO902g .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-zZCwTQdMLiWO902g .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zZCwTQdMLiWO902g .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zZCwTQdMLiWO902g .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zZCwTQdMLiWO902g .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zZCwTQdMLiWO902g .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zZCwTQdMLiWO902g .marker.cross{stroke:#333333;}#mermaid-svg-zZCwTQdMLiWO902g svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zZCwTQdMLiWO902g .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zZCwTQdMLiWO902g text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-zZCwTQdMLiWO902g .actor-line{stroke:grey;}#mermaid-svg-zZCwTQdMLiWO902g .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-zZCwTQdMLiWO902g .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-zZCwTQdMLiWO902g #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-zZCwTQdMLiWO902g .sequenceNumber{fill:white;}#mermaid-svg-zZCwTQdMLiWO902g #sequencenumber{fill:#333;}#mermaid-svg-zZCwTQdMLiWO902g #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-zZCwTQdMLiWO902g .messageText{fill:#333;stroke:#333;}#mermaid-svg-zZCwTQdMLiWO902g .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zZCwTQdMLiWO902g .labelText,#mermaid-svg-zZCwTQdMLiWO902g .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-zZCwTQdMLiWO902g .loopText,#mermaid-svg-zZCwTQdMLiWO902g .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-zZCwTQdMLiWO902g .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-zZCwTQdMLiWO902g .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-zZCwTQdMLiWO902g .noteText,#mermaid-svg-zZCwTQdMLiWO902g .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-zZCwTQdMLiWO902g .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zZCwTQdMLiWO902g .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zZCwTQdMLiWO902g .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zZCwTQdMLiWO902g .actorPopupMenu{position:absolute;}#mermaid-svg-zZCwTQdMLiWO902g .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-zZCwTQdMLiWO902g .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zZCwTQdMLiWO902g .actor-man circle,#mermaid-svg-zZCwTQdMLiWO902g line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-zZCwTQdMLiWO902g :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户端 过滤器链 FilterSecurityInterceptor AccessDecisionManager AccessDecisionVoter SecurityMetadataSource 请求资源 通过过滤器链 获取安全配置 返回资源所需权限 决策请求 投票 投票结果 授权决策 决策结果 请求处理结果 客户端 过滤器链 FilterSecurityInterceptor AccessDecisionManager AccessDecisionVoter SecurityMetadataSource

授权系统的主要组件:

FilterSecurityInterceptor:负责对请求进行安全决策SecurityMetadataSource:提供资源所需的权限AccessDecisionManager:基于投票机制做出授权决策AccessDecisionVoter:投票同意或拒绝访问 实战示例

下面是一个完整的示例,包含自定义认证和授权:

@Configuration // 标记为Spring配置类 @EnableWebSecurity // 启用Spring Security的Web安全支持 public class SecurityConfig { @Autowired private CustomUserDetailsService userDetailsService; // 注入自定义的用户详情服务 @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // 禁用CSRF保护,适用于REST API场景 .csrf(csrf -> csrf.disable()) // 配置请求授权规则 .authorizeHttpRequests(authorize -> authorize // 公开API不需要认证即可访问 .requestMatchers("/api/public/**").permitAll() // 管理员API只允许ADMIN角色访问 .requestMatchers("/api/admin/**").hasRole("ADMIN") // 用户API允许USER或ADMIN角色访问 .requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN") // 其他所有请求都需要认证 .anyRequest().authenticated() ) // 配置表单登录 .formLogin(form -> form // 设置登录处理URL .loginProcessingUrl("/api/login") // 设置登录成功处理器,可自定义登录成功后的行为(如返回JWT令牌) .successHandler(new CustomAuthSuccessHandler()) // 设置登录失败处理器,可自定义失败响应 .failureHandler(new CustomAuthFailureHandler()) // 允许所有用户访问登录接口 .permitAll() ) // 配置登出功能 .logout(logout -> logout // 设置登出URL .logoutUrl("/api/logout") // 设置登出成功处理器,可自定义登出后的响应 .logoutSuccessHandler(new CustomLogoutSuccessHandler()) // 允许所有用户访问登出接口 .permitAll() ) // 配置异常处理 .exceptionHandling(ex -> ex // 设置认证入口点,处理未认证用户访问受保护资源的情况(如返回401状态码) .authenticationEntryPoint(new CustomAuthEntryPoint()) ); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { // 使用BCrypt加密算法对密码进行加密和验证 // 会自动处理盐值,每次加密结果不同,但验证时能正确匹配 return new BCryptPasswordEncoder(); } @Bean public AuthenticationManager authManager(AuthenticationConfiguration config) throws Exception { // 配置认证管理器,Spring Security会自动使用已注册的AuthenticationProvider // 当有CustomUserDetailsService时,会自动创建DaoAuthenticationProvider return config.getAuthenticationManager(); } } 自定义处理器示例 // 自定义认证成功处理器 public class CustomAuthSuccessHandler implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // 设置响应类型为JSON response.setContentType("application/json;charset=UTF-8"); // 创建登录成功响应,可以在这里生成JWT令牌 Map<String, Object> result = new HashMap<>(); result.put("status", "success"); result.put("message", "登录成功"); // 可以添加用户信息或token result.put("token", generateToken(authentication)); // 输出JSON响应 response.getWriter().write(new ObjectMapper().writeValueAsString(result)); } // 生成JWT令牌的方法 private String generateToken(Authentication authentication) { // JWT令牌生成逻辑... return "sample-jwt-token"; } } // 自定义认证失败处理器 public class CustomAuthFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { // 设置响应状态码为401 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 设置响应类型为JSON response.setContentType("application/json;charset=UTF-8"); // 创建登录失败响应 Map<String, Object> result = new HashMap<>(); result.put("status", "error"); result.put("message", "用户名或密码错误"); // 输出JSON响应 response.getWriter().write(new ObjectMapper().writeValueAsString(result)); } } // 自定义登出成功处理器 public class CustomLogoutSuccessHandler implements LogoutSuccessHandler { @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // 设置响应类型为JSON response.setContentType("application/json;charset=UTF-8"); // 创建登出成功响应 Map<String, Object> result = new HashMap<>(); result.put("status", "success"); result.put("message", "登出成功"); // 输出JSON响应 response.getWriter().write(new ObjectMapper().writeValueAsString(result)); } } // 自定义认证入口点 public class CustomAuthEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { // 设置响应状态码为401 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 设置响应类型为JSON response.setContentType("application/json;charset=UTF-8"); // 创建未认证响应 Map<String, Object> result = new HashMap<>(); result.put("status", "error"); result.put("message", "访问此资源需要完全身份验证"); // 输出JSON响应 response.getWriter().write(new ObjectMapper().writeValueAsString(result)); } } 总结

Spring Security 提供了一个灵活、可扩展的安全框架,通过了解其工作原理,可以根据具体需求进行定制化配置。主要工作流程为:

请求先通过一系列过滤器认证过程由 AuthenticationManager 和 AuthenticationProvider 处理授权过程由 AccessDecisionManager 和 AccessDecisionVoter 处理安全上下文在整个请求过程中被维护
标签:

SpringSecurity简介与使用由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“SpringSecurity简介与使用