Spring Security--学习记录二

Spring Security--学习记录二

Spring Security认证流程图

1.Http Request

Spring security 定义了一个过滤器链, 当认证请求到达这个链时, 该请求将会穿过这个链条用于认证和授权. 这个链上的可以定义1..N个过滤器, 过滤器的用途是获取请求中的认证信息, 根据认证方式进行路由, 把认证信息传递给对应的认证处理程序进行处理.

常用过滤链

不同的过滤器处理不同的认证信息. 例如:

  • HTTP Basic 认证请通过过滤器链, 到达 BasicAuthenticationFilter
  • HTTP Digest 认证被 DigestAuthenticationFilter 识别,拦截并处理.
  • 表单登录认证被 UsernamePasswordAuthenticationFilter 识别,拦截并处理.

2.基于用户凭证创建 AuthenticationToken

多种类型的 AuthenticationToken, 基于不同的认证方式, 过滤器会创建不同类型的 AuthenticationToken

这里我们以最常用表单登录为例子, 用户在登录表单中输入用户名和密码, 并点击确定, 浏览器提交POST请求到服务器, 穿过过滤器链, 被 UsernamePasswordAuthenticationFilter 识别, UsernamePasswordAuthenticationFilter 提取请求中的用户名和密码来创建 UsernamePasswordAuthenticationToken 对象.

3.把组装好的 AuthenticationToken 传递给 AuthenticationManagager

组装好的 UsernamePasswordAuthenticationToken 对象被传递给 AuthenticationManagager 的 authenticate 方法进行认证决策.AuthenticationManager 只是一个接口, 实际的实现是 ProviderManager

ProviderManager 有一个配置好的认证提供者列表(AuthenticationProvider), ProviderManager 会把收到的 UsernamePasswordAuthenticationToken 对象传递给列表中的每一个 AuthenticationProvider 进行认证.

4.进行认证处理

public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class<?> authentication);
}

AuthenticationProvider提供了以下的实现类:

CasAuthenticationProvider JaasAuthenticationProvider DaoAuthenticationProvider OpenIDAuthenticationProvider RememberMeAuthenticationProvider LdapAuthenticationProvider

上面我们说了, ProviderManager 会把收到的 UsernamePasswordAuthenticationToken 对象传递给列表中的每一个 AuthenticationProvider 进行认证.那到底 UsernamePasswordAuthenticationToken 会被哪一个接收和处理呢?是由supports方法来决定的。

5.UserDetailsService获取用户信息

UserDetailsService 获取的对象是一个 UserDetails. 框架中自带一个 User 实现, 但是一般我们需要对 UserDetails 进行定制, 内置的 User 太过简单实际项目无法满足需要.案例说明(基于jpa实现):

@Service
public class JpaReactiveUserDetailsService implements ReactiveUserDetailsService {
private UserRepository userRepository;

@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}

/**
* @param s 用户名
* @return Mono<UserDetails>
*/
@Override
public Mono<UserDetails> findByUsername(String s) {
// 从用户Repository中获取一个User Jpa实体对象
Optional<User> optionalUser = userRepository.findByUsername(s);
if (!optionalUser.isPresent()) {
return Mono.empty();
}
User user = optionalUser.get();

// 填充权限
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : user.getRoles()) {
authorities.add(new (role.getName()));
}

// 返回 UserDetails
return Mono.just(new org.springframework.security.core.userdetails.User(
user.getUsername(), user.getPassword(), authorities
));
}
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByEmail(String email);
@Override
void delete(User user);
Optional<User> findByUsername(String username);
}

6.认证结果处理

如果认证成功(用户名,密码完全正确), AuthenticationProvider 将会返回一个完全有效的 Authentication 对象(UsernamePasswordAuthenticationToken). 否则抛出 AuthenticationException 异常.完全有效的 Authentication 对象定义如下:

authenticated属性为 true 已授权的权限列表(GrantedAuthority列表) 用户凭证(仅用户名)

7.认证完成

认证完成后, AuthenticationManager 将会返回该认证对象(UsernamePasswordAuthenticationToken)返回给过滤器

8.存储认证对象

相关的过滤器获得一个认证对象后, 把它存储在安全上下文中(SecurityContext) 用于后续的授权判断(比如查询,修改等操作).

SecurityContextHolder.getContext().setAuthentication(authentication);

认证架构图

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容