为什么要用shiro框架_Java高级框架 - Shiro Day16

Shiro权限框架


目录
1. Shiro概述
1.1. Shiro是什么 What is Apache Shiro?
1.2. 为什么需要使用Shiro(兴趣点)
1.3. Shiro的下载
1.4. 包说明
1.5. Shiro结构图
2. Shiro入门
2.1. 访问流程图
2.2. 配置步骤说明
2.3. 配置步骤
2.3.1. 第一步:导入包
2.3.2. 第二步:shiro.ini配置文件
2.3.3. 第三步:创建SecurityManager对象
2.3.4. 注意事项11
3. Realm的使用
3.1. Realm机制的必要性
3.2. 访问流程图说明
3.3. 配置步骤说明
3.4. 权限校验-配置入门
3.4.1. 第一步:导入包
3.4.2. 第二步:创建shiro.ini配置文件
3.4.3. 第三步:编写一个测试类
3.4.4. 第四步:编写Realm
3.4.5. 加密
3.4.6. 返回的认证信息为一个实体(JavaBean、Map)
3.5. 权限授予-配置入门
3.5.1. 第一步:检验Subject对象的权限校验方法
3.5.2. 第二步:在Realm授权
4. 综合案例
4.1. 第一步:数据库设计
4.2. 第二步:配置Shiro入门示例
4.3. 第三步:编写实体类
4.4. 第四步:编写数据库连接
4.5. 第五步:实现权限验证
4.6. 第六步:实现权限授予
5. 总结

--观点:

学习任何的知识,我们首先要知道它是什么,然后通过是什么(定义)来分析它的作用、行为。从而圈定学习的范围。我们将这个过程称为,学习思路!!

1. Shiro概述

1.1. Shiro是什么

官方说明:

What is Apache Shiro?
Apache Shiro is a powerful and flexible open-source security framework that cleanly handles authentication, authorization, enterprise session management and cryptography.

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

1.2. 为什么需要使用Shiro(兴趣点)

如果你是需要设计RBAC(Role Based Access Control)基础系统,需要编写大量用于权限控制的代码时。那么你需要使用Shiro。因为Shiro已经将RBAC系统大量的代码封装好,可以减少我们大量的工作量。

如:页面的显示的HTML控件根据登录用户的权限不同而不同。使用Shiro可以轻松解决。

1.3. Shiro的下载

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

--所有包的说明,根据列表的说明,下载我们需要的jar包

cb1e3ef80758f632d34bfeaed2bdff79.png

5d9e6da596873f3d6921173a3aa718b0.png

cb25f36bce8237f971402c2870167eee.png

e9afccace7040ea663658b2e0313a32d.png

01007bf21eee9e2cf77995e31fa36269.png

1.4. 包说明

--Shiro常用包

ce6962ac9412e37d4a95ed32eaa96de4.png

1.5. Shiro结构图

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

2. Shiro入门

2.1. 访问流程图

我们知道学习任何的框架,都是从配置流程开始的。我们学习Shiro也是一样。所以首先要了解Shiro的访问流程。从而知道配置的配置,快速入门。

d08013445f2eb80b4f579642afdfc96c.png

1. 首先应用访问(可以使用远程调用,可以是Web请求等),Shiro通过一个Subject对象来标识当前访问的身份。这句话告诉我们,第一次访问的时候,Shiro肯定会创建一个Subject对象标签当前请求(用户)的身份。

2. SecurityManger容器创建一个Subject对象验证请求的参数,SecurityManager的作用是统一管理Subject。这句话意味着,一个SecurityManager对象管理多个Subject的对象。

3. Subject通过SecurityManger获得操作当前用户的权限,在启动的那一刻,SecurityManger就会加载shiro.ini权限配置文件,在用户登录成功后,可以根据shiro配置的信息,获得用户对应的权限。

4. shiro配置:是一个权限控制信息文件,里面必须包括用户的验证信息,权限的信息

--登录流程!!!!

2.2. 配置步骤说明

根据访问流程图,我们要使用访问Shiro权限框架的功能。首先需要有一个配置文件shiro.ini配置文件配置了用户的权限认证信息。然后通过SessionManager对象读取配置文件,获得用户身份Subject,

客户端代码通过当前用户访问有权限的操作。

由此,得出配置步骤:

第一步:任何框架都需要导入包

第二步:创建一个shiro.ini配置文件。(文件名任意编写,后缀必须为ini)

第三步:编写测试代码

2.3. 配置步骤

注意事项:shiro框架依赖slf4j以及beanutils包。

2.3.1. 第一步:导入包

fc7e53b3465cbcbe42188ed5263e1958.png

2.3.2. 第二步: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]    #用于配置路径拦截规则

权限格式使用:权限:操作:操作

代码如下:

[users]
 jim = jim,admin
 
[roles]
 admin = *

2.3.3. 第三步:创建SecurityManager对象

创建一个SecurityManager对象,并且测试校验是否成功

package cn.gzsxt.shiro;
 
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
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 ShiroDemo {
 
 public static void main(String[] args) {
 // 1.获得SecurityManager对象
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.createInstance();
 
 //2.设置SecurityUtils使用的安全管理器是securityManager
        SecurityUtils.setSecurityManager(securityManager);
 
 //3.获得subject
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken token=new UsernamePasswordToken("jim", "jim");
 //4.校验用户名密码是否正确
 
 try {
            Subject resultSubject = securityManager.login(subject, token);
 //获得用户名
            System.out.println(resultSubject.getPrincipal());
 //判断是否拥有admin角色
 boolean hasRole = resultSubject.hasRole("admin");
            System.out.println(hasRole);
        } catch (AuthenticationException e) {
            System.out.println("校验失败,用户名或者密码不正确");
 e.printStackTrace();
        }
    }
} 

