Shiro基础:简单用户认证+权限测试+自定义安全策略+MD5加密

1.简介

1.1什么是Shiro

Apache Shiro(日语“堡垒(Castle)”的意思)是一个强大易用的Java安全框架,
提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障 - 从命令行应用、移动应用到大型网络及企业应用。
Apache Shiro 是一个强大而灵活的开源安全框架,它干净利落地处理身份认证,授权,企业会话管理和加密。
Apache Shiro 的首要目标是易于使用和理解。安全有时候是很复杂的,甚至是痛苦的,但它没有必要这样。框架应该尽可能掩盖复杂的地方,露出一个干净而直观的 API,来简化开发人员在使他们的应用程序安全上的努力。以下是你可以用 Apache Shiro 所做的事情:
 验证用户来核实他们的身份
 对用户执行访问控制,如:
 判断用户是否被分配了一个确定的安全角色
 判断用户是否被允许做某事
 在任何环境下使用 Session API,即使没有 Web 或 EJB 容器。
 在身份验证,访问控制期间或在会话的生命周期,对事件作出反应。
 聚集一个或多个用户安全数据的数据源,并作为一个单一的复合用户“视图”。
 启用单点登录(SSO)功能。
 为没有关联到登录的用户启用"Remember Me"服务

以及更多——全部集成到紧密结合的易于使用的 API 中。
Shiro 视图在所有应用程序环境下实现这些目标——从最简单的命令行应用程序到最大的企业应用,不强制依赖其他第三方框架,容器,或应用服务器。当然,该项目的目标是尽可能地融入到这些环境,但它能够在任何环境下立即可用。

1.2Shiro整体架构图

在这里插入图片描述

  1. Subject:主体,可以看到主体可以是任何与应用交互的“用户”。
    2. SecurityManager:相当于 SpringMVC 中的 DispatcherServlet 或者 Struts2 中的FilterDispatcher。它是 Shiro 的核心,所有具体的交互都通过 SecurityManager 进行控制。它管理着所有 Subject、且负责进行认证和授权、及会话、缓存的管理。
    3. Authenticator:认证器,负责主体认证的,这是一个扩展点,如果用户觉得 Shiro 默认的不好,我们可以自定义实现。其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了。
    4. Authrizer:授权器,或者访问控制器。它用来决定主体是否有权限进行相应的操作,即控制着用户能访问应用中的哪些功能。
    5. Realm:可以有1个或多个 Realm,可以认为是安全实体数据源,即用于获取安全实体的。它可以是 JDBC 实现,也可以是 LDAP 实现,或者内存实现等。
    6. SessionManager:如果写过 Servlet 就应该知道 Session 的概念,Session 需要有人去管理它的生命周期,这个组件就是 SessionManager。而 Shiro 并不仅仅可以用在 Web 环境,也可以用在如普通的 JavaSE 环境。
    7. SessionDAO:DAO 大家都用过,数据访问对象,用于会话的 CRUD。我们可以自定义 SessionDAO 的实现,控制 session 存储的位置。如通过 JDBC 写到数据库或通过 jedis 写入 redis 中。另外 SessionDAO 中可以使用 Cache 进行缓存,以提高性能。
    8. CacheManager:缓存管理器。它来管理如用户、角色、权限等的缓存的。因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能。
    9. Cryptography:密码模块,Shiro 提高了一些常见的加密组件用于如密码加密/解密的

2.测试代码

2.1.目录结构

在这里插入图片描述

2.2pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.wo</groupId>
    <artifactId>shiro_test</artifactId>
    <version>1.0-SNAPSHOT</version>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- shiro 安全框架的jar包-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>


    </dependencies>


</project>

2.3application.yml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/test4?useUnicode=true&characterEncoding=utf8&useSSL=false
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml

3.简单的用户认证

3.1 shiro_first.ini

[users]
zhangsan=123
lisi=123

3.2TestShiro


@RunWith(SpringRunner.class)
@SpringBootTest
public class TestShiro {

    @Test
    public void testFirstShiro(){
        //使用IniSecurityManagerFactory加载shiro_first.ini文件
        IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shiro_first.ini");
        //使用工厂类创建securityManager
        SecurityManager securityManager = iniSecurityManagerFactory.createInstance();
        //使用shiro提供的工具类来创建manager的运行环境
        SecurityUtils.setSecurityManager(securityManager);
        //使用工具类获取我们的主体部分
        Subject subject = SecurityUtils.getSubject();
        //设置用户名及密码部分
        //前端用户传输的用户名和密码
        UsernamePasswordToken token = new UsernamePasswordToken("lisi", "123");
        //从主题中开始登录
        try {
            subject.login(token);
            System.out.println("用户登录成功!!!!!!!!");
        }catch (IncorrectCredentialsException inc){
            System.out.println("用户登录失败!!!!!!!!!失败原因 密码错误!!!");
        }catch (UnknownAccountException uae){
            System.out.println("用户登录失败!!!!!!!!失败原因,没有该用户名");
        }

        if(subject.isAuthenticated()){
            System.out.println("验证通过");
        }else{
            System.out.println("验证失败");
        }
    }
}

4.拥有权限的简单测试

4.1shiro_permission.ini

[users]
normal=123,role1
admin=admin,role2
root=root,role3
[roles]
role1=user:select
role2=user:select,user:update
role3=user:creat,user:delete,user:select,user:update

