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日

相关文章

  • Java调试器的作用是什么?

    Java调试器是帮助Java程序员识别和纠正程序错误或问题的工具。使用调试器可以单步执行程序,查看代码执行状态和变量的值,并在运行时发现程序错误和异常。 以下是使用Java调试器的步骤: 1. 配置调试器 在使用Java调试器之前,需要将调试器连接到正在运行的Java进程。一般来说,可以使用IDE(集成开发环境)来连接调试器。 以Eclipse为例,可以通过…

    Java 2023年5月11日
    00
  • 一篇文章带你学会css变量(推荐!)

    一篇文章带你学会 CSS 变量 本文将从什么是 CSS 变量开始,逐步介绍 CSS 变量的用法和相关技巧,帮助读者熟练使用 CSS 变量。 什么是 CSS 变量 CSS 变量,又称自定义属性,是一种 CSS 新增的功能,它可以在全局范围内定义一个值,并在后续的 CSS 中引用该值。采用变量的方式可以提高 CSS 的复用性,并且可以更方便地对样式进行全局调整。…

    Java 2023年6月15日
    00
  • java如何使用自己的maven本地仓库详解

    下面是详细的讲解: 一、什么是Maven本地仓库? Maven本地仓库就是Maven自己的仓库,是用于存储Maven项目所需要的jar包、插件和其他依赖的本地仓库。一般情况下,我们使用Maven构建Java项目时会从Maven中央仓库或者私有仓库下载依赖,但是有时候我们需要自己编写的依赖或者其他第三方依赖没有在中央仓库或私有仓库中,那么我们就需要使用自己的本…

    Java 2023年5月20日
    00
  • Java集成测试的作用是什么?

    Java集成测试是指在代码整合完成以后,进行的针对整个软件系统进行的测试过程。该过程旨在验证整个软件系统的稳定性与正确性。Java集成测试的作用主要有以下几个方面: 验证软件系统的各个组件之间的相互作用是否符合预期。 检查集成后系统是否具有预期的性能和可靠性。 探测和解决系统中可能存在的集成问题。 对于Java集成测试,我们可以按照以下步骤进行: 确定集成测…

    Java 2023年5月11日
    00
  • Java 认识异常并掌握使用

    Java 认识异常并掌握使用 什么是异常? 在 Java 基础语法中,当程序执行过程中发生错误或异常时,会抛出异常,异常即指程序在运行过程中遇到的错误或意外情况。Java 中的异常是用于处理程序意外情况的一种机制。 异常的分类 Java 中的异常一般分为两类:可检查异常(checked exception)和不可检查异常(unchecked exceptio…

    Java 2023年5月26日
    00
  • 浅谈ASP数据库下载漏洞

    浅谈ASP数据库下载漏洞攻略 什么是ASP数据库下载漏洞 ASP数据库下载漏洞,是指在ASP网站中由于程序员未对用户输入数据进行合适的验证,导致攻击者利用构造恶意请求下载网站中的数据库文件。攻击者可以通过下载数据库文件获取网站中的敏感数据,如用户信息、密码、订单记录等。 攻击过程 攻击者在ASP网站中使用”download.asp?”的关键字搜索,找到下载文…

    Java 2023年6月16日
    00
  • 详解Java快速上手用户后台管理系统

    详解Java快速上手用户后台管理系统 简介 本文将详细讲解使用Java语言开发基本用户后台管理系统的步骤和注意事项,适合有一定Java基础的开发者学习。 步骤 步骤一:安装开发环境 首先需要安装JDK、IDE和相关依赖库,推荐使用Eclipse、IntelliJ IDEA、NetBeans等常用的开发工具。 步骤二:创建项目 在IDE中创建一个Java We…

    Java 2023年5月23日
    00
  • java获取Date时间的各种方式汇总

    Java获取Date时间的各种方式汇总 Date类作为Java中常用的日期时间操作类,提供了多种获取时间的方式。本文将为大家详细介绍Java中常见的Date时间获取方式,希望对大家有所帮助。 currentTimeMillis() currentTimeMillis()方法返回当前系统时间的毫秒数。可以通过将这个时间链接到Date构造函数中来创建对应的Dat…

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