2.3.4. 注意事项

以上示例,我们需要记住并且理解入门示例中的几个API的使用

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

3. Realm的使用

3.1. Realm机制的必要性

以上案例,我们看到,我们的用户验证信息来自于ini配置文件的[users]以及[roles]标记。这样的难以符合我们实际的需求。

我们希望可以将Shiro校验的用户信息存储在数据库里面,在从数据库里面读取出来。

解决方案:Shiro是通过Realm机制,实现将配置文件的校验用户信息存放在数据库、LDAP等数据存储系统里面。

说白了,现在我们要做的事情,就是从数据库里面获得用户的验证信息!!!

3.2. 访问流程图说明

0d90397827ee860a2e682eb4a8051702.png

如图所示:

1. 我们需通过Subject封装访问用户的信息

2. 我们需要一个SecurityManager对象来管理所有用户的权限

3. 我们需要ini配置文件配置获得Realm对象

4. 我们需要在Realm进行权限验证以及授权

3.3. 配置步骤说明

第一步:导入包

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

第三步:创建入口的测试类对象

第四步:创建Realm对象

第五步:配置shiro.ini调用Realm对象

3.4. 权限校验-配置入门

3.4.1. 第一步:导入包

193cca1731f7412405c36d4eec2a14c9.png

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

[main]
#声明realm对象
myRealm=cn.gzsxt.realm.MyRealm
 
 
#指定securityManager的realm对象
securityManager.realms=$myRealm

3.4.3. 第三步:编写一个测试类

package cn.gzsxt.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 org.junit.Test;
 
public class PermissionTest {
 
 @Test
 public void authc(){
 
 try {
 //第一步:获得SecurityManager对象
            IniSecurityManagerFactory ismf=new IniSecurityManagerFactory("classpath:shiro.ini");
            SecurityManager securityManager = ismf.createInstance();
 
 
 //第二步:构造一个subject
            SecurityUtils.setSecurityManager(securityManager);
 
            Subject subject = SecurityUtils.getSubject();
 
 //第三步:封装用户名密码(身份信息)
            UsernamePasswordToken token=new UsernamePasswordToken("zhangsan", "123456");
 
 //第四步:校验(登录)
            Subject resultSubject = securityManager.login(subject, token);
 
 
 //第五步:验证是否通过
            System.out.println(resultSubject.isAuthenticated());
        } catch (AuthenticationException e) {
 e.printStackTrace();
        }
 
 
 
    }
}

3.4.4. 第四步:编写Realm

package cn.gzsxt.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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
 
/**
 * 自动一个MyRealm类,用于权限验证以及权限授予
 *
 * @author ranger
 *
 */
public class MyRealm extends AuthorizingRealm {
 
 /**
     * 权限验证 所谓的权限验证,就是验证访问者(subject).是否使用有使用权限的身份。 说白了,就验证用户名密码是否正确
     *
     * 如果校验成功,我们就返回AuthenticationInfo对象 如果校验失败,我们需要返回一个异常
     * UnknownAccountException
     *
     */
 @Override
 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("用户名:" + token.getPrincipal());
 if (token.getPrincipal().equals("zhangsan")) {
 return new SimpleAuthenticationInfo(token.getPrincipal(), "123456",
 this.getName());
 
        } else {
 return null;
        }
    }
 
 /**
     * 授权 根据通过校验的身份(subject),说白了就是登录成功的访问者,我们给予什么权限。
     * 将查询到的权限信息封装在AuthorizationInfo里面返回!!
     */
 @Override
 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection collection) {
 return null;
    }
 
}
 

3.4.5. 加密

需求:我们的密码是明文的,我们需要将密码Md5加密。

问题:我们发现我们自己写的Md5的类,无法传递给SimpleAuthenticationInfo对象,作为密码校验。如何解决的这个问题呢?

答:shiro框架自带的密码加密的功能。

1. SimpleHash类:用于生成指定的Hash算法。

f637b240ce6b790216a8c5c48ae4801a.png

2. HashedCredentialsMatcher类:用于让Realm校验时,校验指定的Hash算法

ecd967d6a4f86de3aa798edb4d675daa.png

3. ByteSource 用于给Hash算法加盐的

0dddf5f73d9d615efd3865c7a082423f.png

--创建Md5密码

package cn.gzsxt.test;
 
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
 
//注意事项:设置的创建密码的参数必须与校验器的参数保持一致
public class CreatePasswordUtils {
 
 public static void main(String[] args) {
 //加密方式
        String hashAlgorithmName = "MD5";
 //明文密码
        Object credentials = "123456";
 //盐值
        Object salt = ByteSource.Util.bytes("nchu234we");
 //迭代加密的次数,
 int hashIterations = 1;
  //返回加密的结果
        Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
 //加密后的密码
        System.out.println(result);
    }
 
}
 

--修改配置文件

[main]
# 对象名 =类全限制名 ,就是创建一个对象
myRealm = cn.gzsxt.realm.MyRealm
 
#加密的对象
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#设置加密的算法为md5 ,属性对应的是set方法
credentialsMatcher.hashAlgorithmName=md5
#设置md5加密次数为1次
credentialsMatcher.hashIterations=1
#设置md5算法是加盐
credentialsMatcher.hashSalted=true
 
#将加密对象指定给对应给myRealm对象
myRealm.credentialsMatcher=$credentialsMatcher
 
 
#将realm对象加入到securityManager容器里面
#引用 securityManager.realms = $对象名
#securityManager对象名是shiro固定的。用于指定securityManager容器
#对象的引用格式为: 对象名.属性名 = $对象名;
securityManager.realms = $myRealm

