美文网首页
SpringBoot整合Shiro实现权限控制

SpringBoot整合Shiro实现权限控制

作者: 12313凯皇 | 来源:发表于2019-04-18 09:06 被阅读0次
步骤一

pom.xml中添加shiro的依赖:

<!-- shiro -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>
步骤二

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

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

    /**
     * 用户名/工号
     * <p>
     * 长度为9
     * 示例 201904001
     */
    @Id
    @Column(length = 9)
    private String username;

    /**
     * 密码
     */
    @Column(nullable = false, length = 20)
    private String password;


    /**
     * 角色列表
     * <p>
     * 一个用户可以有多个角色
     */
    @ManyToMany(fetch = FetchType.EAGER)  //立即从数据库中加载数据
    @JoinTable(name = "tb_admin_role", joinColumns = {@JoinColumn(name = "username")}, inverseJoinColumns = {@JoinColumn(name = "roleId")})
    private List<Role> roleList;

    public Admin() {
    }

    
    //省略get set方法
}

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

    /**
     * roleId
     * <p>
     * 自增序列
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int roleId;

    /**
     * 角色字符串
     * <p>
     * 用于角色控制
     * 不能为空
     */
    @Column(length = 50, nullable = false)
    private String role;


    // 用户 - 角色关系定义;
    @ManyToMany
    @JoinTable(name = "tb_admin_role", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "username")})
    private List<Admin> adminList;// 一个角色对应多个用户

    // 角色 - 权限关系定义;
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "tb_role_permission", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "permissionId")})
    private List<Permission> permissionList;// 一个角色有多个权限

    public Role() {
    }

    //省略get set方法
}
  • 权限表:
@Entity
@Table(name = "tb_permission")
public class Permission {

    /**
     * permissionId
     * <p>
     * 自增序列
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int permissionId;

    /**
     * 权限字符串
     * <p>
     * 用于权限控制
     * 不能为空
     */
    @Column(length = 50, nullable = false)
    private String permission;


    // 角色 - 权限关系定义;
    @ManyToMany
    @JoinTable(name = "tb_role_permission", joinColumns = {@JoinColumn(name = "permissionId")}, inverseJoinColumns = {@JoinColumn(name = "roleId")})
    private List<Role> roleList;// 一个角色有多个权限

    public Permission() {
    }

    //省略get set方法
}
  • 用户-角色表:
@Entity
@Table(name = "tb_admin_role")
public class AdminRole {

    /**
     * id
     * <p>
     * 自增序列
     */
    @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
     * <p>
     * 自增序列
     */
    @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<String, String> 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实现权限控制

      本文链接:https://www.haomeiwen.com/subject/mreawqtx.html