博客
关于我
Spring Security 架构与源码分析
阅读量:671 次
发布时间:2019-03-16

本文共 3427 字,大约阅读时间需要 11 分钟。

Spring Security 是一个强大的框架,用于实现认证和访问控制(授权)。它通过分离认证和授权两大部分,提供了灵活的配置和扩展,适用于各种复杂的安全需求。以下将从认证和授权两个方面详细阐述 Spring Security 的工作原理及其实现细节。

认证

认证的核心是通过 AuthenticationManager 来完成的。它是一个接口,主要提供了一个方法:authenticate(Authentication authentication)。这个方法的作用是接受一个 Authentication 实例,并根据其是否有效,返回一个 Authentication 对象或者抛出一个 AuthenticationException。

默认实现是 ProviderManager,它负责通过一系列 AuthenticationProvider 来完成认证。每个 AuthenticationProvider 都需要实现两个关键方法:authenticate(Authentication authentication) 和 supports(Class<?> authentication)。

  • authenticate 方法用于进行实际的认证,可能会调用 UserDetailsService 来获取用户信息,并通过 PasswordEncoder 来验证密码是否正确。
  • supports 方法用于检查该 Provider 是否能够支持某一种类型的 Authentication。

常见的 AuthenticationToken 实现

大多数应用程序会使用 UsernamePasswordAuthenticationToken,因为它可以处理用户名和密码的认证。以下是其代码结构:

public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {	...	public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {		...	}

在实际应用中,认证过程遵循以下步骤:

  • 创建一个 UsernamePasswordAuthenticationToken,填充 username 和 password。
  • 调用 AuthenticationManager 的 authenticate 方法,执行认证。
  • 如果认证成功,AuthenticationManager 会返回一个 Authentication 对象,并将其存储在 SecurityContextHolder 中。
  • 如果认证失败,可能会抛出一个 AuthenticationException。
  • 用户信息和密码验证

    在认证过程中,UserDetailsService 负责获取用户信息。它通过 loadUserByUsername(String username) 方法返回一个 UserDetails 对象。默认实现是 DaoAuthenticationProvider,它通过数据库查询用户信息,并使用 PasswordEncoder 来验证密码的正确性。

    public interface UserDetailsService {	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;}

    UserDetails 提供了用户的基本信息,如 username、password、roles 等。开发者可以根据需求自定义实现这个接口,扩展用户的属性。

    核心对象解析

    • SecurityContextHolder:用于存储和获取 SecurityContext,默认使用 ThreadLocal 达到线程安全。
    • SecurityContext:存储应用的 principal 信息,而 Authentication 对象代表凭证。
    • Authentication:通常由多个 Provider 组成,完成认证并返回一个 principal(用户信息)。

    授权与访问控制

    一旦认证成功,系统需要进行授权。Spring Security通过 AccessDecisionManager 来实现授权,默认使用 AffirmativeBased 框架,通过多个 AccessDecisionVoter 来做出决策。

    AccessDecisionVoter

    AccessDecisionVoter 负责对特定的资源进行访问判断。它通过 supports(ConfigAttribute attribute) 方法检查是否支持某个配置属性,vote 方法则进行投票。

    public abstract class AbstractAccessDecisionVoter implements AccessDecisionVoter {	...}

    Classics 的一个实现是 RoleVoter,它通过检查 Authentication 中的 GrantedAuthority,判断是否有访问某个资源的权限。例如:

    public class RoleVoter implements AccessDecisionVoter {	@Override	public boolean supports(ConfigAttribute attribute) {		// 检查 ConfigAttribute 是否以指定的前缀开始		return true;	}	@Override	public int vote(Authentication authentication, Object object, Collection
    attributes) { // 提取用户的权限,判断是否满足 ConfigAttribute 条件 return ACCESS_GRANTED; }}

    核心组件解析

    • AccessDecisionManager:默认使用 AffirmativeBased,通过多个 AccessDecisionVoter 来进行联合决策。
    • GrantedAuthority:表示一个权限,如 ROLE_ADMIN、ROLE_USER 等。
    • ConfigAttribute:资源访问所需的属性,如 path、method、roles 等。

    权限判断与访问控制

    • @PreAuthorize:可在控制器方法或其他逻辑中使用,用于前置检查权限。其底层通过 DefaultPermissionEvaluator 来解析权限。
    • @PostAuthorize:用于在方法执行后进行权限检查,适用于动态变化的权限情况。
    • 权限合成:通过合成安全元件(如 CombinedSecurityMetadataSource),从多个安全元件中获取权限信息,支持联合权限验证。

    实际应用中的配置与扩展

    在实际应用中,开发者可以通过配置来个性化认证和授权:

  • WebSecurityConfigurerAdapter:用于配置 WebSecurity,集成 Telnet、LDAP、数据库等认证方式。
  • PasswordEncoder:用于密码加密和验证,常用MD5PasswordEncoder。
  • UserDetailsService 和 DaoAuthenticationProvider:用于获取用户信息和验证密码,开发者可以自定义实现以支持不同的用户存储和检索方式。
  • PermissionEvaluator:用于定制权限判断逻辑,扩展 Spring Security 的默认权限评估机制。
  • 小结

    Spring Security通过清晰的分层结构和灵活的配置选项,提供了强大的认证和授权功能。从简单的 username-password 认证到复杂的基于角色的访问控制,框架都提供了良好的支持。通过正确配置和定制,开发者可以根据实际需求实现高效且安全的应用程序。

    参考资料

    转载地址:http://uysqz.baihongyu.com/

    你可能感兴趣的文章
    MySqL双机热备份(二)--MysqL主-主复制实现
    查看>>
    MySQL各个版本区别及问题总结
    查看>>
    MySql各种查询
    查看>>
    mysql同主机下 复制一个数据库所有文件到另一个数据库
    查看>>
    mysql启动以后会自动关闭_驾照虽然是C1,一直是开自动挡的车,会不会以后就不会开手动了?...
    查看>>
    mysql启动和关闭外键约束的方法(FOREIGN_KEY_CHECKS)
    查看>>
    Mysql启动失败解决过程
    查看>>
    MySQL启动失败:Can't start server: Bind on TCP/IP port
    查看>>
    mysql启动报错
    查看>>
    mysql启动报错The server quit without updating PID file几种解决办法
    查看>>
    MySQL命令行登陆,远程登陆MySQL
    查看>>
    mysql命令:set sql_log_bin=on/off
    查看>>
    mySQL和Hive的区别
    查看>>
    MySQL和Java数据类型对应
    查看>>
    mysql和oorcale日期区间查询【含左右区间问题】
    查看>>
    MYSQL和ORACLE的一些操作区别
    查看>>
    mysql和redis之间互相备份
    查看>>
    MySQL和SQL入门
    查看>>
    mysql在centos下用命令批量导入报错_Variable ‘character_set_client‘ can‘t be set to the value of ‘---linux工作笔记042
    查看>>
    Mysql在Linux运行时新增配置文件提示:World-wrirable config file ‘/etc/mysql/conf.d/my.cnf‘ is ignored 权限过高导致
    查看>>