--修改校验代码

package cn.gzsxt.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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
 
/**
 * Realm :所有Realm的父接口
 * AuthenticatingRealm :只有权限校验,没有权限授权的Realm
 * AuthorizingRealm : 既有权限校验,权限授权的Realm (主要就是使用它)
 * JdbcRealm:使用实现的对数据库 操作的代码的Realm。它已经写死了表名,必要要按它定义的表名定义数据库表。(灵活性差)
 *
 * 注意事项:使用Realm,将验证认证信息与获得授权信息,都放在一起!!!!!
 * @author ranger
 *
 *
 */
public class MyRealm extends AuthorizingRealm {
 
 /**
     * 用于权限校验
     */
 @Override
 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
 try {
            System.out.println("=权限校验=");
 
 //第一步:获得请求过来的用户名
            Object principal = token.getPrincipal();
 
 //第二步:根据用户查询数据库,返回用户信息 (模拟数据,查询到了"admin")
 if("admin".equals(principal)){
 //第三步:如果用户名相同,校验密码,如果密码正确,不会报异常,如果校验不通过就报异常
 //参数1:用户名
 //参数2:校验的密码,从数据库查询出来的
 //参数3:realm的名字 。随便设置一个唯一字符串
 
 //4). md5加密盐值
 ByteSource salt = ByteSource.Util.bytes("nchu234we");
 
                SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(principal,"8763d15228c560fed665e1fe73b2f601",salt,this.getName());
 return authenticationInfo;
            }
        } catch (Exception e) {
 e.printStackTrace();
        }
 return null;
    }
 
 /**
     * 权限授权
     */
 @Override
 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection token) {
 return null;
    }
}

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

注意:现在校验后返回的认证信息是一个字符串的用户名,而我们如果将Shiro的校验功能用到登录的逻辑里面,我明显需要返回的不是一个用户名,而是用户的信息。

用户的信息,我们只能使用一个实体类来封装。可以是JavaBean或者是Map

答:我们校验方法返回的SimpleAuthenticationInfo的构建方法的第一个参数就是用于指定,返回的用户认证信息的。可以将用户名修改为一个我们指定的实体类对象就可以了!!!

--构建一个实体类

package cn.gzsxt.javabean;
 
import java.io.Serializable;
 
/**
 * 注意:因为Shiro是一个支持缓存的框架,所以实体类需要实现序列化接口
 * @author ranger
 *
 */
public class ActiveUser implements Serializable{
 
 private static final long serialVersionUID = -1354674546192347496L;
 private Integer userId;
 public Integer getUserId() {
 return userId;
    }
 public void setUserId(Integer userId) {
 this.userId = userId;
    }
 private String username;
 private String password;
 private Integer age;
 private Integer status;
 public String getUsername() {
 return username;
    }
 public void setUsername(String username) {
 this.username = username;
    }
 public String getPassword() {
 return password;
    }
 public void setPassword(String password) {
 this.password = password;
    }
 public Integer getAge() {
 return age;
    }
 public void setAge(Integer age) {
 this.age = age;
    }
 public Integer getStatus() {
 return status;
    }
 public void setStatus(Integer status) {
 this.status = status;
    }
 public static long getSerialversionuid() {
 return serialVersionUID;
    }
 
}
 

--修改返回的认证信息

package cn.gzsxt.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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
 
import cn.gzsxt.javabean.ActiveUser;
 
/**
 * Realm :所有Realm的父接口
 * AuthenticatingRealm :只有权限校验,没有权限授权的Realm
 * AuthorizingRealm : 既有权限校验,权限授权的Realm (主要就是使用它)
 * JdbcRealm:使用实现的对数据库 操作的代码的Realm。它已经写死了表名,必要要按它定义的表名定义数据库表。(灵活性差)
 *
 * 注意事项:使用Realm,将验证认证信息与获得授权信息,都放在一起!!!!!
 * @author ranger
 *
 *
 */
public class MyRealm extends AuthorizingRealm {
 
 /**
     * 用于权限校验
     */
 @Override
 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
 try {
            System.out.println("=权限校验=");
 
 //第一步:获得请求过来的用户名
            Object principal = token.getPrincipal();
 
 //第二步:根据用户查询数据库,返回用户信息 (模拟数据,查询到了"admin")
 if("admin".equals(principal)){
 //第三步:如果用户名相同,校验密码,如果密码正确,不会报异常,如果校验不通过就报异常
 //参数1:用户名
 //参数2:校验的密码,从数据库查询出来的
 //参数3:realm的名字 。随便设置一个唯一字符串
 
                ActiveUser user=new ActiveUser();
 user.setUserId(1);
 user.setAge(20);
 user.setPassword("8763d15228c560fed665e1fe73b2f601");
 user.setUsername("admin");
 user.setStatus(0);
 
 //4). md5加密盐值
                ByteSource credentialsSalt = ByteSource.Util.bytes("nchu234we");
 //参数1:用于设置认证信息,返回给调用对象的
 //参数2:校验的密码
 //参数3:如果配置了Md5加密,而且设置了需要加盐,该参数就是密码的盐
 //参数4:指定realm的名字,随便写个唯一的字符串就可以。建议直接使用this.getName();
                SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(user,"8763d15228c560fed665e1fe73b2f601",credentialsSalt,this.getName());
 return authenticationInfo;
            }
        } catch (Exception e) {
 e.printStackTrace();
        }
         //如果校验成功,返回null
 return null;
    }
 
 /**
     * 权限授权
     */
 @Override
 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection token) {
 return null;
    }
}

3.5. 权限授予-配置入门

3.5.1. 第一步:检验Subject对象的权限校验方法

--校验代码

package cn.gzsxt.test;
 
