Shiro安全框架学习

Shiro安全框架学习

一、shiro简介(简介内容来自百度百科)

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

三个核心组件:Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果系统默认的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

二、学习目标

① 认识shiro的整体架构,各组件的概念

② shiro认证,授权的过程

③ shiro自定义的realm、Filter

④ shiro的加密

想更了解“shiro”的小伙伴可以去慕课网搜索“shiro安全框架入门”
链接地址:https://www.imooc.com/view/977
在这里插入图片描述

三、shiro与spring Security的比较(spring的官网也是用shiro做安全管理的)

1、Shiro比Spring更容易使用,实现和最重要的理解。

2、Spring Security更加知名的唯一原因是因为品牌名称。

3、“Spring”以简单而闻名,但讽刺的是很多人发现安装Spring Security很难
但是Spring Security却有更好的社区支持。

4、Apache Shiro在Spring Security处理密码学方面有一个额外的模块。

5、Spring-security 对spring 结合较好,如果项目用的springmvc ,使用起来很方便。但是如果项目中没有用到spring,那就不要考虑它了。

6、Shiro 功能强大、且 简单、灵活。是Apache 下的项目比较可靠,且不跟任何的框架或者容器绑定,可以独立运行。
总结
Apache shiro: 简单灵活、可脱离spring、粒度较粗
spring Security: 复杂笨重、不可脱离spring、粒度更细

四、Shiro的整体架构

在这里插入图片描述
①上面标记为1的是shiro的主体部分subject,可以理解为当前的操作用户

② Security Manager为Shiro的核心,shiro是通过security Manager来提供安全服务的,security Manager管理着Session Manager、Cache Manager等其他组件的实例:Authenticator(认证器,管理我们的登录登出) Authorizer(授权器,负责赋予主体subject有哪些权限) Session Manager(shiro自己实现的一套session管理机制,可以不借助任何web容器的情况下使用session) Session Dao(提供了session的增删改查操作) cache Manager(缓存管理器,用于缓存角色数据和权限数据) Pluggable Realms(shiro与数据库/数据源之间的桥梁,shiro获取认证信息、权限数据、角色数据都是通过Realms来获取)

③ 上图标记为2的cryptography是用来做加密的,使用它可以非常方便快捷的进行数据加密。

④ 上面箭头的流程可以这样理解:主体提交请求到Security Manager,然后由Security Manager调用Authenticator去做认证,而Authenticator去获取认证数据的时候是通过Realms从数据源中来获取的,然后把从数据源中拿到的认证信息与主体提交过来的认证信息做比对。授权器Authorizer也是一样。

五、Shiro的认证

① 创建Security Manager:Security Manager是用来提供安全服务的,所以在做shiro认证的时候要先创建此对象

② 主体Subject提交请求给Security Manager

③ Security Manager调用Authenticator组件做认证

④Authenticator通过Realm来从数据源中获取认证数据

1、引入依赖

<dependencies>
	<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
	</dependency>
</dependencies>

2、测试用例

package com.shiroDemo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;

/**
 * @program: shiro-demo
 * @description: shiro权限测试类
 * @author: Mr.Wang
 * @create: 2021-11-05 09:42
 **/
public class AuthenticationTest {

    //除了SimpleAccountRealm还有JdbcRealm等
    SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();

    //在认证之前先在Realm中添加一个用户,创建Security Manager的时候要用到Realm
    @Before
    public void addUser(){
        simpleAccountRealm.addAccount("wxc","123456");
    }

    @Test//Shiro的认证
    public void testAutentication(){
        //1.构建Security Manager环境(Security Manager是用来提供安全服务的,所以在做shiro认证的时候要先创建此对象,创建Security Manager对象之后要设置Realm)
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(simpleAccountRealm);

        //2.获取向Security Manager提交请求的subject,而主体subject可以通过shiro提供的一个工具类SecurityUtils来获取
        //使用SecurityUtils之前要设置Security Manager环境
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();

        //3.主体Subject提交请求给Security Manager -->  subject.login(token);
        //提交请求时需要一个token,所以要先创建token
        UsernamePasswordToken token = new UsernamePasswordToken("wxc","123456");
        subject.login(token);

        //4. shiro提供了一个检查主体subject是否认证的方法isAuthenticated(),此方法的返回结果是一个boolean值
        System.out.println(subject.isAuthenticated());
		
		//5.注销
        subject.logout();
        System.out.println(subject.isAuthenticated());
        
    }
}

