SpringBoot集成Spring Security(7)——认证流程

在前面的六章中,介绍了 Spring Security 的基础使用,在继续深入向下的学习前,有必要理解清楚 Spring Security 的认证流程,这样才能理解为什么要这样写代码,也方便后续的扩展。

一、认证流程

上图是 Spring Security 认证流程的一部分,下面的讲解以上图为依据。

(1) 用户发起表单登录请求后,首先进入 UsernamePasswordAuthenticationFilter

在 UsernamePasswordAuthenticationFilter 中根据用户输入的用户名、密码构建了 UsernamePasswordAuthenticationToken,并将其交给 AuthenticationManager 来进行认证处理。

AuthenticationManager 本身不包含认证逻辑,其核心是用来管理所有的 AuthenticationProvider,通过交由合适的 AuthenticationProvider 来实现认证。

(2) 下面跳转到了 ProviderManager ,该类是 AuthenticationManager 的实现类:

我们知道不同的登录逻辑它的认证方式是不一样的,比如我们表单登录需要认证用户名和密码,但是当我们使用三方登录时就不需要验证密码。

Spring Security 支持多种认证逻辑,每一种认证逻辑的认证方式其实就是一种 AuthenticationProvider。通过 getProviders() 方法就能获取所有的 AuthenticationProvider,通过 provider.supports() 来判断 provider 是否支持当前的认证逻辑。

当选择好一个合适的 AuthenticationProvider 后,通过 provider.authenticate(authentication) 来让 AuthenticationProvider 进行认证。

(3) 传统表单登录的 AuthenticationProvider 主要是由 AbstractUserDetailsAuthenticationProvider 来进行处理的,我们来看下它的 authenticate()方法。

首先通过 retrieveUser() 方法读取到数据库中的用户信息:

user = retrieveUser(username,(UsernamePasswordAuthenticationToken) authentication);

retrieveUser() 的具体实现在 DaoAuthenticationProvider 中,代码如下:

当我们成功的读取 UserDetails 后,下面开始对其进行认证:

在上图中,我们可以看到认证校验分为 前校验附加校验后校验,如果任何一个校验出错,就会抛出相应的异常。所有校验都通过后,调用 createSuccessAuthentication() 返回认证信息。

在 createSuccessAuthentication 方法中,我们发现它重新 new 了一个 UsernamePasswordAuthenticationToken,因为到这里认证已经通过了,所以将 authorities 注入进去,并设置 authenticated 为 true,即需要认证。

(4)至此认证信息就被传递回 UsernamePasswordAuthenticationFilter 中,在 UsernamePasswordAuthenticationFilter 的父类 AbstractAuthenticationProcessingFilterdoFilter() 中,会根据认证的成功或者失败调用相应的 handler:

这里调用的 handler 实际就是在《SpringBoot集成Spring Security(6)——登录管理》中我们在配置文件中配置的 successHandler()failureHandler()

二、多个请求共享认证信息

Spring Security 通过 Session 来保存用户的认证信息,那么 Spring Security 到底是在什么时候将认证信息放入 Session,又在什么时候将认证信息从 Session 中取出来的呢?

下面将 Spring Security 的认证流程补充完整,如下图:

在上一节认证成功的 successfulAuthentication()方法中,有一行语句:

SecurityContextHolder.getContext().setAuthentication(authResult);

其实就是在这里将认证信息放入 Session 中。

查看 SecurityContext 源码,发现内部就是对 Authentication 的封装,提供了 equals、hashcode、toString等方法,而SecurityContextHolder 可以理解为线程中的 ThreadLocal

我们知道一个 HTTP 请求和响应都是在一个线程中执行,因此在整个处理的任何一个方法中都可以通过 SecurityContextHolder.getContext()来取得存放进去的认证信息。

从 Session 中对认证信息的处理由 SecurityContextPersistenceFilter 来处理,它位于 Spring Security 过滤器链的最前面,它的主要作用是:

  • 当请求时,检查 Session 中是否存在 SecurityContext,如果有将其放入到线程中。
  • 当响应时,检查线程中是否存在 SecurityContext,如果有将其放入到 Session 中。

三、获取用户认证信息

通过调用 SecurityContextHolder.getContext().getAuthentication() 就能够取得认证信息:

@GetMapping("/me")
@ResponseBody
public Object me() {
    return SecurityContextHolder.getContext().getAuthentication();
}

上面的写法有点啰嗦,我们可以简写成下面这种, Spring MVC 会自动帮我们从 Spring Security 中注入:

@GetMapping("/me")
@ResponseBody
public Object me(Authentication authentication) {
    return authentication;
}

如果你仅想获取 UserDetails 对象,也是可以的,写法如下:

@GetMapping("/me")
@ResponseBody
public Object me(@AuthenticationPrincipal UserDetails userDetails) {
    return userDetails;
}

