SpringBoot整合Shiro实现权限控制

步骤一

pom.xml中添加shiro的依赖:



    org.apache.shiro
    shiro-spring
    1.4.0

步骤二

建立相关数据表:用户表用户-角色表角色表角色-权限表权限表。由于不同的项目表中的数据项不同所以下面仅列出较为重要的属性,其他的属性可根据实际需求自行添加。(这里采用的是Hibernate注解方式自动建表)

  • 用户表:
@Entity
@Table(name = "tb_admin")
public class Admin {

    /**
     * 用户名/工号
     * 

* 长度为9 * 示例 201904001 */ @Id @Column(length = 9) private String username; /** * 密码 */ @Column(nullable = false, length = 20) private String password; /** * 角色列表 *

* 一个用户可以有多个角色 */ @ManyToMany(fetch = FetchType.EAGER) //立即从数据库中加载数据 @JoinTable(name = "tb_admin_role", joinColumns = {@JoinColumn(name = "username")}, inverseJoinColumns = {@JoinColumn(name = "roleId")}) private List roleList; public Admin() { } //省略get set方法 }

  • 角色表:
@Entity
@Table(name = "tb_role")
public class Role {

    /**
     * roleId
     * 

* 自增序列 */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int roleId; /** * 角色字符串 *

* 用于角色控制 * 不能为空 */ @Column(length = 50, nullable = false) private String role; // 用户 - 角色关系定义; @ManyToMany @JoinTable(name = "tb_admin_role", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "username")}) private List adminList;// 一个角色对应多个用户 // 角色 - 权限关系定义; @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "tb_role_permission", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "permissionId")}) private List permissionList;// 一个角色有多个权限 public Role() { } //省略get set方法 }

  • 权限表:
@Entity
@Table(name = "tb_permission")
public class Permission {

    /**
     * permissionId
     * 

* 自增序列 */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int permissionId; /** * 权限字符串 *

* 用于权限控制 * 不能为空 */ @Column(length = 50, nullable = false) private String permission; // 角色 - 权限关系定义; @ManyToMany @JoinTable(name = "tb_role_permission", joinColumns = {@JoinColumn(name = "permissionId")}, inverseJoinColumns = {@JoinColumn(name = "roleId")}) private List roleList;// 一个角色有多个权限 public Permission() { } //省略get set方法 }

  • 用户-角色表:
@Entity
@Table(name = "tb_admin_role")
public class AdminRole {

    /**
     * id
     * 

* 自增序列 */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; /** * 管理员Id */ @Column(nullable = false,length = 9) private String username; /** * 角色id */ @Column(nullable = false) private int roleId; public AdminRole() { } //省略get set方法 }

  • 角色-权限表:
@Entity
@Table(name = "tb_role_permission")
public class RolePermission {

    /**
     * id
     * 

* 自增序列 */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; /** * 角色Id */ @Column(nullable = false) private int roleId; /** * 权限id */ @Column(nullable = false) private int permissionId; public RolePermission() { } //省略get set方法 }

至此,环境搭好了,相关数据表也建好了,接下来只需要通过shiro进行关联配置即可。

步骤三

新建ShiroConfig配置文件:

@Configuration
public class ShiroConfig {

    /**
     * 创建ShiroFilterFactoryBean
     * 用户主体  把操作交给SecurityManager
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //添加Shiro内置过滤器
        /*
          Shiro内置过滤器,可以实现权限相关的拦截器
             常用的过滤器:
                anon: 无需认证(登录)可以访问
                authc: 必须认证才可以访问
                user: 如果使用rememberMe的功能可以直接访问
                perms: 该资源必须得到资源权限才可以访问
                role: 该资源必须得到角色权限才可以访问
         */
        Map filterMap = new LinkedHashMap<>();

        //放行
        filterMap.put("/test", "anon");
        filterMap.put("/login", "anon");

