目录
二、前后端分离下,security如何实现认证功能(工作原理)?(重点)
八、如何在 Spring Security 中实现 JWT 认证?
一、什么是Spring Security?核心功能?
Spring Security是一个基于Spring框架的安全框架,提供了完整的安全解决方案,包括认证、授权、攻击防护、加密、会话管理等功能。
其核心功能包括:
- 认证:提供了多种认证方式,如表单认证、HTTP Basic认证、OAuth2认证等,可以与多种身份验证机制集成。
- 授权:提供了多种授权方式,如角色授权、基于表达式的授权等,可以对应用程序中的不同资源进行授权。
- 攻击防护:提供了多种防护机制,如跨站点请求伪造(CSRF)防护、注入攻击防护等。
- 会话管理:提供了会话管理机制,如令牌管理、并发控制等。
- 监视与管理:提供了监视与管理机制,如访问日志记录、审计等。
Spring Security通过配置安全规则和过滤器链来实现以上功能,可以轻松地为Spring应用程序提供安全性和保护机制。
- http.csrf().disable() 禁用csrf攻击防护
- http.csrf().enabled() 启用csrf攻击防护
- CSRF是指跨站请求伪造(Cross-site request forgery),是web常见的攻击之一。
二、前后端分离下,security如何实现认证功能(工作原理)?(重点)
利用token机制实现
Spring Security的具体工作原理如下:
1.用户请求Web应用程序的受保护资源。
2.Spring Security拦截请求,并尝试获取用户的身份验证信息。
3.如果用户没有经过身份验证,Spring Security将向用户显示一个登录页面,并要求用户提供有效的凭据(用户名和密码)。
4.一旦用户提供了有效的凭据,Spring Security将验证这些凭据,并创建一个已认证的安全上下文(SecurityContext)对象。
5.安全上下文对象包含已认证的用户信息,包括用户名、角色和授权信息。
6.在接下来的请求中,Spring Security将使用已经认证的安全上下文对象来判断用户是否有权访问受保护的资源。
7.如果用户有权访问资源,Spring Security将允许用户访问资源,否则将返回一个错误信息。
三、security内部的执行原理?
SpringSecurity的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。这里我们可以看看 入门案例中的过滤器。
四、核心过滤器(按典型执行顺序)
Spring Security 的核心功能是通过一系列内置的过滤器(Filter)组成的过滤器链(FilterChain)实现的。这些过滤器按照特定顺序执行,分别处理认证、授权、会话管理、CSRF防护等安全任务。以下是 Spring Security 主要的内置过滤器及其作用:
序号 | 过滤器名称 | 中文名称/描述 | 说明 |
---|---|---|---|
1 | ChannelProcessingFilter |
通道处理过滤器 | 强制请求使用 HTTPS(配置了 requiresChannel() 时生效) |
2 | WebAsyncManagerIntegrationFilter |
异步管理集成过滤器 | 集成 WebAsyncManager ,确保异步请求也能持有安全上下文 |
3 | SecurityContextPersistenceFilter |
安全上下文持久化过滤器 | 请求开始加载安全上下文(默认从 Session),结束后保存 |
4 | HeaderWriterFilter |
HTTP 头写入过滤器 | 写入安全相关的 HTTP 头(如 X-Content-Type-Options , X-Frame-Options ) |
5 | CorsFilter |
跨域资源共享过滤器 | 处理跨域请求(CORS),需显式配置 |
6 | CsrfFilter |
CSRF 防护过滤器 | 防护 CSRF 攻击,默认对非幂等请求(如 POST)校验 _csrf 令牌 |
7 | LogoutFilter |
注销处理过滤器 | 处理注销请求(默认匹配 /logout ),清除认证信息 |
8 | OAuth2AuthorizationRequestRedirectFilter |
OAuth2 授权请求重定向过滤器 | OAuth2 登录时重定向到授权端点(如第三方登录) |
9 | Saml2WebSsoAuthenticationRequestFilter |
SAML2 单点登录请求过滤器 | SAML2 身份验证的重定向逻辑 |
10 | X509AuthenticationFilter |
X.509 证书认证过滤器 | 处理基于 X.509 证书的认证 |
11 | AbstractPreAuthenticatedProcessingFilter |
预认证处理过滤器 | 预认证处理(如从请求头提取认证信息) |
12 | UsernamePasswordAuthenticationFilter |
用户名密码认证过滤器 | 处理表单登录(默认匹配 /login ,提交用户名密码) |
13 | DefaultLoginPageGeneratingFilter |
默认登录页面生成器 | 自动生成默认登录页面(未自定义时生效) |
14 | DefaultLogoutPageGeneratingFilter |
默认注销页面生成器 | 自动生成默认注销页面 |
15 | ConcurrentSessionFilter |
并发会话控制过滤器 | 检查会话是否过期(需配置会话管理) |
16 | BearerTokenAuthenticationFilter |
Bearer Token 认证过滤器 | 处理 OAuth2 Bearer Token 认证(JWT 等) |
17 | RequestCacheAwareFilter |
请求缓存感知过滤器 | 缓存请求(如登录成功后重定向到原始请求) |
18 | SecurityContextHolderAwareRequestFilter |
安全上下文请求包装过滤器 | 包装请求对象,提供 Spring Security 增强方法(如 isUserInRole() ) |
19 | AnonymousAuthenticationFilter |
匿名认证过滤器 | 为未认证请求分配一个匿名 Authentication 对象 |
20 | SessionManagementFilter |
会话管理过滤器 | 处理会话固定(session fixation)防护和并发会话控制 |
21 | ExceptionTranslationFilter |
异常转换过滤器 | 转换安全异常(如 AuthenticationException 重定向到登录页,AccessDeniedException 返回 403) |
22 | FilterSecurityInterceptor |
安全拦截器 | 最终权限检查(基于 ConfigAttribute 判断请求是否允许访问) |
23 | AuthorizationFilter (Spring Security 5.5+) |
授权决策过滤器 | 更现代的授权决策实现(替代 FilterSecurityInterceptor ) |
五、security内部实现过程(图一重点)?
六、有哪些控制请求访问权限的方法?
在Spring Security中,可以使用以下方法来控制请求访问权限:
- permitAll():允许所有用户访问该请求,不需要进行任何身份验证。
- denyAll():拒绝所有用户访问该请求。
- anonymous():允许匿名用户访问该请求。
- authenticated():要求用户进行身份验证,但是不要求用户具有任何特定的角色。
- hasRole(String role):要求用户具有特定的角色才能访问该请求。
- hasAnyRole(String... roles):要求用户具有多个角色中的至少一个角色才能访问该请求。
- hasAuthority(String authority):要求用户具有特定的权限才能访问该请求。
- hasAnyAuthority(String... authorities):要求用户具有多个权限中的至少一个权限才能访问该请求。
可以将这些方法应用于Spring Security的配置类或者在Spring Security注解中使用。
hasRole 和 hasAuthority 有区别吗?
在Spring Security中,hasRole和hasAuthority都可以用来控制用户的访问权限,但它们有一些细微的差别。
- hasRole方法是基于角色进行访问控制的。它检查用户是否有指定的角色,并且这些角色以"ROLE_"前缀作为前缀(例如"ROLE_ADMIN")。
- hasAuthority方法是基于权限进行访问控制的。它检查用户是否有指定的权限,并且这些权限没有前缀。
因此,使用hasRole方法需要在用户的角色名称前添加"ROLE_"前缀,而使用hasAuthority方法不需要这样做。
例如,假设用户有一个角色为"ADMIN"和一个权限为"VIEW_REPORTS",可以使用以下方式控制用户对页面的访问权限:
.antMatchers("/admin/").hasRole("ADMIN") .antMatchers("/reports/").hasAuthority("VIEW_REPORTS") 在这个例子中,只有具有"ROLE_ADMIN"角色的用户才能访问/admin/路径下的页面,而具有"VIEW_REPORTS"权限的用户才能访问/reports/路径下的页面。
七、如何对密码进行加密?
在 Spring Security 中对密码进行加密通常使用的是密码编码器(PasswordEncoder)。PasswordEncoder 的作用是将明文密码加密成密文密码,以便于存储和校验。Spring Security 提供了多种常见的密码编码器,例如 BCryptPasswordEncoder、SCryptPasswordEncoder、StandardPasswordEncoder 等。
以 BCryptPasswordEncoder 为例,使用步骤如下:
1.在 pom.xml 文件中添加 BCryptPasswordEncoder 的依赖:
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-crypto</artifactId> <version>5.6.1</version> </dependency> 2.在 Spring 配置文件中注入 BCryptPasswordEncoder:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// ...
}
常用的方法:
passwordEncoder.encode("1234")
passwordEncoder.matchs("1234","加密后密码")
八、如何在 Spring Security 中实现 JWT 认证?
要在 Spring Security 中实现基于 JWT(JSON Web Token)的认证,需要执行以下步骤:
引入 JWT 相关依赖,如
jjwt
。实现一个用于生成和解析 JWT 的工具类。
创建一个自定义的
AuthenticationFilter
,用于从请求头中提取 JWT 并进行认证。在
SecurityConfig
类中配置HttpSecurity
,将自定义的AuthenticationFilter
添加到过滤器链。
以下是一个简单的示例:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest().authenticated();
}
}
在这个示例中,我们禁用了 CSRF 防护和会话管理,然后将自定义的 JwtAuthenticationFilter
添加到过滤器链。
认证和授权有什么区别?
认证(Authentication):是验证用户身份的过程,通常涉及到用户名和密码的检查。成功认证后,用户将获得一个认证令牌,用于后续的授权过程。
授权(Authorization):是确定用户是否具有访问特定资源或执行特定操作的权限的过程。系统基于用户的角色、权限或访问控制列表(ACL)来判断用户是否具有访问权限。
九、请简要介绍 Spring Security 的架构。
Spring Security 的架构主要由以下组件组成:
序号 | 组件名称 | 中文名称/描述 | 说明 |
---|---|---|---|
1 | SecurityContextHolder |
安全上下文持有器 | 存储与当前线程关联的安全上下文(SecurityContext) |
2 | Authentication |
认证信息接口 | 表示用户的认证信息(如用户名、凭证、权限等) |
3 | UserDetails |
用户详细信息接口 | 表示用户的详细信息(如用户名、密码、权限、是否启用等) |
4 | UserDetailsService |
用户详情服务接口 | 用于根据用户名加载用户详细信息(常用于认证时获取用户信息) |
5 | AuthenticationManager |
认证管理器 | 负责处理认证请求,验证用户身份 |
6 | AccessDecisionManager |
授权决策管理器 | 根据配置的权限策略决定用户是否有权访问资源 |
7 | FilterChainProxy |
过滤器链代理 | 负责组织和调度多个安全过滤器链,是 Spring Security 的核心处理入口之一 |
8 | SecurityFilterChain |
安全过滤器链 | 由一系列安全过滤器组成的链,用于对 HTTP 请求进行安全处理 |
什么是 SecurityContextHolder
?
SecurityContextHolder
是一个用于存储与当前线程关联的安全上下文的类。它使用 ThreadLocal
机制来存储 SecurityContext
。SecurityContext
包含了当前用户的认证信息,如 Authentication
对象。
十、Spingsecurity异常拦截处理
认证异常拦截
/*
自定义认证异常处理器类
*/
@Component
public class MyAuthenticationExceptionHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
ResponseResult responseResult = new
ResponseResult(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED.value(), "认证失败!");
response.getWriter().append(JSON.toJSONString(responseResult));
}
}
权限异常拦截
/**
* 自定义权限拒绝异常处理器
*/
@Component
public class MyAccessDenyHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
ResponseResult responseResult = new
ResponseResult(403, "权限拒绝,没有访问权限!");
response.getWriter().append(JSON.toJSONString(responseResult));
}
}
注册异常拦截器
@Configuration
//启用security的注解支持
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyAuthenticationExceptionHandler myAuthenticationExceptionHandler;
@Autowired
private MyAccessDenyHandler myAccessDenyHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
//配置自定义异常处理器(认证异常、权限拒绝异常)
http.exceptionHandling()
.authenticationEntryPoint(myAuthenticationExceptionHandler)
.accessDeniedHandler(myAccessDenyHandler);
}
相关权限注解
序号 | 注解代码 | 中文解释 |
---|---|---|
1 | @PreAuthorize("hasAuthority('user:list')") |
方法调用前检查当前用户是否具有名为 user:list 的权限(Authority)。 |
2 | @PreAuthorize("hasAuthority('system:dept:list')") |
方法调用前检查当前用户是否具有名为 system:dept:list 的权限。 |
3 | @PreAuthorize("hasAnyAuthority('system:dept:list','system:test:list')") |
方法调用前检查当前用户是否具有任意一个指定权限:system:dept:list 或 system:test:list 。 |
4 | @PreAuthorize("hasRole('CEO')") |
方法调用前检查当前用户是否拥有角色 CEO (Spring Security 会自动加上 ROLE_ 前缀进行匹配)。 |
5 | @PreAuthorize("hasAnyRole('CEO')") |
方法调用前检查当前用户是否拥有任意一个指定角色,这里是检查是否为 CEO 。 |
hasAuthority 和数据库表权限是等值比对
hasRole 添加ROLE_ 之后和数据库表中的角色名字比对
十一、设置跨域访问
@Configuration
public class MyCorsFilter implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") //路径
.allowedOrigins("*") //域名
.allowedMethods("*") //方法 get/post/put/delete
.allowedHeaders("*") //请求头
.allowCredentials(true) ; //cookie 是否允许携带cookie
}
}
MySecurityConfig.java中设置security允许跨域访问。
//设置跨域访问
http.cors();