### 回答1: Spring Security是一个强大的安全框架,可以在Spring Boot应用程序中使用。Spring Boot可以轻松地集成Spring Security,为应用程序提供认证和授权的功能。 要集成Spring Security,需要完成以下步骤: 1.添加Spring Security依赖项:在pom.xml文件中添加Spring Security依赖项。 2.配置Spring Security:创建一个Security配置类,并在其中定义安全规则。 3.启用Spring Security:在应用程序的启动类中使用@EnableWebSecurity注释启用Spring Security。 通过这些步骤,您可以为Spring Boot应用程序添加安全性,并保护它免受未经授权的访问。 ### 回答2: Spring Boot是一个相当流行的Java框架,它能够极大地简化Java开发者的工作,并且支持大量的集成,其中包括集成Spring SecuritySpring Security是一个强大的框架,用于保护Web应用程序的安全性。在本文中,我们将讨论Spring Boot和Spring Security集成。 一、集成Spring Security依赖 要集成Spring Security,我们需要在我们的Spring Boot应用程序中添加Spring Security的依赖项。我们可以使用 Maven 或 Gradle 来管理我们的项目依赖关系。 在下面的示例中,我们将使用Maven。在pom.xml文件中,添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 二、配置Spring Security 完成依赖注入后,我们需要配置Spring Security,以确保我们的应用程序与身份验证和授权有关的所有部分都按照预期进行工作。 我们可以通过创建一个配置类来完成此操作。 首先,我们需要创建一个@Configuration注释的类,并使用@EnableWebSecurity注释进行注释。 然后,我们可以扩展WebSecurityConfigurerAdapter类,并覆盖configure方法。 ``` @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { // security配置具体实现 @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .and() .httpBasic(); } } ``` 在上面的示例中,我们创建了一个名为SecurityConfig的类,并使用@EnableWebSecurity注释进行注释。我们还覆盖了WebSecurityConfigurerAdapter的configure方法,并定义了我们的HTTP安全配置。 在此示例中,我们允许任何请求进行身份验证,并定义了基本身份验证。 三、添加用户和角色 我们已经定义了我们的安全配置,但还没有定义任何用户和角色。我们可以通过使用 @Configuration注释和@ConfigurationProperties注释来添加用户和角色。 我们可以先定义一个自定义属性的Java类,如下: ``` @ConfigurationProperties(prefix = "myapp") public class SecurityProperties { private String username; private String password; private String role; // getter和setter方法 } ``` 然后,在我们的配置类中,我们可以使用 Java Config 的方式将其注入到类中: ``` @Configuration @EnableWebSecurity @EnableConfigurationProperties(SecurityProperties.class) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private SecurityProperties securityProperties // security配置具体实现 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser(securityProperties.getUsername()) .password("{noop}" + securityProperties.getPassword()) .roles(securityProperties.getRole()); } } ``` 上面的示例中,我们首先使用@EnableConfigurationProperties注释了SecurityProperties类,并将其自动注入到我们的配置类中。然后,我们将使用该类中的属性来创建内存身份验证,然后配置用户名,密码和角色,这将使用我们在配置文件中定义的账号密码。 四、使用自定义登录页面 Spring Security提供了默认的登录页面,但如果我们希望使用自己的自定义登录页面,则需要添加一个控制器来处理登录请求,并在配置类中进行设置。 ``` @Controller public class LoginController { @GetMapping("/login") public String getLoginPage() { return "login"; } } @Configuration @EnableWebSecurity @EnableConfigurationProperties(SecurityProperties.class) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private SecurityProperties securityProperties // security配置具体实现 @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() // 添加需要放过的静态资源 .antMatchers("/", "/home", "/register").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") // 设置自定义登录页面 .permitAll() .and() .httpBasic() .and() .logout() .permitAll(); } } ``` 上面的示例中,我们创建了一个名为LoginController的控制器,用于处理登录请求。 然后,我们在configure方法中定义了需要允许所有用户访问的页面。 最后,我们配置了自定义登录页面,并将其设置为/login。 总结 在这篇文章中,我们讨论了如何集成 Spring SecuritySpring Boot 的应用程序中。 我们首先添加了Spring Security的依赖项,并创建了一个配置类。 然后,我们添加了用户和角色,并定义了如何使用自定义登录页面。 通过完成这些步骤,我们可以确保我们的应用程序安全,并保护客户端免受攻击。 ### 回答3: Spring Boot是一种用于轻松构建Java应用程序的框架,而Spring Security是一个用于保护应用程序的身份验证和授权框架。在这里,我们将讨论如何将Spring Boot集成Spring Security。 首先,我们需要在pom.xml文件中添加Spring Security依赖项: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 接下来,我们需要配置Spring Security。这可以通过创建一个类来完成,并使用@Configuration注释来进行注释。我们还需要扩展WebSecurityConfigurerAdapter类。 ``` @EnableWebSecurity @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/", "/home").permitAll() .antMatchers("/admin").hasRole("ADMIN") .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .permitAll(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user").password("{noop}password").roles("USER") .and() .withUser("admin").password("{noop}password").roles("USER", "ADMIN"); } } ``` 在此示例中,我们启用了Web Security,并配置了以下内容: 1. 除了主页之外的所有页面都需要身份验证 2. 如果用户拥有ADMIN角色,则允许访问/admin页面 3. 禁用跨站点请求伪造(CSRF)保护 4. 配置表单登录和跳转页面 5. 使用内存身份验证管理器配置了两个用户 现在,我们可以通过以下方式测试Spring Security: 1. 启动应用程序 2. 访问http://localhost:8080/login 3. 输入用户名和密码(user/password 或 admin/password) 4. 尝试访问http://localhost:8080/admin 如果用户拥有ADMIN角色,则允许访问/admin页面,否则将显示403错误页面。 总之,Spring Boot集成Spring Security是一种用于保护应用程序的身份验证和授权框架。我们可以轻松地使用Spring Security通过添加依赖项和配置文件来保护我们的应用程序。
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值