4.2TestShiroPermissions

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestShiroPermissions {

    @Test
    public void testUserPermissions(){
        //使用IniSecurityManagerFactory加载shiro_first.ini文件
        IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shiro_permission.ini");
        //使用工厂类创建securityManager
        SecurityManager securityManager = iniSecurityManagerFactory.createInstance();
        //使用shiro提供的工具类来创建manager的运行环境
        SecurityUtils.setSecurityManager(securityManager);
        //使用工具类获取我们的主体部分
        Subject subject = SecurityUtils.getSubject();
        //设置用户名及密码部分
        //前端用户传输的用户名和密码
        UsernamePasswordToken token = new UsernamePasswordToken("root", "root");
        //从主题中开始登录
        try {
            subject.login(token);
            System.out.println("用户登录成功!!!!!!!!");
        }catch (IncorrectCredentialsException inc){
            System.out.println("用户登录失败!!!!!!!!!失败原因 密码错误!!!");
        }catch (UnknownAccountException uae){
            System.out.println("用户登录失败!!!!!!!!失败原因,没有该用户名");
        }
        //判断用户的角色
        String rol="role2";
        boolean hasRole = subject.hasRole(rol);
        if(hasRole){
            System.out.println("用户拥有"+rol+"角色");
        }else {
            System.out.println("用户没有"+rol+"角色");
        }
        //判断用户权限
        String per="user:delete";
        boolean b = subject.isPermitted(per);
        if (b){
            System.out.println("用户拥有"+per+"权限");
        }else {
            System.out.println("用户没有"+per+"权限");
        }
        //批量验证该用户的角色
        boolean[] hasRoles = subject.hasRoles(Arrays.asList("role1", "role2", "role3"));
        System.out.println(Arrays.toString(hasRoles));
        //批量验证该用户的权限
        boolean[] permitted = subject.isPermitted("user:creat", "user:delete");
        System.out.println(Arrays.toString(permitted));
        //验证用户是否拥有输入的全部权限
        boolean permittedAll = subject.isPermittedAll("user:creat", "user:delete");
        System.out.println(permittedAll);

    }
}

5.自定义安全策略的shiro应用案例:

5.1shiro_myrealm.ini

[main]
#自定义realm
myrealm=com.wo.shiro.MyRealm
#在shiro核心中,设置自定义myrealm
securityManager.realms=$myrealm

5.2MyRealm

public class MyRealm extends AuthorizingRealm {

    //授权的方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //获取到前端传输的用户名
        String username = (String) principals.getPrimaryPrincipal();
        //使用前端传输用户名5表联查,获取到用户的所拥有的权限信息
        HashSet<String> objects=new HashSet<>();
        objects.add("user:create");
        objects.add("user:update");
        //声明simpleAuthorizationInfo 对象
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //将权限放置到声明simpleAuthorizationInfo 对象中
        simpleAuthorizationInfo.setStringPermissions(objects);
        //放置角色
        simpleAuthorizationInfo.addRole("role1");
        return simpleAuthorizationInfo;
    }

    //认证的方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取到前端传输的用户名
        String username = (String) token.getPrincipal();
        //使用前端用户名去数据库查询正确的密码
        String password="123";
        //将前端传输过来的用户名,以及使用该用户名 查询到的正确密码放置到查询出的正确密码放置到simpleAuthticationinfo中进行返回
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, getName());
        return simpleAuthenticationInfo;
    }
}

5.3 TestShiroMyRealm

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestShiroMyRealm {
    @Test
    public void testMyRealm(){
        //使用IniSecurityManagerFactory加载shiro_first.ini文件
        IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shiro_myrealm.ini");
        //使用工厂类创建securityManager
        SecurityManager securityManager = iniSecurityManagerFactory.createInstance();
        //使用shiro提供的工具类来创建manager的运行环境
        SecurityUtils.setSecurityManager(securityManager);
        //使用工具类获取我们的主体部分
        Subject subject = SecurityUtils.getSubject();
        //设置用户名及密码部分
        //前端用户传输的用户名和密码
        UsernamePasswordToken token = new UsernamePasswordToken("root", "123");
        //从主题中开始登录

        try {
            subject.login(token);
            System.out.println("用户登录成功");

        }catch (IncorrectCredentialsException ex){
            System.out.println("用户登录失败,失败原因:密码错误");
        }
        boolean b = subject.hasRole("role2");
        if (b){
            System.out.println("用户拥有该角色");
        }else {
            System.out.println("用户没有该角色");
        }
        boolean permitted = subject.isPermitted("user:create");
        if (permitted){
            System.out.println("用户拥有该权限");
        }else {
            System.out.println("用户没有该权限");

        }
    }
}

6.自定义安全策略并凭证MD5加密的shiro应用案例

6.1shiro_myrealmMd5.ini

[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#设置散列算法
credentialsMatcher.hashAlgorithmName=md5
#设置散列次数
credentialsMatcher.hashIterations=1

#将凭证匹配器设置到realm
myRealm=com.wo.shiro.MyRealmMD5
myRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$myRealm

6.2MyRealmMD5

public class MyRealmMD5 extends AuthorizingRealm{
    //权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        //用username 去数据库获取加密后的密码 202cb962ac59075b964b07152d234b70
        String password="202cb962ac59075b964b07152d234b70";
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, getName());
        return simpleAuthenticationInfo;
    }
}

6.3TestShiroMd5MyRealm

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestShiroMd5MyRealm {

    @Test
    public void testMd5(){

        //使用IniSecurityManagerFactory加载shiro_first.ini文件
        IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shiro_myrealmMd5.ini");
        //使用工厂类创建securityManager
        SecurityManager securityManager = iniSecurityManagerFactory.createInstance();
        //使用shiro提供的工具类来创建manager的运行环境
        SecurityUtils.setSecurityManager(securityManager);
        //使用工具类获取我们的主体部分
        Subject subject = SecurityUtils.getSubject();

        String username = "zhangsan";
        String password = "123";
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token);
            System.out.println("用户登录成功");
        }catch (IncorrectCredentialsException inc){
            System.out.println("用户登录失败");

        }


    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值