JAVA技术 七月 12, 2019

Shiro学习一

文章字数 13k 阅读约需 12 mins. 阅读次数 0

老物


       新的公司让我去熟悉下Shiro框架,公司的项目的权限管理都是基于Shiro写的,照着前辈们的blog学习了一番,这里做点个人学习记录。

Shiro的整体架构图

Shiro架构图


首先是Shiro的几个组件

  • SecurityManager
    即所有Subject的管理者,这是Shiro框架的核心组件,可以把他看做是一个Shiro框架的全局管理组件,用于调度各种Shiro框架的服务。
  • Authenticator
    认证器,登入登出,对“Who are you?”进行核实。通常涉及用户名和密码。
  • Authorizer
    授权器,赋予主体有哪些权限,身份验证通过后,由这个组件对登录人员进行访问控制的筛查,比如“who can do what”, 或者“who can do which actions”。Shiro 采用“基于 Realm”的方法,即用户(又称 Subject)、用户组、角色和 permission 的聚合体。
  • Session Manager
    这个组件保证了异构客户端的访问,配置简单。它是基于POJO/J2SE的,不跟任何的客户端或者协议绑定。
  • Subject
    即当前用户,在权限管理的应用程序里往往需要知道谁能够操作什么,谁拥有操作该程序的权利,shiro中则需要通过Subject来提供基础的当前用户信息,Subject 不仅仅代表某个用户,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。
  • Realms
    Realms也就是域,是用户的信息认证器和用户的权限人证器,我们需要自己来实现Realms来自定义的管理我们自己系统内部的权限规则。

通过ini文件来自定义Realm

Maven依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.2.3</version>
</dependency>

shiro.ini

# -----------------------------------------------------------------------------
# Users and their (optional) assigned roles
# username = password, role1, role2, ..., roleN
# -----------------------------------------------------------------------------
[users]

#用户名(登陆账号)是root,密码是123,角色是admin管理员

root = 123,admin
user001 = 123,productManager
user002 = 123,orderManager

# -----------------------------------------------------------------------------
# Roles with assigned permissions
# roleName = perm1, perm2, ..., permN
# -----------------------------------------------------------------------------
[roles]

#admin管理员权限拉满,什么都能做
admin = *

#产品经理只能做产品的管理
productManager = addProduct,deleteProduct,editProduct,listProduct

#订单管理员只能做订单的管理
orderManager = addOrder,deleteOrder,editOrder,listOrder

这里分配了三种角色各自拥有不同的权限

  • admin

    • 拥有所有权限
  • productManager

    • addProduct
    • deleteProduct
    • editProduct
    • listProduct
  • orderManager

    • addOrder
    • deleteOrder
    • editOrder
    • listOrder

Tutorial .java

package shiro;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by MatthewHan on 2018.
 */
public class Tutorial {

    private static final transient Logger log = LoggerFactory.getLogger(Tutorial.class);
    public static void main(String[] args) {

        //step1.使用了IniSecurityManagerFactory类读取ini文件
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        
        //step2.解析ini文件,返回一个Securitymanager对象,对象含有配置信息
        SecurityManager securityManager = factory.getInstance();
        
        //step3.
        SecurityUtils.setSecurityManager(securityManager);


        //获取当前使用的用户
        Subject currentUser  = SecurityUtils.getSubject();
        //获取Session信息
        Session session = currentUser.getSession();
        session.setAttribute("oneKey","aValue");
        String value = (String)session.getAttribute("oneKey");
        if(value.equals("trueValue"))
        {
            log.info("值正确!["+ value +"]");
        }
        else
        {
            log.info("value有错误哦!您的value:["+ value+"]");
        }
    
        log.info("\n**********************是否登陆成功*********************\n");
    
        //登陆后的当前用户,这样我们就可以检查角色和权限:
        if(!currentUser.isAuthenticated()) {
            String username = "user001", password = "1123";
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            token.setRememberMe(true);
    
            try {
                currentUser.login(token);//登陆
                log.info("你居然登陆上了,牛逼");
                log.info("\n**********************打印这些登陆用户的信息*********************\n");
    
                //打印这些登陆用户的信息
                log.info("用户[" + currentUser.getPrincipal() + "] 登陆成功!");
    
                //测试一个role
                String roleName = "productManager";
                if (currentUser.hasRole(roleName)) {
                    log.info("这个角色:[" + roleName + "]");
                } else {
    
                    log.info("emmmm,mere mortal!");
                }
                log.info("\n**********************测试不同类型的权限*********************\n");
    
                //测试不同类型的权限
                if (currentUser.isPermitted("addProduct")) {
                    log.info("您可以对产品进行管理");
                } else {
                    log.info("你不配使用");
                }
    
                //part2
                if (currentUser.isPermitted("addOrder")) {
                    log.info("您可以对订单系统进行管理");
                }
                else{
                    log.info("抱歉,你不配管理订单系统");
                }


            } catch (UnknownAccountException uae) {
                log.info("没有这个用户名:" + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                log.info("这个账号" + token.getPrincipal() + "的密码是错的啦,try again?");
            } catch (LockedAccountException lae) {
                log.info("这个用户" + token.getPrincipal() + "已被封锁" + "请联系管理员解锁");
            } catch (AuthenticationException ae) {
                log.info("发生了一些未知的情况,请联系管理员!");
            }
    
        }

        //用户登出
        currentUser.logout();
        System.exit(0);
    
    }
}

测试类Tutorial,通过UsernamePasswordToken创建的token对象来让Subject(当前对象)进行登陆验证,认证通过后,可以用getPrincipal()这个方法来获取当前对象的用户名.

角色相关验证方法

Subject方法 描述
hasRole(String roleName) 当用户拥有指定角色时,返回true
hasRoles(List roleNames) 按照列表顺序返回相应的一个boolean值数组
hasAllRoles(Collection roleNames) 如果用户拥有所有指定角色时,返回true

Subject方法 描述
checkRole(String roleName) 断言用户是否拥有指定角色
checkRoles(Collection roleNames) 断言用户是否拥有所有指定角色
checkRoles(String… roleNames) 对上一方法的方法重载

权限相关验证方法

Subject方法 说明
checkPermission(Permission p) 断言用户是否拥有制定权限
checkPermission(String perm) 断言用户是否拥有制定权限
checkPermissions(Collection perms) 断言用户是否拥有所有指定权限
checkPermissions(String… perms) 断言用户是否拥有所有指定权限

Subject方法 描述
isPermitted(Permission p) Subject拥有制定权限时,返回true
isPermitted(List perms) 返回对应权限的boolean数组
isPermittedAll(Collection perms) Subject拥有所有制定权限时,返回true
0%