序言
这一篇主要讲的是怎么加载用户信息,以及用户信息的认证
1.加载用户信息
1.1 内存加载
<!--认证管理器 -->
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider>
<security:user-service>
<security:user name="user" password="user" authorities="ROLE_USER" />
<security:user name="admin" password="admin" authorities="ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
- authentication-manage(认证管理器) 顾名思义就是用来管理认证的,不管是用户角色还是资源角色,还是其他的认证都是由authenticationManage来管理的。
- authentication-provider(认证提供者) ,认证管理器不直接提供认证,而是有认证提供者来实现具体的认证。
1.2 数据库加载
在我们的实际项目中内存加载的方式肯定是不行的,我们用户信息都是存在数据库中的。
这时我们就要改写authentication-provider中的user-service,注入我们自己的UserDetailsService类来加载用户信息
<security:authentication-manager alias="authenticationManager">
<!-- 数据库方式加载用户信息 -->
<security:authentication-provider user-service-ref="sysUserDetailsService"/>
</security:authentication-manager>
1.2.1 UserDetailsService
可以看到这是一个接口,用来加载用户信息的
可以看到这个类很简单就一个方法,只要继承这个类,实现这个方法就可以。
1.2.2 UserDetails
在UserDetailsService的返回值类型中我们可以知道UserDetails就是我们的用户信息了,我们要做的就是实现这个接口。UserDetails类中方法如下:
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities(); //角色集合
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
1.2.3 GrantedAuthority
从UserDetails的getAuthorities() 方法我们可以看出来,用户角色是一个集合,同时集合中元素必须继了GrantedAuthority.
可以看到GrantedAuthority方法也很简单,只有一个getAuthority() 方法。如果我们不想实现GrantedAuthority接口也没有关系,毕竟为了一个字段实现一个接口是没有必要的。Spring Security为我们提供了三个默认的实现,我们通常用的是SimpleGrantedAuthority类。
1.2.4 SimpleGrantedAuthority
我们来看看SimpleGrantedAuthority类
可以看到SimpleGrantedAuthority只有一个接受String类型的构造器,说明我们在使用的过程中只需传入一个String类型的字符串。
1.2.5 例:
UserDetailsService
可以看到findUserByName方法返回一个SysUserDetails,SysUserDetails继承了UserDetails。同时在用户登录时使用SimpleGrantedAuthority类加入登录角色。UserDetails
在这里我没有直接实现UserDetails方法,而是使用抽象类SysUserDetails实现了UserDetails的getAuthorities(),同时新增了getRoles和setRoles方法,因为Spring Security中要在权限中加入ROLE 前缀,这样可以在抽象类中统一处理。然后我在继承SysUserDetails类,同时加入自定义的字段。
2. 用户信息认证
我们加载了用户信息后,下一步就进行用户信息的验证。我们先配置自己的认证实现,改写上面的authentication-manager
<!--认证管理器 (自定义 ) -->
<security:authentication-manager alias="sysAuthenticationManager">
<!-- 身份验证(自定义) -->
<security:authentication-provider ref="sysAuthenticationProvider"/>
</security:authentication-manager>
2 .1 AuthenticationProvider
要自定义认证,首先实现AuthenticationProvider接口。
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
boolean supports(Class<?> authentication);
}
2.2 例
@Service
public class SysAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String name = authentication.getName(); // 用户名
String password =authentication.getCredentials().toString(); //密码
//这里是我们自定义的用户加载方法
UserDetails userDetails =userDetailsService.loadUserByUsername(name);
if(userDetails == null){
throw new AuthenticationServiceException("用户名不存在!!!");
}
Mademd5 mad=new Mademd5();//MD5加密
if(!userDetails.getPassword().equals(mad.toMd5(password))){
throw new BadCredentialsException("密码错误");
}
if(userDetails.getAuthorities() == null){
throw new AuthenticationServiceException(userDetails.getUsername()+"尚未分配角色!!!");
}
//把用户信息封装成UsernamePasswordAuthenticationToken对象。
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
3. 总结
以上就是用户信息的加载和验证了。