Shiro 授权(Authorization)

简介

授权

授权,也叫访问控制,她可以控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。
授权的几个关键对象:

  1. 主体(Subject)
  2. 资源(Resource)
  3. 资源(Permission)
  4. 角色(R)

主体

主体,即访问应用的用户,在Shiro 中使用Subject 代表该用户。用户只有授权后才允许访问相应的资源。

资源

在应用中用户可以访问的任何东西,比如访问JSP页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只有授权后才能访问。

资源

安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如:访问用户列表页面、查看/新增/修改/删除用户数据(即很多时候都是CRUD (增查改删)式权限控制)、打印文档等等。
如上可以看出,权限代表了用户有没有操作某个资源的权力,即反映在某个资源上的操作允不允许,不反映谁去执行这个操作。所以后续还需要把权限赋予给用户,即定义哪个用户允许在某个资源上做什么操作(权限),Shiro 不会去做这件事情,而是由实现人员提供。
Shiro支持粗粒度权限(如用户模块的所有权限)和细粒度权限(操作某个用户的权限,即实例级别的)。

角色

角色代表了操作集合,可以理解为权限的集合,-般情况下我们会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有-组不同的权限。

授权(Authorization)

快速上手

在resources下配置shiro.ini

[users]
#配置规则:用户账号=密码,角色1,角色2
admin=123456,管理员
czkt=111111,客户经理

[roles]
#配置规则:角色=权限1,权限2
管理员=user:*,role:*
客户经理=user:list,user:view

授权测试

@Test
    public void testShiro(){
        IniRealm realm=new IniRealm("classpath:shiro.ini");
        DefaultSecurityManager securityManger=new DefaultSecurityManager();

        securityManger.setRealm(realm);
        SecurityUtils.setSecurityManager(securityManger);
        Subject subject=SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken("admin","123456");
        subject.login(token);
        System.out.println("是否通过认证:"+subject.isAuthenticated());
        System.out.println("是否为管理员角色:"+subject.hasRole("管理员"));
        System.out.println("是否能操作用户查看功能:"+subject.isPermitted("user:view"));
        subject.checkPermission("user:view");
    }

运行效果:
在这里插入图片描述

授权流程

在这里插入图片描述

  1. 首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityManager,而SecurityManager接着会委托给Authorizer;
  2. Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例;
  3. 在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;
  4. Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRole*会返回true,否则返回false表示授权失败。

授权方式

Shiro支持四种方式的授权验证(权限控制):

  1. 代码级别权限控制
Subject subject=new Subject();
if(subject.hasRole("管理员")){
	//有权限
}else{
	//无权限
}
  1. 页面标签权限控制
<shiro:hasRole name="管理员">
<!-- 有权限 -->
</shiro:hasRole >
  1. 方法注解权限控制
  @RequiresRoles("管理员")
    public String add(Model model){
    }
  1. URL拦截权限控制
fileMap.put("/user/dologin","anon");
fileMap.put("/user/logout","logout");
fileMap.put("/user/list","perms[用户列表]");
fileMap.put("/user/add","perms[用户添加]");
fileMap.put("/user/edit/**","perms[用户编辑]");
fileMap.put("/user/del/**","perms[用户删除]");

Spring Boot+Shiro 授权

静态授权

自定义Realm授予期限

public class MyShiroRealm extends AuthorizingRealm{

    @Resource
    private IUserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("调用MyShiroRealm.doGetAuthorizationInfo获取权限信息");
        User user=(User)principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        //静态授权
        info.addRole(user.getRole().getRoleName());
        info.addStringPermission("用户列表");
        if (user.getRole().getRoleName().equals("管理员")){
            info.addStringPermission("用户添加");
            info.addStringPermission("用户编辑");
            info.addStringPermission("用户删除");
        }
        return info;
    }
 

配置ShiroConfig拦截URL

 @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactory=new ShiroFilterFactoryBean();
        shiroFilterFactory.setSecurityManager(securityManager);
        shiroFilterFactory.setLoginUrl("/user/login");
        shiroFilterFactory.setSuccessUrl("/main");
        shiroFilterFactory.setUnauthorizedUrl("/403");
        Map<String,String> fileMap=new LinkedHashMap<String,String>();
        fileMap.put("/css/**","anon");
        fileMap.put("/fonts/**","anon");
        fileMap.put("/images/**","anon");
        fileMap.put("/js/**","anon");
        fileMap.put("/localcss/**","anon");
        fileMap.put("/localjs/**","anon");
        fileMap.put("/user/dologin","anon");
        fileMap.put("/user/logout","logout");
        //静态授权
        fileMap.put("/user/list","perms[用户列表]");
        fileMap.put("/user/add","perms[用户添加]");
        fileMap.put("/user/edit/**","perms[用户编辑]");
        fileMap.put("/user/del/**","perms[用户删除]");

        fileMap.put("/**","authc");
        shiroFilterFactory.setFilterChainDefinitionMap(fileMap);
        return shiroFilterFactory;
    }

测试授权控制

在IndexController控制器添加unauthorized方法:

@RequestMapping(value = "/403")
    public String unauthorized(){
        return "403";
    }