执行结果:
在这里插入图片描述

六、Shiro的授权

① 创建Security Manager

② 主体subject授权

③ 主体授权是交给Security Manager授权

④ Security Manager调用授权器Authorizer授权

⑤ 通过Realm在数据库或者缓存中来获取授权的数据(角色数据和权限数据)

package com.shiroDemo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;

/**
 * @program: shiro-demo
 * @description: shiro权限测试类
 * @author: Mr.Wang
 * @create: 2021-11-05 09:42
 **/
public class AuthenticationTest {

    //除了SimpleAccountRealm还有JdbcRealm等
    SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();

    //在认证之前先在Realm中添加一个用户,创建Security Manager的时候要用到Realm
    @Before
    public void addUser(){
        //shiro的授权 user,user1都是角色,这里可以自定义多个角色
        simpleAccountRealm.addAccount("wxc","123456","admin","user","user1");
    }

    @Test//Shiro的授权
    public void test3(){
        //1.构建Security Manager环境(Security Manager是用来提供安全服务的,所以在做shiro认证的时候要先创建此对象,创建Security Manager对象之后要设置Realm)
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(simpleAccountRealm);
        //2.获取向Security Manager提交请求的subject,而主体subject可以通过shiro提供的一个工具类SecurityUtils来获取
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        //3.主体Subject提交请求给Security Manager -->  subject.login(token);
        UsernamePasswordToken token = new UsernamePasswordToken("wxc","123456");
        subject.login(token);
        //4. shiro提供了一个检查主体subject是否认证的方法isAuthenticated(),此方法的返回结果是一个boolean值
        System.out.println(subject.isAuthenticated());
        //校验角色
        subject.checkRoles("user1");
    }

}

执行结果:
在这里插入图片描述

七、Shiro常用的Realm

**1、**内置Realm,“IniRealm"在项目中新建一个ini文件,下面的内容的意思是,新建了一个用户,账号是xiehuaxin,密码为123456,此账号的角色为admin,而admin角色又具有删除用户和更新用户的权限(多个权限中间用逗号分隔),注意这里的“user:delete”不是一定要这样写的,只是一个字符串,你也可以写成"admin=shanchuyonghu”,这要在校验的时候也用“shanchuyonghu”来匹配就行了,当然这种命名习惯还是不建议的,建议使用“user:delete”这种对象+动作的命名方式。
在这里插入图片描述
shiro.ini文件文字可自定义,路径也可以放在自己喜欢的路径下,这里做测试我放在resources下。
文件内容:
在这里插入图片描述

package com.shiroDemo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;


/**
 * @program: shiro-demo
 * @description: Shiro内置Realm
 * @author: Mr.Wang
 * @create: 2021-11-05 10:46
 **/
public class IniRealmTest {

    @Test
    public void test(){
    	//这里设置.ini文件的路径
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        //1.构建Security Manager环境(Security Manager是用来提供安全服务的,所以在做shiro认证的时候要先创建此对象,创建Security Manager对象之后要设置Realm)
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(iniRealm);
        //2.获取向Security Manager提交请求的subject,而主体subject可以通过shiro提供的一个工具类SecurityUtils来获取 SecurityUtils.setSecurityManager(defaultSecurityManager);//使用SecurityUtils之前要设置Security Manager环境 Subject subject = SecurityUtils.getSubject(); //3.主体Subject提交请求给Security Manager --> subject.login(token); UsernamePasswordToken token = new UsernamePasswordToken("xiehuaxin","123456");//提交请求时需要一个token,所以要先创建token subject.login(token); //4. shiro提供了一个检查主体subject是否认证的方法isAuthenticated(),此方法的返回结果是一个boolean值 System.out.println(subject.isAuthenticated());
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        //3.生产token
        UsernamePasswordToken token = new UsernamePasswordToken("root","123456");
        //4.登录
        subject.login(token);
        //判断是否登录认证
        System.out.println(subject.isAuthenticated());
        //5.校验角色
        subject.checkRoles("user");
        //6.校验权限
        subject.checkPermission("user:add");
    }

}

