Spring Security教程(6)---- 使用数据库管理用户及权限
2014-03-13 21:23
796 查看
上一章已经把表结构上传了,今天这部分主要用到的表是
SYS_USERS
用户管理表
SYS_ROLES
角色管理表
SYS_AUTHORITIES权限管理表
SYS_USERS_ROLES用户角色表
SYS_ROLES_AUTHORITIES角色权限表
要实现使用数据库管理用户,需要自定义用户登录功能,而Spring已经为我们提供了接口UserDetailsService
[java] view
plaincopy
package org.springframework.security.core.userdetails;
public interface UserDetailsService {
/**
* Locates the user based on the username. In the actual implementation, the search may possibly be case
* insensitive, or case insensitive depending on how the implementation instance is configured. In this case, the
* <code>UserDetails</code> object that comes back may have a username that is of a different case than what was
* actually requested..
*
* @param username the username identifying the user whose data is required.
*
* @return a fully populated user record (never <code>null</code>)
*
* @throws UsernameNotFoundException if the user could not be found or the user has no GrantedAuthority
*/
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
UserDetailsService是一个接口,只有一个方法loadUserByUsername,根据方法名可以看出这个方法是根据用户名来获取用户信息,但是返回的是一个UserDetails对象。而UserDetails也是一个接口
[java] view
plaincopy
package org.springframework.security.core.userdetails;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import java.io.Serializable;
import java.util.Collection;
//这里省略了Spring的注释,只是我自己对这些方法的简单的注释,如果想了解Spring对这些方法的注释,请查看Spring源码
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities(); //权限集合
String getPassword(); //密码
String getUsername(); //用户名
boolean isAccountNonExpired(); //账户没有过期
boolean isAccountNonLocked(); //账户没有被锁定
boolean isCredentialsNonExpired(); //证书没有过期
boolean isEnabled();//账户是否有效
}
因此我们的SysUsers这个bean需要实现这个接口
[html] view
plaincopy
@Entity
@DynamicUpdate(true)
@DynamicInsert(true)
@Table(name = "SYS_USERS", schema = "FYBJ")
public class SysUsers implements UserDetails,Serializable {
/**
*
*/
private static final long serialVersionUID = -6498309642739707784L;
// Fields
private String userId;
private String username;
private String name;
private String password;
private Date dtCreate;
private Date lastLogin;
private Date deadline;
private String loginIp;
private String VQzjgid;
private String VQzjgmc;
private String depId;
private String depName;
private boolean enabled;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
@JsonIgnore
private Set<SysUsersRoles> sysUsersRoleses = new HashSet<SysUsersRoles>(0);
private Collection<GrantedAuthority> authorities;
//.....省略setter,getter.....
//如果属性是boolean(注:不是Boolean)类型的值,在生产getter时会变为isXxx,如enabled生产getter为isEnabled
}
这样写我们的SysUsers只要生产getter和setter方法就实现了UserDetails,同时还可以使用数据库来控制这些属性,两全其美。
在UserDetails中有个属性需要注意下Collection<GrantedAuthority> authorities,这个属性中存储了这个用户所有的权限。
下面需要先写下SysUsers的DAO层,一个方法是根据用户名获取用户,一个方法是根据用户名获取用户所有的权限,这里我用的是Spring Data Jpa,如果不懂这个请自行从网上查阅资料
[java] view
plaincopy
public interface SysUsersRepository extends JpaRepository<SysUsers, String> {
public SysUsers getByUsername(String username);
public Collection<GrantedAuthority> loadUserAuthorities(String username);
}
其中getByUsername符合Spring的命名规范,所以这个方法不需要我们来实现,而loadUserAuthorities则需要我们自己动手实现
[java] view
plaincopy
public class SysUsersRepositoryImpl {
protected Log logger = LogFactory.getLog(getClass());
@PersistenceContext
private EntityManager entityManager;
/**
* 根据用户名获取到用户的权限并封装成GrantedAuthority集合
* @param username
*/
public Collection<GrantedAuthority> loadUserAuthorities(String username){
List<SysAuthorities> list = this.getSysAuthoritiesByUsername(username);
List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
for (SysAuthorities authority : list) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(authority.getAuthorityMark());
auths.add(grantedAuthority);
}
return auths;
}
/**
* 先根据用户名获取到SysAuthorities集合
* @param username
* @return
*/
@SuppressWarnings("unchecked")
private List<SysAuthorities> getSysAuthoritiesByUsername(String username){
String sql = "SELECT * FROM SYS_AUTHORITIES WHERE AUTHORITY_ID IN( "+
"SELECT DISTINCT AUTHORITY_ID FROM SYS_ROLES_AUTHORITIES S1 "+
"JOIN SYS_USERS_ROLES S2 ON S1.ROLE_ID = S2.ROLE_ID "+
"JOIN SYS_USERS S3 ON S3.USER_ID = S2.USER_ID AND S3.USERNAME=?1)";
Query query = this.entityManager.createNativeQuery(sql, SysAuthorities.class);
query.setParameter(1, username);
List<SysAuthorities> list = query.getResultList();
return list;
}
}
不管是用Spring Data Jpa还是普通的方法只要实现这两个方法就可以了
最后也是最重要的一个类UserDetailsService
[java] view
plaincopy
public class DefaultUserDetailsService implements UserDetailsService {
protected final Log logger = LogFactory.getLog(getClass());
@Autowired
private SysUsersRepository sysUsersRepository;
@Autowired
private MessageSource messageSource;
@Autowired
private UserCache userCache;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
SysUsers user = (SysUsers) this.userCache.getUserFromCache(username);
if(user == null){
user = this.sysUsersRepository.getByUsername(username);
if(user == null)
throw new UsernameNotFoundException(this.messageSource.getMessage(
"UserDetailsService.userNotFount", new Object[]{username}, null));
//得到用户的权限
auths = this.sysUsersRepository.loadUserAuthorities( username );
user.setAuthorities(auths);
}
logger.info("*********************"+username+"***********************");
logger.info(user.getAuthorities());
logger.info("********************************************************");
this.userCache.putUserInCache(user);
return user;
}
}
在loadUserByUsername方法中首先是从缓存中查找用户,如果找到用户就直接用缓存中的用户,如果没有找到就从数据库中获取用户信息。
从数据库中获取用户时先获取User对象,如果用户为空则抛出UsernameNotFoundException,其中UserDetailsService.userNotFount是在property文件中自定义的,如果获取到了user则再获取用户的权限,按照Spring的标准如果没有任何权限也是要抛出这个异常的,在这里我们就不做判断了。
登录后可以看到控制台打印出来以下信息
[plain] view
plaincopy
*********************admin***********************
[AUTH_PASSWORD_MODIFY, AUTH_GG_FBGBGG, AUTH_GG_FBZNGG]
********************************************************
说明我们登录成功并且已经获取到了权限,但是可能会出现如下页面
这样就是你在数据库中存储的权限跟配置文件中的不对应,或者说访问资源是没有从用户的权限集合中找到这个权限。
SYS_USERS
用户管理表
SYS_ROLES
角色管理表
SYS_AUTHORITIES权限管理表
SYS_USERS_ROLES用户角色表
SYS_ROLES_AUTHORITIES角色权限表
要实现使用数据库管理用户,需要自定义用户登录功能,而Spring已经为我们提供了接口UserDetailsService
[java] view
plaincopy
package org.springframework.security.core.userdetails;
public interface UserDetailsService {
/**
* Locates the user based on the username. In the actual implementation, the search may possibly be case
* insensitive, or case insensitive depending on how the implementation instance is configured. In this case, the
* <code>UserDetails</code> object that comes back may have a username that is of a different case than what was
* actually requested..
*
* @param username the username identifying the user whose data is required.
*
* @return a fully populated user record (never <code>null</code>)
*
* @throws UsernameNotFoundException if the user could not be found or the user has no GrantedAuthority
*/
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
UserDetailsService是一个接口,只有一个方法loadUserByUsername,根据方法名可以看出这个方法是根据用户名来获取用户信息,但是返回的是一个UserDetails对象。而UserDetails也是一个接口
[java] view
plaincopy
package org.springframework.security.core.userdetails;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import java.io.Serializable;
import java.util.Collection;
//这里省略了Spring的注释,只是我自己对这些方法的简单的注释,如果想了解Spring对这些方法的注释,请查看Spring源码
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities(); //权限集合
String getPassword(); //密码
String getUsername(); //用户名
boolean isAccountNonExpired(); //账户没有过期
boolean isAccountNonLocked(); //账户没有被锁定
boolean isCredentialsNonExpired(); //证书没有过期
boolean isEnabled();//账户是否有效
}
因此我们的SysUsers这个bean需要实现这个接口
[html] view
plaincopy
@Entity
@DynamicUpdate(true)
@DynamicInsert(true)
@Table(name = "SYS_USERS", schema = "FYBJ")
public class SysUsers implements UserDetails,Serializable {
/**
*
*/
private static final long serialVersionUID = -6498309642739707784L;
// Fields
private String userId;
private String username;
private String name;
private String password;
private Date dtCreate;
private Date lastLogin;
private Date deadline;
private String loginIp;
private String VQzjgid;
private String VQzjgmc;
private String depId;
private String depName;
private boolean enabled;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
@JsonIgnore
private Set<SysUsersRoles> sysUsersRoleses = new HashSet<SysUsersRoles>(0);
private Collection<GrantedAuthority> authorities;
//.....省略setter,getter.....
//如果属性是boolean(注:不是Boolean)类型的值,在生产getter时会变为isXxx,如enabled生产getter为isEnabled
}
这样写我们的SysUsers只要生产getter和setter方法就实现了UserDetails,同时还可以使用数据库来控制这些属性,两全其美。
在UserDetails中有个属性需要注意下Collection<GrantedAuthority> authorities,这个属性中存储了这个用户所有的权限。
下面需要先写下SysUsers的DAO层,一个方法是根据用户名获取用户,一个方法是根据用户名获取用户所有的权限,这里我用的是Spring Data Jpa,如果不懂这个请自行从网上查阅资料
[java] view
plaincopy
public interface SysUsersRepository extends JpaRepository<SysUsers, String> {
public SysUsers getByUsername(String username);
public Collection<GrantedAuthority> loadUserAuthorities(String username);
}
其中getByUsername符合Spring的命名规范,所以这个方法不需要我们来实现,而loadUserAuthorities则需要我们自己动手实现
[java] view
plaincopy
public class SysUsersRepositoryImpl {
protected Log logger = LogFactory.getLog(getClass());
@PersistenceContext
private EntityManager entityManager;
/**
* 根据用户名获取到用户的权限并封装成GrantedAuthority集合
* @param username
*/
public Collection<GrantedAuthority> loadUserAuthorities(String username){
List<SysAuthorities> list = this.getSysAuthoritiesByUsername(username);
List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
for (SysAuthorities authority : list) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(authority.getAuthorityMark());
auths.add(grantedAuthority);
}
return auths;
}
/**
* 先根据用户名获取到SysAuthorities集合
* @param username
* @return
*/
@SuppressWarnings("unchecked")
private List<SysAuthorities> getSysAuthoritiesByUsername(String username){
String sql = "SELECT * FROM SYS_AUTHORITIES WHERE AUTHORITY_ID IN( "+
"SELECT DISTINCT AUTHORITY_ID FROM SYS_ROLES_AUTHORITIES S1 "+
"JOIN SYS_USERS_ROLES S2 ON S1.ROLE_ID = S2.ROLE_ID "+
"JOIN SYS_USERS S3 ON S3.USER_ID = S2.USER_ID AND S3.USERNAME=?1)";
Query query = this.entityManager.createNativeQuery(sql, SysAuthorities.class);
query.setParameter(1, username);
List<SysAuthorities> list = query.getResultList();
return list;
}
}
不管是用Spring Data Jpa还是普通的方法只要实现这两个方法就可以了
最后也是最重要的一个类UserDetailsService
[java] view
plaincopy
public class DefaultUserDetailsService implements UserDetailsService {
protected final Log logger = LogFactory.getLog(getClass());
@Autowired
private SysUsersRepository sysUsersRepository;
@Autowired
private MessageSource messageSource;
@Autowired
private UserCache userCache;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
SysUsers user = (SysUsers) this.userCache.getUserFromCache(username);
if(user == null){
user = this.sysUsersRepository.getByUsername(username);
if(user == null)
throw new UsernameNotFoundException(this.messageSource.getMessage(
"UserDetailsService.userNotFount", new Object[]{username}, null));
//得到用户的权限
auths = this.sysUsersRepository.loadUserAuthorities( username );
user.setAuthorities(auths);
}
logger.info("*********************"+username+"***********************");
logger.info(user.getAuthorities());
logger.info("********************************************************");
this.userCache.putUserInCache(user);
return user;
}
}
在loadUserByUsername方法中首先是从缓存中查找用户,如果找到用户就直接用缓存中的用户,如果没有找到就从数据库中获取用户信息。
从数据库中获取用户时先获取User对象,如果用户为空则抛出UsernameNotFoundException,其中UserDetailsService.userNotFount是在property文件中自定义的,如果获取到了user则再获取用户的权限,按照Spring的标准如果没有任何权限也是要抛出这个异常的,在这里我们就不做判断了。
登录后可以看到控制台打印出来以下信息
[plain] view
plaincopy
*********************admin***********************
[AUTH_PASSWORD_MODIFY, AUTH_GG_FBGBGG, AUTH_GG_FBZNGG]
********************************************************
说明我们登录成功并且已经获取到了权限,但是可能会出现如下页面
这样就是你在数据库中存储的权限跟配置文件中的不对应,或者说访问资源是没有从用户的权限集合中找到这个权限。
相关文章推荐
- Spring Security教程(6)---- 使用数据库管理用户及权限
- Spring Security教程(6)---- 使用数据库管理用户及权限
- Spring Security教程(6)---- 使用数据库管理用户及权限
- Spring Security教程(11)---- 使用数据库来管理资源
- phpMyAdmin使用教程:[2]用户及权限管理
- 使用navicat 8实现创建数据库和导入数据 管理用户与权限[图文方法]
- Spring Security教程(11)---- 使用数据库来管理资源
- 使用navicat 8实现创建数据库和导入数据 管理用户与权限[图文方法]
- 第 2 章 使用数据库管理用户权限
- Jenkins使用教程之用户权限管理(包含插件的安装)
- Spring Security教程(12)---- 使用数据库来管理方法
- Spring Security 引用数据库管理用户权限-----login.jsp 提示"用户名或密码错误"
- Spring Security教程(12)---- 使用数据库来管理方法
- Jenkins使用教程之用户权限管理(包含插件的安装)
- Spring Security教程(12)---- 使用数据库来管理方法
- Spring Security教程(11)---- 使用数据库来管理资源
- Spring Security教程(11)---- 使用数据库来管理资源
- 【Spring Security】二、数据库管理用户权限
- 第 2 章 使用数据库管理用户权限
- mongodb authentication 设置权限之后,新建个管理账户和一般数据库用户,在win 7 64bit 环境下测试使用实例