热门关键字:
jquery > jquery教程 > java > Shiro权限框架

Shiro权限框架

354
作者:管理员
发布时间:2020/4/11 15:47:45
评论数:0
转载请自觉注明原文:http://www.jq-school.com/Show.aspx?id=1272

1.Shiro是什么

  Shiro是一个非常强大的、易于使用的、开源的权限框架(安全框架)。它包括了权限校验、权限授予、会话管理、安全加密等组件。

2.为什么需要使用Shiro

  在设计RBAC(Role Based Access Control)基础系统时,需要编写大量用于权限控制的代码。如果使用Shiro就可以大大减少我们的工作量。因为Shiro已经将RBAC系统大量的代码封装好。
  如:页面的显示的HTML控件根据登录用户的权限不同而不同。使用Shiro可以轻松解决。

3.Shiro的下载

  shiro的下载路径:http://shiro.apache.org/download.html

  Shiro包说明

  使用时根据列表的说明,下载需要的jar包即可

包 名 Maven 坐标 说 明
 shiro-all  不推荐采用  包含Shiro的所有功能 
 shiro-core <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency>  只要使用shiro必须的核心包,它依赖slf4j 和 commons-beanutils 以及还需要一个INI配置文件
 shiro-web  <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.3.2</version> </dependency>  支持基于Web的应用
 shiro-aspectj  <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-aspectj</artifactId> <version>1.3.2</version> </dependency>  AspectJ对Shiro AOP和注释的支持
 shiro-cas

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-cas</artifactId>
<version>1.3.2</version>
</dependency>

 对cas单点登录框架的支持
 shiro-ehcache

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.3.2</version>
</dependency>

 对echche缓存框架的支持
 shiro-hazelcast

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-hazelcast</artifactId>
<version>1.3.2</version>
</dependency>

 对hazelcast的famework缓存的支持
 shiro-features <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-features</artifactId> <version>1.3.2</version> </dependency>  Karaf 的集成
 shiro-guice

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-guice</artifactId>
<version>1.3.2</version>
</dependency>

 对谷歌的guice框架的支持(类似spring的ioc框架)
 shiro-quartz

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>1.3.2</version>
</dependency>

 对quartz定时任务调度框架的支持
 shiro-spring <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency>  支持Spring框架集成。

        标红部分为常用包

4.Shiro结构图

  Shiro权限框架

Authentication:权限校验,每次操作校验用户是否有访问权限
Authorization:授权,用户登录时,授予用户对应的权限
Session Management:会话管理,用于记录用户的登录状态
Cryptography:加密,加密算法的实现(SHA、MD5)
web Support:对Web项目的支持,Shiro的标签!

5.Shiro入门

  5.1 访问流程图

    登录流程:

  Shiro权限框架

 

 

1.应用访问(如Web请求等)
2.Shiro根据访问请求创建一个Subject对象来标识当前访问的身份。
3.SecurityManger 加载配置文件进行身份校验(验证账号密码)
4.身份校验通过后SecurityManger 会根据配置文件授予当前Subject对象对应的用户权限

5.2 入门示例

配置步骤:

第一步:导入jar包

Shiro权限框架


第二步:shiro.ini配置文件
创建一个shiro.ini配置文件,编写权限认证信息。
注:1.shiro.ini文件名可以任意编写,但后缀必须是ini
  2.shiro.ini配置文件放在classpath根目录下

shiro.ini文件配置规则说明:

[main]   #用于配置SecurityManager里面的对象 
  对象名=类全限制名
  对象名.属性[.属性...] = 值 

[users]   #用于配置用户名信息
   用户名= 密码, 角色1, 角色2, …, 角色N
 
[roles]   #用于配置角色信息
   角色名= 权限1, 权限2, …, 权限N   #全部权限使用 * (星号)
   
[urls]    #用于配置路径拦截规则

  权限命名格式建议:权限:操作:操作

  shiro.ini配置:

##用户信息
 [users]
 admin=123456,role_admin,role_user
 
 ##角色信息
 [roles]
 role_admin=* role_user=modular:to_add,modular:add

  测试:

package com.gjs.shiro.test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; public class ShiroTest { public static void main(String[] args) { //第一步:读取配置文件创建安全管理器 IniSecurityManagerFactory factory =new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.createInstance(); //第二步:设置SecurityUtils的安全管理器  SecurityUtils.setSecurityManager(securityManager); //第三步:获得一个没有权限身份对象 Subject subject = SecurityUtils.getSubject(); //第四步:构建验证信息token UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456"); //第四步:身份校验(验证账号密码) try {
            Subject resultSubject = securityManager.login(subject, token);
            
            System.out.println("校验通过");
            System.out.println("用户名:"+resultSubject.getPrincipal());
            System.out.println("验证授权:"+resultSubject.isPermitted("modular:add"));
            
        } catch (AuthenticationException e) {
            System.out.println("校验失败,用户名或者密码不正确");
            e.printStackTrace();
        }
        
    }
}

 