执行结果:
在这里插入图片描述
2、JdbcRealm
1、引入数据库依赖

	<!-- 引入驱动包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>
        <!--引入数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.4</version>
        </dependency>

2、创建数据库及相关表(Mysql)

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for role_permission
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `permission` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of role_permission
-- ----------------------------
INSERT INTO `role_permission` VALUES (1, 'admin', 'admin:add');
INSERT INTO `role_permission` VALUES (2, 'admin', 'admin:delete');
INSERT INTO `role_permission` VALUES (3, 'user', 'user:add');
INSERT INTO `role_permission` VALUES (4, 'user', 'user:delete');

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'wxc', '123456');

-- ----------------------------
-- Table structure for user_roles
-- ----------------------------
DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user_roles
-- ----------------------------
INSERT INTO `user_roles` VALUES (1, 'wxc', 'admin');
INSERT INTO `user_roles` VALUES (2, 'wxc', 'user');

SET FOREIGN_KEY_CHECKS = 1;

测试:

package com.shiroDemo;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

/**
 * @program: shiro-demo
 * @description: JdbcRealm测试
 * @author: Mr.Wang
 * @create: 2021-11-05 11:27
 **/
public class JdbcRealmTest {

    DruidDataSource dataSource = new DruidDataSource();

    {//设置数据源
        dataSource.setUrl("jdbc:mysql:///test?useSSL=false");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
    }

    @Test
    public void test(){
        //1.创建jdbcReaml对象
        JdbcRealm jdbcRealm = new JdbcRealm();

        //2.设置数据源
        jdbcRealm.setDataSource(dataSource);

        //这里需要注意的是,在使用JdbcRealm的时候要设置权限的开关,只有设置为true时才会去查询权限数据
        jdbcRealm.setPermissionsLookupEnabled(true);

        //设置认证查询
        String sql = "select password from user where username = ?";
        jdbcRealm.setAuthenticationQuery(sql);

        //设置角色查询
        String roleSql = "select role_name from user_roles where username = ?";
        jdbcRealm.setUserRolesQuery(roleSql);

        //设置权限查询
        String perSql = "select permission from role_permission where role_name = ?";
        jdbcRealm.setPermissionsQuery(perSql);

        //构建Security Manager环境(Security Manager是用来提供安全服务的,所以在做shiro认证的时候要先创建此对象,创建Security Manager对象之后要设置Realm)
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(jdbcRealm);

        //获取向Security Manager提交请求的subject,而主体subject可以通过shiro提供的一个工具类SecurityUtils来获取
        SecurityUtils.setSecurityManager(defaultSecurityManager);//使用SecurityUtils之前要设置Security Manager环境
        Subject subject = SecurityUtils.getSubject();

        //主体Subject提交请求给Security Manager --> subject.login(token);
        UsernamePasswordToken token = new UsernamePasswordToken("wxc","123456");//提交请求时需要一个token,所以要先创建token
        subject.login(token);
        
        //shiro提供了一个检查主体subject是否认证的方法isAuthenticated(),此方法的返回结果是一个boolean值
        System.out.println(subject.isAuthenticated());
        subject.checkRoles("admin","user");
    }


}

执行结果:
在这里插入图片描述

在使用JdbcRealm时,如果没有设置查询语句,JdbcReal有自己默认的查询语句。

八、自定义Realm

通过查看JdbcRealm或者IniRealm的源码可以发现,它们都继承自AuthorizingRealm,所以要自定义Realm也要使自定义的Realm继承AuthorizingRealm.

package com.shiroDemo;

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.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @program: shiro-demo
 * @description: 自定义Realm
 * @author: Mr.Wang
 * @create: 2021-11-08 10:25
 **/
public class CustomRealm extends AuthorizingRealm {

    Map<String,String> userMap = new HashMap<String, String>();
    {
        userMap.put("wxc","123456");
        super.setName("customRealm");//自定义
    }

    /**
     * 用来做授权(就是checkRole,checkPermission时用到的)
     * @param principals
     * @return
     */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("自定义授权方法");
        //1、现获取用户名
        String userName = (String)principals.getPrimaryPrincipal();

        //2、从数据库或者缓存中获取角色授权
        Set<String> roleSet = getRolesByUserName(userName);

