Spring Security 之自定义UserDetails

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Security 之自定义UserDetails相关的知识,希望对你有一定的参考价值。

  Spring Security(以下简称SS)中默认存在一个org.springframework.security.core.userdetails.UserDetails类,该类是SS内置的,提供了几个简单的属性,如userName,password,enabled等等,但这些属性不能完全适应我们现在的系统,所有一般需要自定义自己的UserDetails。自定义UserDetails需要继承SS内置的UserDetails,之所以继承内置的UserDetails,是因为在SS中可以通过SecurityContextHolder取得用户凭证和用户所有的信息,用户信息都存放在系统内置的UserDetails中,如果继承之后,即可进行向下转型,变成我们自己的定义的UserDetails了。

  参考代码如下,以下自定义的UserDetails中加入了用户拥有的设备,用户角色,用户权限等等,假设我需要在用户登录之后就加载这些用户关联的信息,那么加入UserDetails之后,在任何位置就能通过SecurityContextHolder取到了。

技术分享
 1 /**
 2  * 
 3  * @author bigbang 通过扩展UserDetails接口扩展自己的用户信息
 4  */
 5 public class MyUserDetails implements UserDetails {
 6 
 7     private static final long serialVersionUID = 1L;
 8     private User user;
 9     private List<Privilege> privileges;
10     private Collection<GrantedAuthority> roles;
11     private List<Device> devices;
12 
13     public MyUserDetails() {
14     }
15 
16     public MyUserDetails(User user, List<Privilege> privileges, Collection<GrantedAuthority> roles, List<Device> devices) {
17         super();
18         this.user = user;
19         this.privileges = privileges;
20         this.roles = roles;
21         this.devices = devices;
22     }
23 
24     public List<Privilege> getPrivileges() {
25         return privileges;
26     }
27 
28     public List<Device> getDevices() {
29         return devices;
30     }
31 
32     @Override
33     public Collection<? extends GrantedAuthority> getAuthorities() {
34         return this.roles;
35     }
36 
37     @Override
38     public String getPassword() {
39         return user.getPassWord();
40     }
41 
42     @Override
43     public String getUsername() {
44         return user.getUserName();
45     }
46 
47     @Override
48     public boolean isAccountNonExpired() {
49         return true;
50     }
51 
52     @Override
53     public boolean isAccountNonLocked() {
54         return true;
55     }
56 
57     @Override
58     public boolean isCredentialsNonExpired() {
59         return true;
60     }
61 
62     @Override
63     public boolean isEnabled() {
64         return true;
65     }
66 
67     public User getUser() {
68         return user;
69     }
70 
71     public void setUser(User user) {
72         this.user = user;
73     }
74 
75     public Collection<GrantedAuthority> getRoles() {
76         return roles;
77     }
78 
79     public void setRoles(Collection<GrantedAuthority> roles) {
80         this.roles = roles;
81     }
82 
83     public void setPrivileges(List<Privilege> privileges) {
84         this.privileges = privileges;
85     }
86 
87     public void setDevices(List<Device> devices) {
88         this.devices = devices;
89     }
90 
91 }
View Code

  

  在定义之后,接着就是怎么使用了。因为使用了自己的凭证信息,所以必须在ss的配置文件中加入自定义的认证管理器(AuthenticationManager)与认证数据容器(AuthenticationProvider).

  第一步是在http标签添加认证管理器:

1 <http auto-config="true" use-expressions="true" authentication-manager-ref="myAuthenticationManager">
2 </http>

  第二步在认证管理器中添加认证容器:

  

1     <authentication-manager id="myAuthenticationManager">
2         <authentication-provider user-service-ref="accountSecurityService">
3             <password-encoder hash="bcrypt" base64="true"/>
4         </authentication-provider>
5     </authentication-manager>

  它其中指定了一个用户信息服务,那么对应关系即可以理解为: 用户信息服务——>认证数据提供者——>认证管理器,通过一层层包装用户数据。

  自定义用户信息服务才是我们真正使用自定义UserDetails的核心,它实现了UserDetailsService接口,它所需要实现的方法只有一个 loadUserByUserName(String userName),返回UserDetails对象。就是根据用户名查询出一个UserDetails。此时我们可以返回一个自定义的UserDetails。  

  

 1 public class AccountSecurityService implements UserDetailsService {
 2 
 3     @Autowired
 4     private IUserService userService;
 5 
 6     @Override
 7     public UserDetails loadUserByUsername(String userName)
 8             throws UsernameNotFoundException {
 9         MyUserDetails details = null;
10         com.bigbang.entity.User user = userService.getUserDetail(userName); //查询一次用户所有关联信息
11         if (user == null)
12             return null;
13         details = new MyUserDetails(user,null,null,null);
14         return details;
15     }
16 
17 }

  此处仅仅是查询出了用户的基本信息,与用户相关联的角色与设备并没有设置进去,这样做的好处是防止用户如果登录多次就会多次查询,如果登录失败同样也会查询,造成不必要的查询。那么这部分信息,我们可以放到登录成功之后查询,这部分属于认证阶段,暂时不说。

  

以上是关于Spring Security 之自定义UserDetails的主要内容,如果未能解决你的问题,请参考以下文章

spring boot整合 spring security之自定义认证

Tomcat 重启后 Spring Security 主体未完全填充

Spring之自定义事件

[死磕 Spring 35/43] --- IOC 之自定义类型转换器

[死磕 Spring 35/43] --- IOC 之自定义类型转换器

[死磕 Spring 35/43] --- IOC 之自定义类型转换器