下面我将为你详细讲解“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
其中,hashAlgorithmName
和 hashIterations
是用来加密密码的,这里以 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
的用户,在该账户下分配两个角色 admin
和 user
,每个角色各有两个权限 user:add
、user: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
整合 Shiro
和 Redis
的完整攻略。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot整合Shiro和Redis的示例代码 - Python技术站