修改403页面

 <body class="nav-md footer_fixed">
    <div class="container body">
      <div class="main_container">
        <div th:include="demo/common/header"></div>
          <div class="col-md-12">
            <div class="x_panel">
              <div class="x_title">
                <h2 style="color: red">
                  权限不足
                <i class="fa fa-remove"></i>
                <small style="color: red"><span th:text="${session.userSession.userName}">登录用户</span>
                 - 对不起,你没有操作改功能的权限! ^_^</small></h2>
                <div class="clearfix"></div>
              </div>
            </div>
          </div>
        </div>
        <!-- page content -->
    <div th:include="demo/common/footer"></div>

动态授权

基础代码开发

  1. 添加实体类Right
@Entity
@Table(name = "sys_right")
@JsonIgnoreProperties(value = {"hibernateLazyInitializer","handler"})
public class Right implements Serializable {
    @Id
    @Column(name = "right_code")
    private String rightCode;
    @Column(name = "right_parent_code")
    private String rightParentCode;
    @Column(name = "right_type")
    private String rightType;
    @Column(name = "right_test")
    private String rightTest;
    @Column(name = "right_url")
    private String rightUrl;
    @Column(name = "right_tip")
    private String rightTip;
	//多对多
	@ManyToMany(targetEntity = Role.class,mappedBy = "rights")
    @JsonIgnore
    private Set<Role> roles = new HashSet<Role>(0);
    
    //省略get/set方法,改造方法
}
  1. 修改Role实体类,添加与Right类的多对多关联
@ManyToMany(targetEntity = Right.class,fetch = FetchType.LAZY)
    @JoinTable(name = "sys_role_right",joinColumns = {@JoinColumn(name = "rf_role_id")}
        ,inverseJoinColumns = {@JoinColumn(name = "rf_right_code")})
    @OrderBy(value = "rightCode")
    private Set<Right> rights = new HashSet<Right>(0);

  1. 开发RightRepository
public interface RightRepository extends JpaRepository<Right,String> {
    List<Right> findRightsByRolesOrderByRightCode(Role role);//根据角色
}
  1. 添加新的方法
public interface IRoleService {
    public List<Role> findAllRoles();
    public List<Right> findAllRights();
    public List<Right> findRightsByRole(Role role);
}

调整IndexController

   @RequestMapping("/user/dologin")
    public String dologin(String userName, String userPassword, Model model, HttpSession session){
        try {
            UsernamePasswordToken token=new UsernamePasswordToken(userName,userPassword);
            Subject subject= SecurityUtils.getSubject();
            subject.login(token);
            User user=(User) subject.getPrincipal();
            Role role=user.getRole();
            List<Right> rights=roleService.findRightsByRole(role);
            role.getRights().addAll(rights);
            session.setAttribute("userSession",user);
            return "demo/main";
}

调整自定义Realm

public class MyShiroRealm extends AuthorizingRealm{

    @Resource
    private IUserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("调用MyShiroRealm.doGetAuthorizationInfo获取权限信息");
        User user=(User)principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        //静态授权
//        info.addRole(user.getRole().getRoleName());
//        info.addStringPermission("用户列表");
//        if (user.getRole().getRoleName().equals("管理员")){
//            info.addStringPermission("用户添加");
//            info.addStringPermission("用户编辑");
//            info.addStringPermission("用户删除");
//        }
        //动态授权
        Role role=user.getRole();
        if (role!=null){
            info.addRole(user.getRole().getRoleName());
            Set<Right> rights=role.getRights();
            if (rights!=null && rights.size()>0){
                rights.forEach(right -> info.addStringPermission(right.getRightCode()));
            }
        }
        return info;
    }
 }

调整配置对象ShiroConfig

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactory=new ShiroFilterFactoryBean();
        shiroFilterFactory.setSecurityManager(securityManager);
        shiroFilterFactory.setLoginUrl("/user/login");
        shiroFilterFactory.setSuccessUrl("/main");
        shiroFilterFactory.setUnauthorizedUrl("/403");
        Map<String,String> fileMap=new LinkedHashMap<String,String>();
        fileMap.put("/css/**","anon");
        fileMap.put("/fonts/**","anon");
        fileMap.put("/images/**","anon");
        fileMap.put("/js/**","anon");
        fileMap.put("/localcss/**","anon");
        fileMap.put("/localjs/**","anon");
        fileMap.put("/user/dologin","anon");
        fileMap.put("/user/logout","logout");
        //静态授权
//        fileMap.put("/user/list","perms[用户列表]");
//        fileMap.put("/user/add","perms[用户添加]");
//        fileMap.put("/user/edit/**","perms[用户编辑]");
//        fileMap.put("/user/del/**","perms[用户删除]");

        //动态授权
        List<Right> rights=roleService.findAllRights();
        for (Right right:rights){
            if (right.getRightUrl()!=null && !right.getRightUrl().trim().equals("")){
                fileMap.put(right.getRightUrl()+"/**","perms["+right.getRightCode()+"]");
            }
        }

        fileMap.put("/**","authc");
        shiroFilterFactory.setFilterChainDefinitionMap(fileMap);
        return shiroFilterFactory;
    }
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值