认证过程
- 用户使用用户名和密码进行登录。
- Spring Security将获取到的用户名和密码封装成一个实现了Authentication接口的UsernamePasswordAuthenticationToken。
- 将上述产生的token对象传递给AuthenticationManager进行登录认证。
- AuthenticationManager认证成功后将会返回一个封装了用户权限等信息的Authentication对象。
- 通过调用SecurityContextHolder.getContext().setAuthentication(…)将AuthenticationManager返回的Authentication对象赋予给当前的SecurityContext。
spring security的类
Authentication接口: 表示用户认证信息
SecurityContextHolder: 保存SecurityContext
- 用户登录认证之前相关信息,封装到Authentication接口的具体实现类的对象
- 登录成功后将更全面的信息,封装到Authentication接口的具体实现类的对象,保存在SecurityContextHolder所持有的SecurityContext中
- 通过Authentication.getPrincipal()可以获取到代表当前用户的信息,这个对象通常是UserDetails的实例
AuthenticationManager: 处理认证请求的接口,只有一个方法,认证成功则返回一个封装了当前用户权限等
Authentication authenticate(Authentication authentication) throws AuthenticationException;
- AuthenticationManager的默认实现是ProviderManager,而且它不直接自己处理认证请求,而是委托给其所配置的AuthenticationProvider列表进行认证
- 有一个AuthenticationProvider认证后的结果不为null,则表示该AuthenticationProvider已经认证成功,之后的AuthenticationProvider将不再继续认证。然后直接以该AuthenticationProvider的认证结果作为ProviderManager的认证结果
- 校验认证请求最常用的方法是根据请求的用户名加载对应的UserDetails,然后比对UserDetails的密码与认证请求的密码是否一致,一致则表示认证通过
AuthenticationProvider:
<!-- 自定义AuthenticationProvider -->
<!-- 自定义UserDetailsService -->
<security:authentication-manager>
<security:authentication-provider ref="myAuthenticationProvider" user-service-ref="myUserDetailsService"/>
</security:authentication-manager>
UserDetailsService: UserDetails定义了一些可以获取用户名、密码、权限等与认证相关的信息的方法
- 通过Authentication.getPrincipal()的返回类型是Object,但很多情况下其返回的其实是一个UserDetails的实例
<!-- 用于认证的AuthenticationManager -->
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
user-service-ref="userDetailsService" />
</security:authentication-manager>
<bean id="userDetailsService"
<!--也可以自己重写方法,不使用JdbcDaoImpl-->
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
GrantedAuthority: Authentication的getAuthorities()可以返回当前Authentication对象拥有的权限,即当前用户拥有的权限。其返回值是一个GrantedAuthority类型的数组
从数据库获取用户信息
jdbc-user-service: 定义一个从数据库获取UserDetails的UserDetailsService
<!--
users-by-username-query:指定查询用户信息的SQL:默认sql:select username, password, enabled from users where username = ?
authorities-by-username-query:指定查询用户权限的SQL:默认sql:select username, authority from authorities where username = ?
group-authorities-by-username-query:指定查询用户组权限的SQL:默认sql:select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id
-->
<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service
data-source-ref="dataSource"
users-by-username-query="select username, password, enabled from t_user where username = ?" />
</security:authentication-provider>
</security:authentication-manager>
** 直接使用JdbcDaoImpl**
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService"/>
</security:authentication-manager>
<bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
PasswordEncoder
Spring Security支持的加密算法
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder hash="md5"/>
</security:authentication-provider>
</security:authentication-manager>
属性hash表示我们将用来进行加密的哈希算法
加密算法 | PasswordEncoder实现类 |
---|---|
plaintext | PlaintextPasswordEncoder |
sha | ShaPasswordEncoder |
sha-256 | ShaPasswordEncoder,使用时new ShaPasswordEncoder(256) |
md4 | Md4PasswordEncoder |
md5 | Md5PasswordEncoder |
{sha} | LdapShaPasswordEncoder |
{ssha} | LdapShaPasswordEncoder |
加密时使用salt
指定当前PasswordEncoder需要使用的salt。这个salt可以是一个常量,也可以是当前UserDetails的某一个属性,还可以通过实现SaltSource接口实现自己的获取salt的逻辑,SaltSource中只定义了如下一个方法。
public Object getSalt(UserDetails user);
使用常量“abc”作为salt
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder hash="md5" base64="true">
<security:salt-source system-wide="abc"/>
</security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
使用UserDetails的username作为salt
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder hash="md5" base64="true">
<security:salt-source user-property="username"/>
</security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
使用自己实现的SaltSource获取salt
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder hash="md5" base64="true">
<security:salt-source ref="mySaltSource"/>
</security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>