Spring Security教程(6)---- 使用数据库管理用户及权限

来源:互联网 发布:客户数据怎么划分 编辑:程序博客网 时间:2024/05/18 03:22

上一章已经把表结构上传了,今天这部分主要用到的表是

  • SYS_USERS  用户管理表
  • SYS_ROLES  角色管理表
  • SYS_AUTHORITIES权限管理表
  • SYS_USERS_ROLES用户角色表
  • SYS_ROLES_AUTHORITIES角色权限表

要实现使用数据库管理用户,需要自定义用户登录功能,而Spring已经为我们提供了接口UserDetailsService

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package org.springframework.security.core.userdetails;  
  2.   
  3. public interface UserDetailsService {  
  4.   
  5.     /** 
  6.      * Locates the user based on the username. In the actual implementation, the search may possibly be case 
  7.      * insensitive, or case insensitive depending on how the implementation instance is configured. In this case, the 
  8.      * <code>UserDetails</code> object that comes back may have a username that is of a different case than what was 
  9.      * actually requested.. 
  10.      * 
  11.      * @param username the username identifying the user whose data is required. 
  12.      * 
  13.      * @return a fully populated user record (never <code>null</code>) 
  14.      * 
  15.      * @throws UsernameNotFoundException if the user could not be found or the user has no GrantedAuthority 
  16.      */  
  17.     UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;  
  18. }  

UserDetailsService是一个接口,只有一个方法loadUserByUsername,根据方法名可以看出这个方法是根据用户名来获取用户信息,但是返回的是一个UserDetails对象。而UserDetails也是一个接口

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package org.springframework.security.core.userdetails;  
  2.   
  3. import org.springframework.security.core.Authentication;  
  4. import org.springframework.security.core.GrantedAuthority;  
  5.   
  6. import java.io.Serializable;  
  7. import java.util.Collection;  
  8. //这里省略了Spring的注释,只是我自己对这些方法的简单的注释,如果想了解Spring对这些方法的注释,请查看Spring源码  
  9. public interface UserDetails extends Serializable {  
  10.       
  11.     Collection<? extends GrantedAuthority> getAuthorities(); //权限集合  
  12.      
  13.     String getPassword(); //密码  
  14.   
  15.     String getUsername(); //用户名  
  16.   
  17.     boolean isAccountNonExpired(); //账户没有过期  
  18.   
  19.     boolean isAccountNonLocked();  //账户没有被锁定  
  20.   
  21.     boolean isCredentialsNonExpired(); //证书没有过期  
  22.   
  23.     boolean isEnabled();//账户是否有效  
  24. }  

因此我们的SysUsers这个bean需要实现这个接口

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Entity  
  2. @DynamicUpdate(true)  
  3. @DynamicInsert(true)  
  4. @Table(name = "SYS_USERS"schema = "FYBJ")  
  5. public class SysUsers implements UserDetails,Serializable {  
  6.   
  7.     /**  
  8.      *   
  9.      */  
  10.     private static final long serialVersionUID = -6498309642739707784L;  
  11.       
  12.     // Fields  
  13.   
  14.     private String userId;  
  15.     private String username;  
  16.     private String name;  
  17.     private String password;  
  18.     private Date dtCreate;  
  19.     private Date lastLogin;  
  20.     private Date deadline;  
  21.     private String loginIp;  
  22.     private String VQzjgid;  
  23.     private String VQzjgmc;  
  24.     private String depId;  
  25.     private String depName;  
  26.     private boolean enabled;  
  27.     private boolean accountNonExpired;  
  28.     private boolean accountNonLocked;  
  29.     private boolean credentialsNonExpired;  
  30.     @JsonIgnore  
  31.     private Set<SysUsersRoles> sysUsersRoleses = new HashSet<SysUsersRoles>(0);  
  32.       
  33.     private Collection<GrantedAuthority>  authorities;  
  34.       
  35.     //.....省略setter,getter.....  
  36.     //如果属性是boolean(注:不是Boolean)类型的值,在生产getter时会变为isXxx,如enabled生产getter为isEnabled  
  37. }  
这样写我们的SysUsers只要生产getter和setter方法就实现了UserDetails,同时还可以使用数据库来控制这些属性,两全其美。

在UserDetails中有个属性需要注意下Collection<GrantedAuthority>  authorities,这个属性中存储了这个用户所有的权限。

下面需要先写下SysUsers的DAO层,一个方法是根据用户名获取用户,一个方法是根据用户名获取用户所有的权限,这里我用的是Spring Data Jpa,如果不懂这个请自行从网上查阅资料

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public interface SysUsersRepository extends JpaRepository<SysUsers, String> {  
  2.       
  3.     public SysUsers getByUsername(String username);  
  4.       
  5.     public Collection<GrantedAuthority> loadUserAuthorities(String username);  
  6.       
  7. }  
