SpringBoot整合Shiro和Redis的示例代码

下面我将为你详细讲解“SpringBoot整合Shiro和Redis的示例代码”的具体过程,包含示例代码说明。

一、引入相关依赖

首先需要在 pom.xml 文件中引入相关依赖,包括 SpringBoot、Shiro 和 Redis 的依赖,示例代码如下:

<dependencies>
    <!-- SpringBoot 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>

    <!-- Shiro 依赖 -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring-boot-starter</artifactId>
        <version>1.6.0</version>
    </dependency>

    <!-- Redis 客户端依赖 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.8.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.8.0</version>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.2.0</version>
    </dependency>
</dependencies>

二、配置 Shiro

application.yml(或 application.properties) 文件中配置 Shiro 的相关信息,示例代码如下:

shiro:
  hashAlgorithmName: md5 # 修改 hash 算法,默认是 sha-256
  hashIterations: 2 # 修改 hash 迭代次数
  redis:
    host: localhost
    port: 6379
    timeout: 10000
    password: XXXXXX
    database: 0

其中,hashAlgorithmNamehashIterations 是用来加密密码的,这里以 md5 和 2 为例。

三、编写 Shiro 自定义 Realm

需要自定义一个 Realm 来将 Shiro 和 Redis 集成起来。示例代码如下:

public class CustomRealm extends AuthorizingRealm {

    private RedisManager redisManager;

    public void setRedisManager(RedisManager redisManager) {
        this.redisManager = redisManager;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(redisManager.getRoles(username));
        authorizationInfo.setStringPermissions(redisManager.getPermissions(username));
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        String password = new String((char[]) token.getCredentials());
        String dbPassword = redisManager.getPassword(username);
        if (dbPassword == null || !dbPassword.equals(password)) {
            throw new IncorrectCredentialsException("用户名或密码错误!");
        }
        return new SimpleAuthenticationInfo(username, password, getName());
    }
}

四、编写 RedisManager

RedisManager 是用来访问 Redis 缓存的,示例代码如下:

public class RedisManager {

    private JedisPool jedisPool;

    public RedisManager(String host, int port, int timeout, String password, int database) {
        jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout, password, database);
    }

    public Jedis getJedis() {
        return jedisPool.getResource();
    }

    public String getPassword(String username) {
        try (Jedis jedis = getJedis()) {
            return jedis.hget("user:" + username, "password");
        }
    }

    public Set<String> getRoles(String username) {
        try (Jedis jedis = getJedis()) {
            return jedis.smembers("user:" + username + ":roles");
        }
    }

    public Set<String> getPermissions(String username) {
        try (Jedis jedis = getJedis()) {
            return jedis.smembers("user:" + username + ":permissions");
        }
    }
}

五、集成 Shiro 和 Redis

这里使用 Shiro 和 Redis 的集成插件 ShiroRedisCacheManager

@Configuration
public class ShiroConfig {

    @Bean
    public CustomRealm customRealm() {
        CustomRealm customRealm = new CustomRealm();
        customRealm.setCachingEnabled(true);
        customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        customRealm.setAuthenticationCachingEnabled(true);
        customRealm.setAuthenticationCacheName("authenticationCache");
        customRealm.setAuthorizationCachingEnabled(true);
        customRealm.setAuthorizationCacheName("authorizationCache");
        customRealm.setRedisManager(redisManager());
        return customRealm;
    }

    @Bean
    public RedisManager redisManager() {
        return new RedisManager(
                environment.getProperty("shiro.redis.host"),
                Integer.valueOf(environment.getProperty("shiro.redis.port")),
                Integer.valueOf(environment.getProperty("shiro.redis.timeout")),
                environment.getProperty("shiro.redis.password"),
                Integer.valueOf(environment.getProperty("shiro.redis.database"))
        );
    }

    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName(environment.getProperty("shiro.hashAlgorithmName"));
        matcher.setHashIterations(Integer.valueOf(environment.getProperty("shiro.hashIterations")));
        return matcher;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setSuccessUrl("/index");
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");

        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(customRealm());
        securityManager.setCacheManager(redisCacheManager());
        return securityManager;
    }

    @Bean
    public RedisCacheManager redisCacheManager() {
        RedisCacheManager redisCacheManager = new ShiroRedisCacheManager(redisManager());
        redisCacheManager.setKeyPrefix("shiro:cache:");
        redisCacheManager.setExpire(1800); // 设置缓存过期时间,单位秒,默认1小时
        return redisCacheManager;
    }

}

六、示例说明

示例1:验证用户登录

首先创建一个账号密码为 test/test123 的用户,在该账户下分配两个角色 adminuser,每个角色各有两个权限 user:adduser:delete

在前端页面进行登录操作,后台服务器验证用户名和密码。如果验证成功,CustomRealm#doGetAuthorizationInfo() 方法将被调用,用户的角色和权限将存储在 Redis 中。

@Controller
public class LoginController {