        //授权过滤器
        //注意:当前授权拦截后,shiro会自动跳转到未授权页面
        filterMap.put("/testSelect", "perms[selectTest]");
        filterMap.put("/testAdd", "perms[addTest]");

        //必须认证(登录)
        filterMap.put("/*", "authc");

        //未登录状态访问其他url
        shiroFilterFactoryBean.setLoginUrl("/needLogin");
        //设置未授权提示页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

        return shiroFilterFactoryBean;
    }

    /**
     * 创建DefaultWebSecurityManager
     * 安全管理器 关联Realm
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联Realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     * 创建Realm
     * 连接数据的桥梁
     */
    @Bean(name = "userRealm")
    public UserRealm getRealm() {
        return new UserRealm();
    }


}

其中需要注意的是,通过filterMap设置指定url的访问权限或角色,如filterMap.put("/testSelect", "perms[selectTest]");
这条语句的意思就是访问/testSelect需要selectTest权限才能访问。

其次,要登录之后才会被授权,授权后才能访问相应权限的url,否则会跳转到shiroFilterFactoryBean.setLoginUrl("/needLogin");这句话所指定的url地址。

步骤四

创建UserRealm文件:

public class UserRealm extends AuthorizingRealm {

    @Autowired
    AdminRepository adminRepository;

    /**
     * 执行授权逻辑
     * 登录时授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("执行授权逻辑");

        //给资源进行授权
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        Admin admin = (Admin) principals.getPrimaryPrincipal();
        for (Role role : admin.getRoleList()) {
            //添加角色
            authorizationInfo.addRole(role.getRole());
            for (Permission permission : role.getPermissionList()) {
                //添加权限
                authorizationInfo.addStringPermission(permission.getPermission());
            }
        }

        return authorizationInfo;
    }

    /**
     * 执行认证逻辑
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行认证逻辑");

        //编写shiro判断逻辑,判断用户名和密码
        //1.判断用户名
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        Admin admin = adminRepository.findByUsername(token.getUsername());
        if (admin == null) {
            //用户名不存在
            return null;  //UnknownAccountException
        }

        //判断密码
        return new SimpleAuthenticationInfo(admin, admin.getPassword(), "");
    }
}
步骤五

至此,Shiro的权限控制就完成了,现在只需在数据表中添加相应数据项即可。最后,附上上述代码中所涉及到的url接口:

/**
 * 登录
 *
 * @param username 用户名
 * @param password 密码
 * @return Msg
 */
@PostMapping("/login")
public Msg Login(@RequestParam("username") String username,
                 @RequestParam("password") String password) {
    /*
      使用Shiro编写认证操作
     */
    //1.获取Subject
    Subject subject = SecurityUtils.getSubject();

    //2.封装用户数据
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);

    //3.执行登录方法
    try {
        //将跳转到UserRealm中去
        subject.login(token);
    } catch (UnknownAccountException e) {
        e.printStackTrace();
        //登录失败
        return new Msg(ResultCode.RESULT_CODE_USER_NOT_EXIST);
    } catch (IncorrectCredentialsException e) {
        e.printStackTrace();
        //密码错误
        return new Msg(ResultCode.RESULT_CODE_ERROR_PASSWORD);
    }
    return new Msg("登录成功");
}

/**
 * 未登录就请求其他url
 */
@RequestMapping("/needLogin")
public Msg needLogin() {
    return new Msg(ResultCode.RESULT_CODE_NEED_LOGIN);
}

/**
 * 未授权
 */
@RequestMapping("/noAuth")
public Msg noAuth() {
    return new Msg(ResultCode.RESULT_CODE_NO_PERMISSION);
}

@RequestMapping("/testSelect")
public String testSelect() {
    return "testSelect";
}

@RequestMapping("/testAdd")
public String testAdd() {
    return "testAdd";
}

参考资源: springboot(十四):springboot整合shiro-登录认证和权限管理,SpringBoot与Shiro整合-权限管理实战视频

你可能感兴趣的:(SpringBoot整合Shiro实现权限控制)