其中getByUsername符合Spring的命名规范,所以这个方法不需要我们来实现,而loadUserAuthorities则需要我们自己动手实现

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class SysUsersRepositoryImpl {  
  2.       
  3.     protected Log logger = LogFactory.getLog(getClass());  
  4.       
  5.     @PersistenceContext  
  6.     private EntityManager entityManager;  
  7.       
  8.     /** 
  9.      * 根据用户名获取到用户的权限并封装成GrantedAuthority集合 
  10.      * @param username 
  11.      */  
  12.     public Collection<GrantedAuthority> loadUserAuthorities(String username){  
  13.         List<SysAuthorities> list = this.getSysAuthoritiesByUsername(username);  
  14.           
  15.         List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();  
  16.           
  17.         for (SysAuthorities authority : list) {  
  18.             GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(authority.getAuthorityMark());  
  19.             auths.add(grantedAuthority);  
  20.         }  
  21.   
  22.         return auths;  
  23.           
  24.     }  
  25.     /** 
  26.      * 先根据用户名获取到SysAuthorities集合 
  27.      * @param username 
  28.      * @return 
  29.      */  
  30.     @SuppressWarnings("unchecked")  
  31.     private List<SysAuthorities> getSysAuthoritiesByUsername(String username){  
  32.         String sql = "SELECT * FROM SYS_AUTHORITIES WHERE AUTHORITY_ID IN( "+  
  33.                 "SELECT DISTINCT AUTHORITY_ID FROM SYS_ROLES_AUTHORITIES  S1 "+  
  34.                 "JOIN SYS_USERS_ROLES S2 ON S1.ROLE_ID = S2.ROLE_ID "+  
  35.                 "JOIN SYS_USERS S3 ON S3.USER_ID = S2.USER_ID AND S3.USERNAME=?1)";  
  36.           
  37.         Query query = this.entityManager.createNativeQuery(sql, SysAuthorities.class);  
  38.         query.setParameter(1, username);  
  39.           
  40.         List<SysAuthorities> list = query.getResultList();  
  41.         return list;  
  42.     }  
  43. }  
不管是用Spring Data Jpa还是普通的方法只要实现这两个方法就可以了

最后也是最重要的一个类UserDetailsService

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class DefaultUserDetailsService implements UserDetailsService {  
  2.   
  3.     protected final Log logger = LogFactory.getLog(getClass());  
  4.       
  5.     @Autowired  
  6.     private SysUsersRepository sysUsersRepository;  
  7.       
  8.     @Autowired  
  9.     private MessageSource messageSource;  
  10.       
  11.     @Autowired  
  12.     private UserCache userCache;  
  13.       
  14.     @Override  
  15.     public UserDetails loadUserByUsername(String username)  
  16.             throws UsernameNotFoundException {  
  17.           
  18.         Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();  
  19.         SysUsers user = (SysUsers) this.userCache.getUserFromCache(username);  
  20.           
  21.         if(user == null){  
  22.             user = this.sysUsersRepository.getByUsername(username);  
  23.             if(user == null)  
  24.                 throw new UsernameNotFoundException(this.messageSource.getMessage(  
  25.                         "UserDetailsService.userNotFount"new Object[]{username}, null));  
  26.             //得到用户的权限  
  27.             auths = this.sysUsersRepository.loadUserAuthorities( username );  
  28.               
  29.             user.setAuthorities(auths);  
  30.         }  
  31.           
  32.         logger.info("*********************"+username+"***********************");  
  33.         logger.info(user.getAuthorities());  
  34.         logger.info("********************************************************");  
  35.           
  36.         this.userCache.putUserInCache(user);  
  37.           
  38.         return user;  
  39.     }  
  40.   
  41. }  

在loadUserByUsername方法中首先是从缓存中查找用户,如果找到用户就直接用缓存中的用户,如果没有找到就从数据库中获取用户信息。

从数据库中获取用户时先获取User对象,如果用户为空则抛出UsernameNotFoundException,其中UserDetailsService.userNotFount是在property文件中自定义的,如果获取到了user则再获取用户的权限,按照Spring的标准如果没有任何权限也是要抛出这个异常的,在这里我们就不做判断了。

登录后可以看到控制台打印出来以下信息

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. *********************admin***********************  
  2. [AUTH_PASSWORD_MODIFY, AUTH_GG_FBGBGG, AUTH_GG_FBZNGG]  
  3. ********************************************************  
说明我们登录成功并且已经获取到了权限,但是可能会出现如下页面


这样就是你在数据库中存储的权限跟配置文件中的不对应,或者说访问资源是没有从用户的权限集合中找到这个权限。

0 0
原创粉丝点击