        //3、从数据库或者缓存中获取权限数据
        Set<String> perSet = getPermissionsByUserName(userName);
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setStringPermissions(perSet);
        simpleAuthorizationInfo.setRoles(roleSet);
        return simpleAuthorizationInfo;
    }

    /**
     * 从数据库或缓存中获取权限数据(这里模拟数据库查询)
     * @param userName
     * @return
     */
    private Set<String> getPermissionsByUserName(String userName) {
        Set<String> perSet = new HashSet<String>();
        perSet.add("user:add");
        perSet.add("user:delete");
        return perSet;
    }

    /**
     * 通过用户名获取到角色数据(这里为了简单点就不真的去查询数据库了,仅模拟数据库查询)
     * @param userName
     * @return
     */
    private Set<String> getRolesByUserName(String userName) {
        Set<String> roleSet = new HashSet<String>();
        roleSet.add("admin");
        roleSet.add("user");
        return roleSet;
    }

    /**
     * 用来做认证(就是login时用到的)
     * @param token           主体subject传过来的验证信息
     * @return
     * @throws AuthenticationException
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("自定义认证方法");
        //1.先通过主体传过来的验证信息获取用户名
        String userName = (String)token.getPrincipal();

        //2.通过用户名去数据库中获取凭证
        String password = getPasswordByUserName(userName);
        if(password == null){
            return null;
        }

        //查询到用户,则返回AuthenticationInfo对象
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName,password,"customRealm");
        return simpleAuthenticationInfo;
    }

    /**
     * 通过userName查询对应用户密码(这里直接通过Map获取)
     * @param userName
     * @return
     */
    private String getPasswordByUserName(String userName) {
        return userMap.get(userName);
    }
}

测试自定义Realm

package com.shiroDemo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

/**
 * @program: shiro-demo
 * @description: 测试自定义Realm
 * @author: Mr.Wang
 * @create: 2021-11-08 10:57
 **/
public class CustomRealmTest {

    @Test
    public void test1(){//自定义Realm测试
        CustomRealm customRealm = new CustomRealm();
        //1.构建Security Manager环境(Security Manager是用来提供安全服务的,所以在做shiro认证的时候要先创建此对象,创建Security Manager对象之后要设置Realm)
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(customRealm);

        //2.获取向Security Manager提交请求的subject,而主体subject可以通过shiro提供的一个工具类SecurityUtils来获取
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();

        //3.主体Subject提交请求给Security Manager -->  subject.login(token);
        UsernamePasswordToken token = new UsernamePasswordToken("wxc","123456");
        subject.login(token);

        //4. shiro提供了一个检查主体subject是否认证的方法isAuthenticated(),此方法的返回结果是一个boolean值
        System.out.println(subject.isAuthenticated());
        subject.checkRoles("admin");
        subject.checkPermission("user:delete");
    }
    
 }

执行结果:
在这里插入图片描述

九、Shiro的加密

1、md5加密

package com.shiroDemo;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

/**
 * @program: shiro-demo
 * @description: 测试自定义Realm
 * @author: Mr.Wang
 * @create: 2021-11-08 10:57
 **/
public class CustomRealmTest {

    @Test
    public void test2(){//shiro加密测试
        CustomRealm customRealm = new CustomRealm();

        //1.构建Security Manager环境(Security Manager是用来提供安全服务的,所以在做shiro认证的时候要先创建此对象,创建Security Manager对象之后要设置Realm)
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(customRealm);

        //md5加密测试
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");//设置加密算法名称
        matcher.setHashIterations(1);//设置加密次数
        customRealm.setCredentialsMatcher(matcher);

        //2.获取向Security Manager提交请求的subject,而主体subject可以通过shiro提供的一个工具类SecurityUtils来获取
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();

        //3.主体Subject提交请求给Security Manager -->  subject.login(token);
        UsernamePasswordToken token = new UsernamePasswordToken("wxc","123456");
        subject.login(token);

        //4. shiro提供了一个检查主体subject是否认证的方法isAuthenticated(),此方法的返回结果是一个boolean值
        System.out.println(subject.isAuthenticated());
        subject.checkRoles("admin");
        subject.checkPermission("user:delete");
    }

    @Test
    public void test3(){//因为正常情况,我们设置了加密,数据也是被加密过的,前面自定义的map数据是没有加密的这路输入密码获取加密后的密码去替换map的数据
        Md5Hash md5Hash = new Md5Hash("123456");
        System.out.println(md5Hash.toString());
    }

}