import java.util.ArrayList;
import java.util.List;
 
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;
 
/**
 * 注意:根据示例
 * 1.身份信息是放在Subject这个身份对象里面的
 * 2.Shiro的所有对象是通过securityManager来管理
 * 3.可以在配置文件配置,认证的信息(数据库里面的表数据)
 * @author ranger
 *
 */
public class ShiroTest {
 
 public static void main(String[] args) {
 //第一步:读取配置文件
        IniSecurityManagerFactory factory= new IniSecurityManagerFactory("classpath:shiro.ini");
 //第二步:获得安全管理器
        SecurityManager securityManager = factory.createInstance();
 //第三步:通过安全管理器帮助类构建一个Subject(身份)
        SecurityUtils.setSecurityManager(securityManager);
 Subject subject = SecurityUtils.getSubject();
 
 //第四步:构建身份信息(用户名/密码)
        UsernamePasswordToken token = new  UsernamePasswordToken("admin","123456");
 
 //第五步:校验是否成功,将一个空的身份,以及身份信息通过登录方法,如果成功返回带身份信息的Subject对象。如果不成功就报异常
 try {
 Subject result = securityManager.login(subject, token);
            System.out.println("认证成功,用户名"+result.getPrincipals());
 
 boolean flag = result.isAuthenticated();
 //使用校验方法,校验用户对应的角色
 boolean hasRole = result.hasRole("roleAdmin");
            System.out.println("是否有指定的角色:"+hasRole);
            List<String> hasRoles=new ArrayList<>();
 hasRoles.add("roleAdmin");
 hasRoles.add("roleEdu");
 boolean allRoles = result.hasAllRoles(hasRoles);
            System.out.println("是否都包括集合的所有角色:"+allRoles);
 
 //校验用户是否有对应的权限
 boolean permitted = result.isPermitted("user:add");
            System.out.println("是否有user:add权限:"+permitted);
 
 boolean permitted2 = result.isPermitted("modular:add");
            System.out.println("是否有modular:add权限:"+permitted2);
 
            System.out.println(flag);
        } catch (AuthenticationException e) {
            System.out.println("用户名或者密码出错");
 e.printStackTrace();
        }
    }
}

---配置文件

#users标签:用于指定用户信息,以及用户的角色
#注意:shiro的支持一个用于有多个角色的
#用户名= 密码, 角色1, 角色2, …, 角色N
#如果出现多个角色,用于取的是角色的并集
[users]
 admin = 123456,roleAdmin,roleEdu
#roles标签:用于设置角色的信息,包括的角色以及权限
#权限字符串的格式为:模块名:操作:操作...  类似我们的子权限的设置 
[roles]
   roleAdmin = user:query,user:add,user:delete,modular:*
   roleEdu = edu:query,edu:add

3.5.2. 第二步:在Realm授权

根据以上代码,我们确认,在配置文件配置的角色以及权限只可以通过权限校验的。

问题:我们以后开发程序是不可以将程序的权限以及角色写在配置文件里面的。而是写在数据库里面!!!我们如何将数据库里面的权限设置给我们对象的认证者呢?

答:在我们AuthorizingRealm提供了权限授予的方法doGetAuthorizationInfo可以用于授权。替换在配置文件的权限、角色信息。

--JavaBean

package cn.gzsxt.javabean;
 
import java.io.Serializable;
 
/**
 * 注意:因为Shiro是一个支持缓存的框架,所以实体类需要实现序列化接口
 * @author ranger
 *
 */
public class ActiveUser implements Serializable{
 
 private static final long serialVersionUID = -1354674546192347496L;
 private Integer userId;
 public Integer getUserId() {
 return userId;
    }
 public void setUserId(Integer userId) {
 this.userId = userId;
    }
 private String username;
 private String password;
 private Integer age;
 private Integer status;
 
 public String getUsername() {
 return username;
    }
 public void setUsername(String username) {
 this.username = username;
    }
 public String getPassword() {
 return password;
    }
 public void setPassword(String password) {
 this.password = password;
    }
 public Integer getAge() {
 return age;
    }
 public void setAge(Integer age) {
 this.age = age;
    }
 public Integer getStatus() {
 return status;
    }
 public void setStatus(Integer status) {
 this.status = status;
    }
 public static long getSerialversionuid() {
 return serialVersionUID;
    }
 
}
 

--Realm

package cn.gzsxt.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;
 
import cn.gzsxt.javabean.ActiveUser;
import cn.gzsxt.javabean.Role;
 
/**
 * Realm :所有Realm的父接口
 * AuthenticatingRealm :只有权限校验,没有权限授权的Realm
 * AuthorizingRealm : 既有权限校验,权限授权的Realm (主要就是使用它)
 * JdbcRealm:使用实现的对数据库 操作的代码的Realm。它已经写死了表名,必要要按它定义的表名定义数据库表。(灵活性差)
 *
 * 注意事项:使用Realm,将验证认证信息与获得授权信息,都放在一起!!!!!
 * @author ranger
 *
 *
 */
public class MyRealm extends AuthorizingRealm {
 