    @RequestMapping("/login")
    public String login(@RequestParam("username") String username,
                        @RequestParam("password") String password,
                        Model model) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token);
            return "redirect:/index";
        } catch (Exception e) {
            model.addAttribute("errorMsg", "用户名或密码错误!");
            return "login";
        }
    }

}

示例2:查询用户权限

在前端页面进行某个操作时会访问后端服务,后端服务需要验证该用户是否有权限进行该操作。由于用户权限已经存储在 Redis 中,直接从 Redis 中获取即可。

@RequestMapping("/operation")
@ResponseBody
public String operation() {
    Subject subject = SecurityUtils.getSubject();
    if (subject == null || !subject.isAuthenticated()) {
        return "用户未登录或登录状态已过期!";
    }
    if (subject.isPermitted("user:add")) {
        return "用户具有添加权限!";
    } else {
        return "用户没有添加权限!";
    }
}

以上便是 SpringBoot 整合 ShiroRedis 的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot整合Shiro和Redis的示例代码 - Python技术站

(0)
上一篇 2023年6月15日
下一篇 2023年6月15日

相关文章

  • Springmvc异常处理器及拦截器实现代码

    当我们在使用SpringMVC框架进行开发的时候,我们希望在程序运行中出现异常的时候能够进行处理,这时候就需要用到SpringMVC的异常处理器和拦截器。下面是实现这两个功能的代码: SpringMVC异常处理器的实现 首先在SpringMVC配置文件中配置SimpleMappingExceptionResolver,它可以捕获所有未处理的异常,并将它们映射…

    Java 2023年5月27日
    00
  • 对ArrayList和LinkedList底层实现原理详解

    对ArrayList和LinkedList底层实现原理详解 ArrayList 简介 ArrayList是基于动态数组实现的,其最大的特点就是可以随机访问,这也是数组的一个最大优点。另外,ArrayList支持在尾部快速添加元素的操作,当然,如果要在中间插入、删除元素,这是需要移动数组元素,所以操作速度会相对比较慢,并且,在ArrayList中,如果进行了大…

    Java 2023年5月26日
    00
  • 详解Spring Boot 定时任务的实现方法

    Spring Boot提供了一种简单的方式来实现定时任务。以下是详解Spring Boot定时任务的实现方法的完整攻略: 添加依赖 在pom.xml文件中添加以下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>sp…

    Java 2023年5月15日
    00
  • Java深入浅出讲解String类常见方法

    Java深入浅出讲解String类常见方法攻略 String概述 在Java中,String是一种基本的数据类型,也是一种常用的数据类型。对于String类型的字符串,Java中提供了很多常见的方法,可以帮助我们对字符串进行各种操作。 String类常见方法 1. length() length()方法返回字符串的长度,即字符串中字符的个数。 示例: Str…

    Java 2023年5月26日
    00
  • 百度UEditor编辑器使用教程与使用方法(图文)

    百度UEditor编辑器使用教程与使用方法(图文) 1. 简介 百度UEditor编辑器是一个轻量、可定制的富文本编辑器,特别适用于网站开发,用于对富文本的输入和输出,如网站后台管理系统和文章编辑器等。本篇文章将用图文的形式详细介绍其使用方法。 2. 安装和使用 2.1 下载 首先,需要从百度UEditor官方网站下载编辑器。我们可以下载源码并自定义配置,也…

    Java 2023年6月15日
    00
  • 详解用java描述矩阵求逆的算法

    详解用Java描述矩阵求逆的算法 算法概述 在线性代数中,矩阵求逆是一个很重要的问题,它在各种科学计算中发挥着关键作用。矩阵求逆也被用于解决多元线性回归等问题。 基本上所有矩阵求逆算法都是基于高斯-约旦变换(Gauss-Jordan elimination)来工作的,该算法旨在通过对原始矩阵进行顺序消元、列缩放和行交换等操作,从而生成一个沿着对角线对称的单位…

    Java 2023年5月19日
    00
  • JavaWeb实现文件上传下载功能实例详解

    针对“JavaWeb实现文件上传下载功能实例详解”的完整攻略,我来为你做一个详细的讲解。 一、文件上传的实现过程 文件上传是指通过网页将文件传输到服务器的操作,它是Web应用程序中常见的功能之一。而JavaWeb开发环境中,要想实现文件上传,需要经过以下几个步骤: 1. 前端表单设计 在前端,我们需要添加一个input标签,并设置其type属性为file,用…

    Java 2023年5月20日
    00
  • Jsp连接Access数据库(不通过建立ODBC数据源的方法)

    JSP连接Access数据库是一种常见的操作,但是通常需要通过建立ODBC数据源这一繁琐步骤。下面,本文将介绍一种不需要建立ODBC数据源的方法。 准备工作 在进行JSP连接Access数据库之前,需要先做一些准备工作: 确保电脑上安装了Java开发环境JDK和Tomcat服务器; 准备一个Access数据库文件,例如database.mdb; 准备两个Ja…

    Java 2023年6月15日
    00
合作推广
合作推广
分享本页
返回顶部