SpringSecurity动态加载用户角色权限实现登陆及鉴权

file

不少人以为Spring Security实现登陆验证很难,我最开始学习的时候也这样以为。由于我很久都没看懂我该怎么样将本身写的用于接收用户名密码的Controller与Spring Security结合使用,这是一个先入为主的误区。后来我搞懂了:根本不用你本身去写Controller。你只须要告诉Spring Security用户信息、角色信息、权限信息、登陆页是什么?登录成功页是什么?或者其余有关登陆的一切信息。具体的登陆验证逻辑它来帮你实现。html

1、动态数据登陆验证的基础知识

在本号以前的文章中,已经介绍了Spring Security的formLogin登陆认证模式,RBAC的权限控制管理模型,而且针对Spring Security的登陆认证逻辑源码进行了解析等等。咱们全部的用户、角色、权限信息都是在配置文件里面写死的,然而在实际的业务系统中,这些信息一般是存放在RBAC权限模型的数据库表中的。下面咱们来回顾一下其中的核心概念:java

  • RBAC的权限模型能够从用户获取为用户分配的一个或多个角色,从用户的角色又能够获取该角色的多种权限。经过关联查询能够获取某个用户的角色信息和权限信息。
  • 在源码解析的文章中,咱们知道若是咱们不但愿用户、角色、权限信息写死在配置里面。咱们应该实现UserDetails与UserDetailsService接口,从而从数据库或者其余的存储上动态的加载这些信息。

以上是对一些核心的基础知识的总结,若是您对这些知识还不是很清晰,建议您先往下读本文。若是看完本文仍然理解困难,建议您翻看本号以前的文章。spring

2、UserDetails与UserDetailsService接口

  • UserDetailsService接口有一个方法叫作loadUserByUsername,咱们实现动态加载用户、角色、权限信息就是经过实现该方法。函数见名知义:经过用户名加载用户。该方法的返回值就是UserDetails。
  • UserDetails就是用户信息,即:用户名、密码、该用户所具备的权限。

下面咱们来看一下UserDetails接口都有哪些方法。数据库

public interface UserDetails extends Serializable {
    //获取用户的权限集合
    Collection<!--? extends GrantedAuthority--> getAuthorities();

    //获取密码
    String getPassword();

    //获取用户名
    String getUsername();

    //帐号是否没过时
    boolean isAccountNonExpired();

    //帐号是否没被锁定
    boolean isAccountNonLocked();

    //密码是否没过时
    boolean isCredentialsNonExpired();

    //帐户是否可用
    boolean isEnabled();
}

如今,咱们明白了,只要咱们把这些信息提供给Spring Security,Spring Security就知道怎么作登陆验证了,根本不须要咱们本身写Controller实现登陆验证逻辑。springboot

3、实现UserDetails 接口

public class SysUser implements UserDetails{
    
    String password();  //密码
    String username();  //用户名
    boolean accountNonExpired;   //是否没过时
    boolean accountNonLocked;   //是否没被锁定
    boolean credentialsNonExpired;  //是否没过时
    boolean enabled;  //帐号是否可用
    Collection<!--? extends GrantedAuthority--> authorities;  //用户的权限集合

    //省略构造方法
    //省略set方法
    //省略get方法(即接口UserDetails的方法)
}

咱们就是写了一个适应于UserDetails的java POJO类,所谓的 UserDetails接口实现就是一些get方法。get方法由Spring Security调用,咱们经过set方法或构造函数为 Spring Security提供UserDetails数据。ide

4、实现UserDetailsService接口

@Component
public class MyUserDetailsService implements UserDetailsService{

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            
       //这里从数据库sys_user表里面查询实体类对象。loadUser方法可以使用Mybatis或JDBC或JPA自行实现。
       SysUser sysUser =  loadUser(username);   

        // 判断用户是否存在 
       if(user == null)  {  throw  new  UsernameNotFoundException("用户名不存在");  }

       //从数据库该用户全部的角色信息,全部的权限标志
       //遍历全部的ROLE角色及全部的Authority权限(菜单、按钮)。
       //用逗号分隔他们的惟一标志,具体过程自行实现。
       sysUser.setAuthorities(
               AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_AMIN , system:user:delete"));
        
        //sysUser.setAccountNonLocked(true或false);
        return sysUser;
    }
}
  • 一般数据库表sys_user字段要和SysUser属性一一对应,好比username、password、enabled。可是好比accountNonLocked字段用于登陆屡次错误锁定,但咱们通常不会在表里存是否锁定,而是存一个锁定时间字段。经过锁定时间是否大于当前时间判断帐号是否锁定,因此实现过程当中能够灵活作判断并用好set方法,没必要拘泥于一一对应的形式。
  • 角色是一种特殊的权限,在Spring Security咱们可使用hasRole(角色标识)表达式判断用户是否具备某个角色,决定他是否能够作某个操做;经过hasAuthority(权限标识)表达式判断是否具备某个操做权限。

5、最后说明

至此,咱们将系统里面的全部的用户、角色、权限信息都经过UserDetailsService和UserDetails告知了Spring Security。可是多数朋友可能仍然不知道该怎样实现登陆的功能,其实剩下的事情很简单了:函数

  • 写一个登陆界面,写一个登陆表单,表单使用post方法提交到默认的/login路径
  • 表单的用户名、密码字段名称默认是username、password。
  • 写一个登陆成功以后的跳转页面,好比index.html

而后把这些信息经过配置方式告知Spring Security ,以上的配置信息名称均可以灵活修改。若是您不知道如何配置请参考本号以前的文章《formLogin登陆认证模式》。post

期待您的关注

相关文章
相关标签/搜索