 /**
     * 用于权限校验
     */
 @Override
 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
 try {
            System.out.println("=权限校验=");
 
 //第一步:获得请求过来的用户名
            Object principal = token.getPrincipal();
 
 //第二步:根据用户查询数据库,返回用户信息 (模拟数据,查询到了"admin")
 if("admin".equals(principal)){
 //第三步:如果用户名相同,校验密码,如果密码正确,不会报异常,如果校验不通过就报异常
 //参数1:用户名
 //参数2:校验的密码,从数据库查询出来的
 //参数3:realm的名字 。随便设置一个唯一字符串
 
                ActiveUser user=new ActiveUser();
 user.setUserId(1);
 user.setAge(20);
 user.setPassword("8763d15228c560fed665e1fe73b2f601");
 user.setUsername("admin");
 user.setStatus(0);
 
 //4). md5加密盐值
                ByteSource credentialsSalt = ByteSource.Util.bytes("nchu234we");
 //参数1:用于设置认证信息,返回给调用对象的
 //参数2:校验的密码
 //参数3:如果配置了Md5加密,而且设置了需要加盐,该参数就是密码的盐
 //参数4:指定realm的名字,随便写个唯一的字符串就可以。建议直接使用this.getName();
                SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(user,"8763d15228c560fed665e1fe73b2f601",credentialsSalt,this.getName());
 return authenticationInfo;
            }
        } catch (Exception e) {
 e.printStackTrace();
        }
 
 
 return null;
    }
 
 /**
     * 权限授权,必须在通过验证后才执行的方法
     */
 @Override
 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection token) {
 
        System.out.println("===权限授予====");
 //获得当前通过验证的用户,为什么可以获得校验后的用户信息呢?
 //答:因为就是如果通不过校验,肯定就会有有授权,进入了授权肯定就有校验的认证用户了
 
        ActiveUser user=(ActiveUser) token.getPrimaryPrincipal();
 
 
        SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
 
 authorizationInfo.addStringPermission("user:query");
 authorizationInfo.addStringPermission("user:add");
 authorizationInfo.addStringPermission("user:delete");
 authorizationInfo.addStringPermission("user:edit");
 authorizationInfo.addStringPermission("modular:*");
 
 authorizationInfo.addRole("roleAdmin");
 
 //将权限设置角色里面
 Role role=new Role();
  role.setPermisssion(authorizationInfo.getStringPermissions());
  user.setRole(role);
 
 return authorizationInfo;
    }
}

--配置文件

[main]
# 对象名 =类全限制名 ,就是创建一个对象
myRealm = cn.gzsxt.realm.MyRealm
 
#加密的对象
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#设置加密的算法为md5
credentialsMatcher.hashAlgorithmName=md5
#设置md5加密次数为1次
credentialsMatcher.hashIterations=1
#设置md5算法是加盐
credentialsMatcher.hashSalted=true
 
#将加密对象指定给对应给myRealm对象
myRealm.credentialsMatcher=$credentialsMatcher
 
 
#将realm对象加入到securityManager容器里面
#引用 securityManager.realms = $对象名
#securityManager对象名是shiro固定的。用于指定securityManager容器
#对象的引用格式为: 对象名.属性名 = $对象名;
securityManager.realms = $myRealm

--测试代码

package cn.gzsxt.test;
 
import java.util.ArrayList;
import java.util.List;
 
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 cn.gzsxt.javabean.ActiveUser;
import cn.gzsxt.javabean.Role;
 
/**
 * 注意:根据示例
 * 1.身份信息是放在Subject这个身份对象里面的
 * 2.Shiro的所有对象是通过securityManager来管理
 * 3.可以在配置文件配置,认证的信息(数据库里面的表数据)
 * @author ranger
 *
 */
public class ShiroTest {
 
 public static void main(String[] args) {
 //第一步:读取配置文件
        IniSecurityManagerFactory factory= new IniSecurityManagerFactory("classpath:shiro.ini");
 //第二步:获得安全管理器
        SecurityManager securityManager = factory.createInstance();
 //第三步:通过安全管理器帮助类构建一个Subject(身份)
        SecurityUtils.setSecurityManager(securityManager);
        Subject subject = SecurityUtils.getSubject();
 
 //第四步:构建身份信息(用户名/密码)
        UsernamePasswordToken token = new  UsernamePasswordToken("admin","123456");
 
 //第五步:校验是否成功,将一个空的身份,以及身份信息通过登录方法,如果成功返回带身份信息的Subject对象。如果不成功就报异常
 try {
            Subject result = securityManager.login(subject, token);
            System.out.println("认证成功,用户名"+result.getPrincipals());
 
 
 
 boolean flag = result.isAuthenticated();
 //使用校验方法,校验用户对应的角色
 boolean hasRole = result.hasRole("roleAdmin");
            System.out.println("是否有指定的角色:"+hasRole);
            List<String> hasRoles=new ArrayList<>();
 hasRoles.add("roleAdmin");
 hasRoles.add("roleEdu");
 boolean allRoles = result.hasAllRoles(hasRoles);
            System.out.println("是否都包括集合的所有角色:"+allRoles);
 
 //校验用户是否有对应的权限
 boolean permitted = result.isPermitted("user:add");
            System.out.println("是否有user:add权限:"+permitted);
 
 boolean permitted2 = result.isPermitted("modular:add");
            System.out.println("是否有modular:add权限:"+permitted2);
 
            System.out.println(flag);
 
 
        } catch (AuthenticationException e) {
            System.out.println("用户名或者密码出错");
 e.printStackTrace();
        }
    }
}

4. 综合案例

在数据库里面设计,权限信息表。然后通过shiro读取数据库的信息。实现验证与授权。

4.1. 第一步:数据库设计

-- 导出 shiro-1115 的数据库结构
DROP DATABASE IF EXISTS `shiro-1115`;
CREATE DATABASE IF NOT EXISTS `shiro-1115` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `shiro-1115`;
 