API说明:

IniSecurityManagerFactory:作用加载ini配置文件获得SecurityManagerFactory对象
SecurityManager:安全管理容器,就是否则整个Shiro框架授权校验对象的管理
SecurityUtils :SecurityManager对象帮助类
Subject:验证通过后用于存储授权信息的身份对象
UsernamePasswordToken :用于设置校验信息的对象
IncorrectCredentialsException :密码出错异常
UnknownAccountException:用户名出错异常

6.Realm的使用

  在入门示例中,用户验证信息来自于ini配置文,这样的难以符合我们实际的需求。而在实际开发中,我们的用户信息是存储在数据库里面,再从数据库里面读取出来。
Shiro是通过Realm机制,实现将配置文件的校验用户信息存放在数据库等数据存储系统里面。

  6.1 访问流程图

  Shiro权限框架

  如图所示,我们需要在ini配置文件中配置Realm对象,再在Realm中进行权限验证以及授权

6.2 示例:

配置步骤:

第一步:导入jar包

Shiro权限框架

  第二步:编写Realm

package com.gjs.shiro.realm; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; /** * 我们自定义Realm继承授权的Realm AuthorizingRealm。因为授权包括校验。
 * @author gjs
 * */ public class MyRealm extends AuthorizingRealm{ /** * 权限校验: 就是验证访问者(subject).是否使用有使用权限的身份,即验证账号密码。验证通过回AuthenticationInfo对象 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("权限校验");
        System.out.println("用户名:" + token.getPrincipal()); if (token.getPrincipal().equals("admin")) { //参数1:用于存储用户信息,可以填充给Subject对象 //参数2:校验的密码。注意Shiro的校验是SimpleAuthenticationInfo内部完成的。 //参数3:Realm名字,用来标识Realm return new SimpleAuthenticationInfo(token.getPrincipal(), "123456", this.getName());
        } return null;
    } /** * 权限授予:根据通过校验的身份(subject)将查询到的权限信息封装在AuthorizationInfo里面返回 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("modular:add");//添加权限 info.addRole("RoleAdmin");//添加角色 return info;
    }
}

  第三步:创建shiro.ini配置文件

[main]
 ##声明Realm对象
 myRealm=com.gjs.shiro.realm.MyRealm
 ##配置securityManager的realm对象。  对象引用需要在对象名前面加上 $
 securityManager.realms=$myRealm

  第四步:编写测试类

package com.gjs.shiro.test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; public class ShiroTest { public static void main(String[] args) { //第一步:读取配置文件创建安全管理器 IniSecurityManagerFactory factory =new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.createInstance(); //第二步:设置SecurityUtils的安全管理器  SecurityUtils.setSecurityManager(securityManager); //第三步:获得一个没有权限身份对象 Subject subject = SecurityUtils.getSubject(); //第四步:构建验证信息token UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456"); //第四步:身份校验(验证账号密码) try {
            Subject resultSubject = securityManager.login(subject, token);
            
            System.out.println("校验通过");
            System.out.println("用户名:"+resultSubject.getPrincipal());
            System.out.println("验证授权:"+resultSubject.isPermitted("modular:add"));
            System.out.println("是否有RoleAdmin角色:"+resultSubject.hasRole("RoleAdmin"));
            
        } catch (AuthenticationException e) {
            System.out.println("校验失败,用户名或者密码不正确");
            e.printStackTrace();
        }
        
    }
}

 

6.3 加密

  在开发中我们需要对密码进行加密,而我们自己编写的加密工具类无法传递给SimpleAuthenticationInfo对象,作为密码校验。所以就要用到shiro框架自带的密码加密的功能。
  SimpleHash类:用于生成指定的Hash算法。
  HashedCredentialsMatcher类:用于让Realm校验时,校验指定的Hash算法
  ByteSource 用于给Hash算法加盐的 

  示例:

  生成md5密码

package com.gjs.shiro.test; import org.apache.shiro.crypto.hash.Md5Hash; import org.apache.shiro.util.ByteSource; /** * 用来创建加密后的密码,参数与校验器的参数保持一致
 * @author gjs
 * */ public class Md5Util { public static void main(String[] args) {
        ByteSource salt = ByteSource.Util.bytes("gjs");
        Md5Hash md5=new Md5Hash("123456", salt, 3);
        String password = md5.toString();
        System.out.println(password);
    }
}

  修改ini配置文件

[main]
 ##声明Realm对象
 myRealm=com.gjs.shiro.realm.MyRealm
 #加密的对象
 credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
 ##指定加密算法. 属性对应的是set方法
 credentialsMatcher.hashAlgorithmName=md5
 ##算法是否加盐
 credentialsMatcher.hashSalted=true ##加密次数
 credentialsMatcher.hashIterations=3 ##指定加密的校验器给MyReam
 myRealm.credentialsMatcher=$credentialsMatcher
 ##配置securityManager的realm对象。  对象引用需要在对象名前面加上 $
 securityManager.realms=$myRealm

  修改Realm类:

package com.gjs.shiro.realm; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; /** * 我们自定义Realm继承授权的Realm AuthorizingRealm。因为授权包括校验。
 * @author gjs
 * */ public class MyRealm extends AuthorizingRealm{ /** * 权限校验: 就是验证访问者(subject).是否使用有使用权限的身份,即验证账号密码。验证通过回AuthenticationInfo对象 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("权限校验");
        System.out.println("用户名:" + token.getPrincipal()); if (token.getPrincipal().equals("admin")) {
            ByteSource salt = ByteSource.Util.bytes("gjs"); //参数1:用于存储用户信息,可以填充给Subject对象 //参数2:校验的密码。注意Shiro的校验是SimpleAuthenticationInfo内部完成的。 //参数3:Realm名字,用来标识Realm return new SimpleAuthenticationInfo(token.getPrincipal(), "a0af233bfd499995a8c1bacc4f61c489",salt, this.getName());
        } return null;
    } /** * 权限授予:根据通过校验的身份(subject)将查询到的权限信息封装在AuthorizationInfo里面返回 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("modular:add");//添加权限 info.addRole("RoleAdmin");//添加角色 return info;
    }
} 

  6.4 返回的认证信息为一个实体(JavaBean、Map)

  上面代码校验后返回的认证信息是一个字符串的用户名,而我们如果将Shiro的校验功能用到登录的逻辑里面,明显需要返回的不是一个用户名,而是用户的信息。
用户的信息,我们需要用一个实体类来封装。可以是JavaBean或者是Map
  我们上面写的校验方法返回的SimpleAuthenticationInfo的构建方法的第一个参数就是用于指定,返回的用户认证信息的。可以将用户名修改为一个我们指定的实体类对象就可以了

pojo实体类:

package com.gjs.shiro.pojo; import java.util.Date; public class User { private int id; private String name; private String password; private Date createDate; private int status; private Role role; public Role getRole() { return role;
    } public void setRole(Role role) { this.role = role;
    } public int getId() { return id;
    } public void setId(int id) { this.id = id;
    } public String getName() { return name;
    } public void setName(String name) { this.name = name;
    } public String getPassword() { return password;
    } public void setPassword(String password) { this.password = password;
    } public Date getCreateDate() { return createDate;
    } public void setCreateDate(Date createDate) { this.createDate = createDate;
    } public int getStatus() { return status;
    } public void setStatus(int status) { this.status = status;
    }
    @Override public String toString() { return "User [id=" + id + ", name=" + name + ", password=" + password + ", createDate=" + createDate + ", status=" + status + ", role=" + role + "]";
    }
}
package com.gjs.shiro.pojo; import java.util.List; public class Role { private int roleId; private String roleName; private List<Perm> rolePerms; public int getRoleId() { return roleId;
    } public void setRoleId(int roleId) { this.roleId = roleId;
    } public String getRoleName() { return roleName;
    } public void setRoleName(String roleName) { this.roleName = roleName;
    } public List<Perm> getRolePerms() { return rolePerms;
    } public void setRolePerms(List<Perm> rolePerms) { this.rolePerms = rolePerms;
    }
    @Override public String toString() { return "Role [roleId=" + roleId + ", roleName=" + roleName + ", rolePerms=" + rolePerms + "]";
    }
    
}
package com.gjs.shiro.pojo; public class Perm { private int permId; private String permName; private String permAction; private String permKey; public int getPermId() { return permId;
    } public void setPermId(int permId) { this.permId = permId;
    } public String getPermName() { return permName;
    } public void setPermName(String permName) { this.permName = permName;
    } public String getPermAction() { return permAction;
    } public void setPermAction(String permAction) { this.permAction = permAction;
    } public String getPermKey() { return permKey;
    } public void setPermKey(String permKey) { this.permKey = permKey;
    }
    @Override public String toString() { return "Perm [permId=" + permId + ", permName=" + permName + ", permAction=" + permAction + ", permKey="
                + permKey + "]";
    }
    
}

  修改Realm

package com.gjs.shiro.realm; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; import com.gjs.shiro.pojo.Perm; import com.gjs.shiro.pojo.Role; import com.gjs.shiro.pojo.User; /** * 我们自定义Realm继承授权的Realm AuthorizingRealm。因为授权包括校验。
 * @author gjs
 * */ public class MyRealm extends AuthorizingRealm{ /** * 权限校验: 就是验证访问者(subject).是否使用有使用权限的身份,即验证账号密码。验证通过回AuthenticationInfo对象 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("权限校验");
           User user=new User(); //此处的数据应从数据库查出来 user.setId(1);
        user.setName((String)token.getPrincipal());
        user.setStatus(0);
        user.setCreateDate(new Date()); if (token.getPrincipal().equals(user.getName())) {
            ByteSource salt = ByteSource.Util.bytes("gjs"); //参数1:用于设置认证信息,返回给调用对象的 //参数2:校验的密码。注意Shiro的校验是SimpleAuthenticationInfo内部完成的。 //参数3:密码的盐 //参数4:Realm名字,用来标识Realm return new SimpleAuthenticationInfo(user, "a0af233bfd499995a8c1bacc4f61c489",salt, this.getName());
        } return null;
    } /** * 权限授予:根据通过校验的身份(subject)将查询到的权限信息封装在AuthorizationInfo里面返回 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //获取认证信息 User user = (User) principals.getPrimaryPrincipal(); //将授权信息也存到当前用户对象里面(值传递) //角色 Role role=new Role();
        role.setRoleId(1);
        role.setRoleName("RoleAdmin");
        user.setRole(role); //权限 List<Perm> perms=new ArrayList<>();
        Perm perm1=new Perm();
        perm1.setPermId(1);
        perm1.setPermName("用户管理");
        perm1.setPermAction("/user/toUserList");
        perm1.setPermKey("user:to_edit");
           
        perms.add(perm1);
                
        role.setRolePerms(perms);
        
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission(user.getRole().getRolePerms().get(0).getPermKey());//添加权限 info.addRole(user.getRole().getName());//添加角色 return info;
    }
}

  测试类:

package com.gjs.shiro.test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import com.gjs.shiro.pojo.User; public class ShiroTest { public static void main(String[] args) { //第一步:读取配置文件创建安全管理器 IniSecurityManagerFactory factory =new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.createInstance(); //第二步:设置SecurityUtils的安全管理器  SecurityUtils.setSecurityManager(securityManager); //第三步:获得一个没有权限身份对象 Subject subject = SecurityUtils.getSubject(); //第四步:构建验证信息token UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456"); //第四步:身份校验(验证账号密码) try {
            Subject resultSubject = securityManager.login(subject, token);
            
            System.out.println("校验通过");
            User user=(User) resultSubject.getPrincipal();//获取认证信息 System.out.println("用户名:"+user.getName());
            System.out.println("验证授权:"+resultSubject.isPermitted("modular:add"));
            System.out.println("是否有RoleAdmin角色:"+resultSubject.hasRole("RoleAdmin"));
            
            System.out.println("获得角色:"+user.getRole());
            System.out.println("获得第一个权限:"+user.getRole().getRolePerms().get(0));
        } catch (AuthenticationException e) {
            System.out.println("校验失败,用户名或者密码不正确");
            e.printStackTrace();
        }
        
    }
}

7.常用API:

IniSecurityManagerFactory : 用于加载配置文件,创建SecurityManager对象
SecurityManager :就是整个Shiro的控制对象
SecurityUtils :SecurityManager 工具类,用于获得Subject对象
Subject :身份类,存储返回的数据信息、提供了校验的权限的方法
UsernamePasswordToken 身份信息构建类 (Token 令牌,作用就是传入校验参数)
AuthorizingRealm 支持校验与授权的Realm
AuthenticationInfo 校验成功返回的信息的父接口
SimpleAuthenticationInfo 校验成功返回信息类
Md5Hash Md5加密类
ByteSource 字节码处理工具类,我们在构造Md5加盐时使用到。
HashedCredentialsMatcher Md5算法校验器,用于支持Md5校验
AuthorizationInfo 授权成功返回的信息类的父接口
PrincipalCollection 授予是获得验证信息的类
SimpleAuthorizationInfo 授权成功返回的信息类的实现类





如果您觉得本文的内容对您的学习有所帮助:支付鼓励



关键字:Shiro权限框架
友荐云推荐