因为正常情况,我们设置了加密,数据也是被加密过的,前面自定义的map数据是没有加密的这里输入密码获取加密后的密码去替换map的数据
在这里插入图片描述
在这里插入图片描述
替换后执行测试代码:

@Test
    public void test2(){//shiro加密测试
        CustomRealm customRealm = new CustomRealm();

        //1.构建Security Manager环境(Security Manager是用来提供安全服务的,所以在做shiro认证的时候要先创建此对象,创建Security Manager对象之后要设置Realm)
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(customRealm);

        //md5加密测试
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");//设置加密算法名称
        matcher.setHashIterations(1);//设置加密次数
        customRealm.setCredentialsMatcher(matcher);

        //2.获取向Security Manager提交请求的subject,而主体subject可以通过shiro提供的一个工具类SecurityUtils来获取
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();

        //3.主体Subject提交请求给Security Manager -->  subject.login(token);
        UsernamePasswordToken token = new UsernamePasswordToken("wxc","123456");
        subject.login(token);

        //4. shiro提供了一个检查主体subject是否认证的方法isAuthenticated(),此方法的返回结果是一个boolean值
        System.out.println(subject.isAuthenticated());
        subject.checkRoles("admin");
        subject.checkPermission("user:delete");
    }

执行结果:
在这里插入图片描述

2、盐值加密
盐值加密和md5加密很相似:
先获取盐值加密后的密码,这里"123"表示盐值是我随便写的,在实际项目中可以使用对象的id(userid)来做盐值进行生成

 @Test
    public void test3(){
      	Md5Hash md5Hash = new Md5Hash("123456","123");
        System.out.println(md5Hash.toString());
    }

执行后复制加密后的密码替换map集合的密码:
在这里插入图片描述
替换之后,在我们自定义Realm中添加一句代码:
simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(“123”));
123是盐值

/**
     * 用来做认证(就是login时用到的)
     * @param token           主体subject传过来的验证信息
     * @return
     * @throws AuthenticationException
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("自定义认证方法");
        //1.先通过主体传过来的验证信息获取用户名
        String userName = (String)token.getPrincipal();

        //2.通过用户名去数据库中获取凭证
        String password = getPasswordByUserName(userName);
        if(password == null){
            return null;
        }

        //查询到用户,则返回AuthenticationInfo对象
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName,password,"customRealm");
        simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("123"));
        return simpleAuthenticationInfo;
    }

执行结果:
在这里插入图片描述
shiro的基础内容大致学习完毕,如想学习更深层的知识点可以看些shiro底层视频讲解!谢谢观看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习Shiro框架可以按照以下步骤进行: 1. 了解基础概念:首先,你需要了解Shiro的基本概念和术语,例如主体(Subject)、认证(Authentication)、授权(Authorization)、Realm等。可以阅读Shiro的官方文档或者相关的教程来获得这些知识。 2. 安装和配置:安装Shiro框架并进行基本的配置。你可以在Shiro的官方网站上找到安装指南和配置示例。 3. 认证功能:学习如何使用Shiro进行用户认证,包括用户名密码认证、Remember Me功能、多Realm认证等。可以尝试编写简单的认证示例来理解这些功能。 4. 授权功能:学习如何使用Shiro进行用户授权,包括角色授权和权限授权。了解如何定义角色和权限,并且如何在代码中进行授权判断。 5. Session管理:了解Shiro如何管理用户的会话信息,包括会话超时、会话验证等。学习如何使用Shiro提供的Session API来管理会话。 6. 整合框架:如果你使用其他的Java框架,例如Spring或者Spring Boot学习如何将Shiro与这些框架进行整合,以便更好地利用Shiro的功能。 7. 安全性优化:深入了解Shiro安全性能优化技巧,例如密码加密、安全配置、防止常见安全漏洞等。 8. 实战练习:通过编写实际的应用程序来巩固所学的知识。可以尝试开发一个简单的Web应用程序,使用Shiro进行用户认证和授权。 除了官方文档和教程,还可以参考一些优秀的书籍或在线教程,例如《Apache Shiro官方指南》、《深入浅出Shiro安全框架》等。此外,加入Shiro的社区或者论坛,与其他开发者交流经验也是一个很好的学习方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值