Security AuthenticationManager 和Authentication

在 Spring Security 中,AuthenticationManager 和 Authentication 的工作流程如下:

用户提交认证请求

用户通过登录表单或 API 提交其认证信息(例如用户名和密码)。

创建 Authentication 对象

在后端,系统创建一个包含用户凭证的 Authentication 对象。常见的实现类是 UsernamePasswordAuthenticationToken。

传递 Authentication 对象给 AuthenticationManager        

未认证的 Authentication 对象被传递给 AuthenticationManager 的 authenticate 方法。

AuthenticationManager 调用 AuthenticationProvider

AuthenticationManager 将认证请求委托给一个或多个 AuthenticationProvider 进行验证。通常使用的是 ProviderManager,它可以包含多个 AuthenticationProvider。

AuthenticationProvider 进行认证

每个 AuthenticationProvider 尝试验证传入的 Authentication 对象:

UserDetailsService 加载用户信息:AuthenticationProvider 使用 UserDetailsService 加载用户信息。

验证用户凭证:AuthenticationProvider 比较传入的凭证和加载的用户信息,如果匹配,则认证成功。

创建经过认证的 Authentication 对象:如果认证成功,AuthenticationProvider 创建一个包含用户详细信息和权限的新的 Authentication 对象。

返回认证结果

认证成功:AuthenticationManager 返回一个经过认证的 Authentication 对象。此对象包含用户的详细信息和权限。

认证失败:如果认证失败,AuthenticationManager 抛出一个 AuthenticationException 异常。

存储认证信息

认证成功后,Spring Security 将 Authentication 对象存储在 SecurityContextHolder 中,以便在后续请求中使用。

后续请求处理

在后续请求中,Spring Security 会从 SecurityContextHolder 中获取当前用户的 Authentication 对象,以确定用户的身份和权限。


  1.    提交用户名和密码,发送认证请求
  2.    AuthenticationManager: 创建 Authentication 对象并调用 authenticate 方法
  3.     AuthenticationManager->AuthenticationProvider: 委托认证请求
  4.     AuthenticationProvider->UserDetailsService: 加载用户信息
  5.     UserDetailsService-->AuthenticationProvider: 返回用户详情
  6.     AuthenticationProvider-->AuthenticationManager:返回经过认证的Authentication对象
  7.     AuthenticationManagerr-->返回经过认证的 Authentication 对象
  8.     SecurityContextHolder: 存储认证信息
  9.    返回认证结果

    note over SecurityContextHolder: 后续请求中使用存储的认证信息

示例代码:

pom.xml

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

SecurityConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

import java.util.Arrays;

@Configuration
public class SecurityConfig {

    @Bean
    public AuthenticationManager authenticationManager() {
        UserDetailsService userDetailsService = inMemoryUserDetailsManager();
        AuthenticationProvider authenticationProvider = new CustomAuthenticationProvider(userDetailsService);
        return new ProviderManager(Arrays.asList(authenticationProvider));
    }

    @Bean
    public UserDetailsService inMemoryUserDetailsManager() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("user").password("{noop}password").roles("USER").build());
        manager.createUser(User.withUsername("admin").password("{noop}admin").roles("ADMIN").build());
        return manager;
    }

    private static class CustomAuthenticationProvider implements AuthenticationProvider {

        private final UserDetailsService userDetailsService;

        public CustomAuthenticationProvider(UserDetailsService userDetailsService) {
            this.userDetailsService = userDetailsService;
        }

        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            String username = authentication.getName();
            String password = authentication.getCredentials().toString();

            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            if (userDetails != null && "{noop}".concat(password).equals(userDetails.getPassword())) {
                return new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities());
            } else {
                throw new UsernameNotFoundException("Invalid username or password");
            }
        }

        @Override
        public boolean supports(Class<?> authentication) {
            return authentication.equals(UsernamePasswordAuthenticationToken.class);
        }
    }
}

AuthController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AuthController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @PostMapping("/login")
    public String login(@RequestBody AuthRequest authRequest) {
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword());

        Authentication authentication = authenticationManager.authenticate(authenticationToken);

        if (authentication.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(authentication);
            return "Authentication successful for user: " + authentication.getName();
        } else {
            return "Authentication failed";
        }
    }
}

class AuthRequest {
    private String username;
    private String password;

    // getters and setters
}

        通过这个示例代码,我们展示了 AuthenticationManager 和 Authentication 在 Spring Security 中的工作流程。用户提交认证请求,系统创建 Authentication 对象并通过 AuthenticationManager 进行验证,最终将认证信息存储在 SecurityContextHolder 中。

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值