-- 导出 表 shiro-1115.tb_admin 结构
DROP TABLE IF EXISTS `tb_admin`;
CREATE TABLE IF NOT EXISTS `tb_admin` (
  `admin_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '管理员编号',
  `admin_name` varchar(50) DEFAULT NULL COMMENT '管理员名',
  `admin_account` varchar(50) DEFAULT NULL COMMENT '登录账号',
  `admin_pwd` varchar(50) DEFAULT NULL COMMENT '登录密码',
  `create_date` datetime DEFAULT NULL COMMENT '创建日期',
  `admin_status` int(11) DEFAULT NULL COMMENT '管理员状态 0可用,1禁用',
  `role_id` bigint(20) DEFAULT NULL COMMENT '角色编号',
 PRIMARY KEY (`admin_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='管理员';
 
-- 正在导出表  shiro-1115.tb_admin 的数据:~1 rows (大约)
DELETE FROM `tb_admin`;
/*!40000 ALTER TABLE `tb_admin` DISABLE KEYS */;
INSERT INTO `tb_admin` (`admin_id`, `admin_name`, `admin_account`, `admin_pwd`, `create_date`, `admin_status`, `role_id`) VALUES
    (1, '配置管理员', 'admin', '123456', '2019-04-02 16:33:39', 0, 1);
/*!40000 ALTER TABLE `tb_admin` ENABLE KEYS */;
 
-- 导出 表 shiro-1115.tb_dictionary 结构
DROP TABLE IF EXISTS `tb_dictionary`;
CREATE TABLE IF NOT EXISTS `tb_dictionary` (
  `dictionary_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典编号',
  `dictionary_name` varchar(200) DEFAULT NULL COMMENT '字典名',
  `dictionary_value` varchar(500) DEFAULT NULL COMMENT '字典值',
  `dictionary_type_code` bigint(20) DEFAULT NULL COMMENT '字段类型编码',
  `dictionary_type_name` varchar(200) DEFAULT NULL COMMENT '字段类型名称',
 PRIMARY KEY (`dictionary_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='tb_dictionary';
 
-- 正在导出表  shiro-1115.tb_dictionary 的数据:~0 rows (大约)
DELETE FROM `tb_dictionary`;
/*!40000 ALTER TABLE `tb_dictionary` DISABLE KEYS */;
/*!40000 ALTER TABLE `tb_dictionary` ENABLE KEYS */;
 
-- 导出 表 shiro-1115.tb_modular 结构
DROP TABLE IF EXISTS `tb_modular`;
CREATE TABLE IF NOT EXISTS `tb_modular` (
  `modular_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '模块编号',
  `modular_name` varchar(200) DEFAULT NULL COMMENT '模块名',
  `modular_sort` bigint(20) DEFAULT NULL COMMENT '排序顺序',
 PRIMARY KEY (`modular_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='模块表';
 
-- 正在导出表  shiro-1115.tb_modular 的数据:~0 rows (大约)
DELETE FROM `tb_modular`;
/*!40000 ALTER TABLE `tb_modular` DISABLE KEYS */;
INSERT INTO `tb_modular` (`modular_id`, `modular_name`, `modular_sort`) VALUES
    (1, '系统管理模块', 0);
/*!40000 ALTER TABLE `tb_modular` ENABLE KEYS */;
 
-- 导出 表 shiro-1115.tb_permission 结构
DROP TABLE IF EXISTS `tb_permission`;
CREATE TABLE IF NOT EXISTS `tb_permission` (
  `permission_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '权限编号',
  `permission_name` varchar(200) DEFAULT NULL COMMENT '权限名',
  `permission_action` varchar(500) DEFAULT NULL COMMENT '权限路径,匹配路径是否有权限',
  `permission_is_show` int(11) DEFAULT NULL COMMENT '是否显示',
  `permission_key` varchar(500) DEFAULT NULL COMMENT '父菜单编号,0表示顶级菜单',
  `modular_id` bigint(20) DEFAULT NULL COMMENT '模块编号',
 PRIMARY KEY (`permission_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='权限表';
 
-- 正在导出表  shiro-1115.tb_permission 的数据:~2 rows (大约)
DELETE FROM `tb_permission`;
/*!40000 ALTER TABLE `tb_permission` DISABLE KEYS */;
INSERT INTO `tb_permission` (`permission_id`, `permission_name`, `permission_action`, `permission_is_show`, `permission_key`, `modular_id`) VALUES
    (1, '管理员管理', '/admin/toAdminList', 0, 'admin:list', 1),
    (2, '管理员管理-To增加', '/admin/toAdminAdd', 0, 'admin:list:to_add', 1),
    (3, '管理员管理-增加', '/admin/addAdmin', 0, 'admin:list:add', 1);
/*!40000 ALTER TABLE `tb_permission` ENABLE KEYS */;
 
-- 导出 表 shiro-1115.tb_role 结构
DROP TABLE IF EXISTS `tb_role`;
CREATE TABLE IF NOT EXISTS `tb_role` (
  `role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色编号',
  `role_name` varchar(50) DEFAULT NULL COMMENT '角色名',
  `role_permissions` varchar(1000) DEFAULT NULL COMMENT '权限集,权限编号使用逗号分隔',
 PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色';
 
-- 正在导出表  shiro-1115.tb_role 的数据:~1 rows (大约)
DELETE FROM `tb_role`;
/*!40000 ALTER TABLE `tb_role` DISABLE KEYS */;
INSERT INTO `tb_role` (`role_id`, `role_name`, `role_permissions`) VALUES
    (1, '超级管理员', '1,2,3');
/*!40000 ALTER TABLE `tb_role` ENABLE KEYS */;

4.2. 第二步:配置Shiro入门示例

--配置文件

[users]
 admin = 123456,roleAdmin
[roles]
   roleAdmin = user:list,user:list:add,user:list:to_add

--测试入口

package cn.gzsxt.test;
 
import org.apache.shiro.SecurityUtils;
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) {
 //第一步:读取配置文件,创建SecurityManager容器
        IniSecurityManagerFactory factory=new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.createInstance();
 
 //第二步:通过SecurityUtil获得一个身份对象
        SecurityUtils.setSecurityManager(securityManager);
        Subject subject = SecurityUtils.getSubject();
 
 //第三步:构建一个身份信息(Token)
        UsernamePasswordToken token=new UsernamePasswordToken("admin","123456");
 //验证信息,获得配置文件的身份信息以及权限
 
        Subject resultSubject = securityManager.login(subject, token);
 
        System.out.println("用户信息:"+resultSubject.getPrincipal());
    }
 
}

4.3. 第三步:编写实体类

--Admin

package cn.gzsxt.pojo;
 
import java.io.Serializable;
 
 
public class Admin implements Serializable {
 
 private static final long serialVersionUID = -4165903044029644075L;
 
 private Long adminId;//BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '管理员编号',
 private String adminName;//VARCHAR(50) NULL DEFAULT NULL COMMENT '管理员名',
 private String adminAccount;//VARCHAR(50) NULL DEFAULT NULL COMMENT '登录账号',
 private String adminPwd;//VARCHAR(50) NULL DEFAULT NULL COMMENT '登录密码',
 private String createDate;//DATETIME NULL DEFAULT NULL COMMENT '创建日期',
 private Integer adminStatus;//INT(11) NULL DEFAULT NULL COMMENT '管理员状态 0可用,1禁用',
 private Long roleId;//BIGINT(20) NULL DEFAULT NULL COMMENT '角色编号',
 
 //一个管理员只能是有一个角色
 private Role role;
 
 public Role getRole() {
 return role;
    }
 public void setRole(Role role) {
 this.role = role;
    }
 public Long getAdminId() {
 return adminId;
    }
 public void setAdminId(Long adminId) {
 this.adminId = adminId;
    }
 public String getAdminName() {
 return adminName;
    }
 public void setAdminName(String adminName) {
 this.adminName = adminName;
    }
 public String getAdminAccount() {
 return adminAccount;
    }
 public void setAdminAccount(String adminAccount) {
 this.adminAccount = adminAccount;
    }
 public String getAdminPwd() {
 return adminPwd;
    }
 public void setAdminPwd(String adminPwd) {
 this.adminPwd = adminPwd;
    }
 public String getCreateDate() {
 return createDate;
    }
 public void setCreateDate(String createDate) {
 this.createDate = createDate;
    }
 public Integer getAdminStatus() {
 return adminStatus;
    }
 public void setAdminStatus(Integer adminStatus) {
 this.adminStatus = adminStatus;
    }
 public Long getRoleId() {
 return roleId;
    }
 public void setRoleId(Long roleId) {
 this.roleId = roleId;
    }
}

--Role

package cn.gzsxt.pojo;
 
import java.io.Serializable;
import java.util.List;
 
public class Role implements Serializable {
 
 private static final long serialVersionUID = 7439278538619165462L;
 
 private Long roleId;//BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '角色编号',
 private String roleName;//VARCHAR(50) NULL DEFAULT NULL COMMENT '角色名',
 private String rolePermissions;//VARCHAR(1000) NULL DEFAULT NULL COMMENT '权限集,权限编号使用逗号分隔',
 //一个就是有多个权限
 private List<Permission> permissions;
 public List<Permission> getPermissions() {
 return permissions;
    }
 public void setPermissions(List<Permission> permissions) {
 this.permissions = permissions;
    }
 public Long getRoleId() {
 return roleId;
    }
 public void setRoleId(Long roleId) {
 this.roleId = roleId;
    }
 public String getRoleName() {
 return roleName;
    }
 public void setRoleName(String roleName) {
 this.roleName = roleName;
    }
 public String getRolePermissions() {
 return rolePermissions;
    }
 public void setRolePermissions(String rolePermissions) {
 this.rolePermissions = rolePermissions;
    }
 
}

--Permission

package cn.gzsxt.pojo;
 
import java.io.Serializable;
 
public class Permission implements Serializable {
 
 
 private static final long serialVersionUID = -8720560773258570437L;
 
 private Long permissionId;//BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '权限编号',
 private String permissionName;//VARCHAR(200) NULL DEFAULT NULL COMMENT '权限名',
 private String permissionAction;//VARCHAR(500) NULL DEFAULT NULL COMMENT '权限路径,匹配路径是否有权限',
 private Integer permissionIsShow;//INT(11) NULL DEFAULT NULL COMMENT '是否显示',
 private String permissionKey;//VARCHAR(500) NULL DEFAULT NULL COMMENT '父菜单编号,0表示顶级菜单',
 private Long modularId;//BIGINT(20) NULL DEFAULT NULL COMMENT '模块编号',
 public Long getPermissionId() {
 return permissionId;
    }
 public void setPermissionId(Long permissionId) {
 this.permissionId = permissionId;
    }
 public String getPermissionName() {
 return permissionName;
    }
 public void setPermissionName(String permissionName) {
 this.permissionName = permissionName;
    }
 public String getPermissionAction() {
 return permissionAction;
    }
 public void setPermissionAction(String permissionAction) {
 this.permissionAction = permissionAction;
    }
 public Integer getPermissionIsShow() {
 return permissionIsShow;
    }
 public void setPermissionIsShow(Integer permissionIsShow) {
 this.permissionIsShow = permissionIsShow;
    }
 public String getPermissionKey() {
 return permissionKey;
    }
 public void setPermissionKey(String permissionKey) {
 this.permissionKey = permissionKey;
    }
 public Long getModularId() {
 return modularId;
    }
 public void setModularId(Long modularId) {
 this.modularId = modularId;
    }
}

4.4. 第四步:编写数据库连接

package cn.gzsxt.utils;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
 
 
 
public class DbUitls {
 
 //1.获得数据库连接
 public static Connection getConnection(){
 //四要素
        String driver="org.gjt.mm.mysql.Driver";
        String url="jdbc:mysql://localhost:3306/shiro-1115";
        String user="root";
        String password="123456";
 
 //加载驱动
 try {
            Class.forName(driver);
 return DriverManager.getConnection(url, user, password);
        } catch (ClassNotFoundException e) {
 e.printStackTrace();
        } catch (SQLException e) {
 e.printStackTrace();
        }
 return null;
    }
 
 public static void main(String[] args) {
        System.out.println(DbUitls.getConnection());
    }
 
}

4.5. 第五步:实现权限验证

--权限验证代码

package cn.gzsxt.realm;
 
import java.sql.SQLException;
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 cn.gzsxt.dao.AdminDAO;
import cn.gzsxt.dao.PermissionDAO;
import cn.gzsxt.dao.RoleDAO;
import cn.gzsxt.pojo.Admin;
import cn.gzsxt.pojo.Permission;
import cn.gzsxt.pojo.Role;
 
public class MyRealm extends AuthorizingRealm {
 
 private AdminDAO adminDAO = new AdminDAO();
 private RoleDAO roleDAO=new RoleDAO();
 private PermissionDAO permissionDAO =new PermissionDAO();
 
 /**
     * 权限验证
     */
 @Override
 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("=权限验证==");
 
 // 连接数据库,通过用户名查询用户信息
 // 1.获得认证信息,账号名
        String adminAccount = (String) token.getPrincipal();
 // 2.通过账号名查询查询指定的管理员记录
 try {
            Admin admin = adminDAO.findByAccount(adminAccount);
 //密码加盐
            ByteSource salt=ByteSource.Util.bytes("asdfwera"+admin.getAdminSalt());
            SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(admin,admin.getAdminPwd(),salt,this.getName());
 return authenticationInfo;
        } catch (SQLException e) {
 e.printStackTrace();
        }
 
 return null;
    }
 
 /**
     * 权限授权,授予必须依赖权限验证通过
     */
 @Override
 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
 
    }
 
}
 

--配置文件修改

#[users]
#   admin = 123456,roleAdmin
#[roles]
#   roleAdmin = user:list,user:list:add,user:list:to_add
 
[main]
  #自定义Realm
  myRealm =  cn.gzsxt.realm.MyRealm
  #创建一个Hash算法的对象
  credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
  #设置hash算法是Md5算法
  credentialsMatcher.hashAlgorithmName=md5
  #设置迭代加密的次数
  credentialsMatcher.hashIterations=2
  #设置是否加盐
  credentialsMatcher.hashSalted=true
 
 
  #指定自定义Realm支持hash算法加密的密码
  myRealm.credentialsMatcher=$credentialsMatcher
  securityManager.realms=$myRealm

4.6. 第六步:实现权限授予

package cn.gzsxt.realm;
 
import java.sql.SQLException;
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 cn.gzsxt.dao.AdminDAO;
import cn.gzsxt.dao.PermissionDAO;
import cn.gzsxt.dao.RoleDAO;
import cn.gzsxt.pojo.Admin;
import cn.gzsxt.pojo.Permission;
import cn.gzsxt.pojo.Role;
 
public class MyRealm extends AuthorizingRealm {
 
 private AdminDAO adminDAO = new AdminDAO();
 private RoleDAO roleDAO=new RoleDAO();
 private PermissionDAO permissionDAO =new PermissionDAO();
 
 /**
     * 权限验证
     */
 @Override
 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("=权限验证==");
 
 // 连接数据库,通过用户名查询用户信息
 // 1.获得认证信息,账号名
        String adminAccount = (String) token.getPrincipal();
 // 2.通过账号名查询查询指定的管理员记录
 try {
            Admin admin = adminDAO.findByAccount(adminAccount);
 //密码加盐
            ByteSource salt=ByteSource.Util.bytes("asdfwera"+admin.getAdminSalt());
            SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(admin,admin.getAdminPwd(),salt,this.getName());
 return authenticationInfo;
        } catch (SQLException e) {
 e.printStackTrace();
        }
 
 return null;
    }
 
 /**
     * 权限授权,授予必须依赖权限验证通过
     */
 @Override
 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
 //获得当前验证通过的管理员
        Admin admin=(Admin) principalCollection.getPrimaryPrincipal();
 //通过当前管理员获得角色编号
        Long roleId = admin.getRoleId();
 try {
 //通过角色编号查询唯一的角色(单角色权限验证)
            Role role = roleDAO.findByRoleId(roleId);
 //将角色信息放在管理员的实体类里面
 admin.setRole(role);
 
 //通过就是的权限ID集,获得角色的权限
            String rolePermissions = role.getRolePermissions();
            List<Permission> permissions = permissionDAO.findByIds(rolePermissions);
 //将角色的权限赋予角色对象
 role.setPermissions(permissions);
 
 //创建一个权限授予对象
            SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
 //将角色设置给该对象
 authorizationInfo.addRole(role.getRoleName());
 //将权限设置给Shiro的权限对象
 for (Permission permission : permissions) {
 authorizationInfo.addStringPermission(permission.getPermissionKey());
            }
 //返回
 return authorizationInfo;
 
        } catch (SQLException e) {
 e.printStackTrace();
        }
 
 return null;
    }
 
}
 

5. 总结

1. Shiro是什么

一个权限控制框架。

2. Shiro的作用是什么

就是在实现Rbac系统的时候,使用它来做权限验证,可以减少我们的开发的代码。

3. 我们将使用的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 授权成功返回的信息类的实现类

bc6ba035c571985547d0c99406e27bdd.png
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值