banner
NEWS LETTER

Shiro整合redis完成登陆鉴权与缓存功能

Scroll down

首先引入相关依赖:
shiro-redis-spring-boot-starter在maven仓库里搜不到,自己复制引入就好。我记得是整合的部分其他依赖(比如spring-boot-starter)然后外加上大佬制作的shiro-redis依赖,可以引入后自己看一下具体依赖,然后移除之前引入的重复依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--shiro-redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis-spring-boot-starter</artifactId>
<version>3.2.1</version>
</dependency>

相关配置:
包括开启缓存,redis相关配置,缓存前缀等

1
2
3
4
5
6
7
8
9
10
shiro-redis:
enabled: true
redis-manager:
host: 127.0.0.1:6379
password:
cache-manager:
key-prefix: "shiro:cache:"
expire: 600 # 单位:秒
session-dao:
key-prefix: "shiro:session:"

自定义realm:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Component
public class MyRealm extends AuthorizingRealm {

//引入userService去数据库中查询用户、角色、权限信息
@Autowired
private UserService userService;

//自定义授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取用户名
User principal = (User) principalCollection.getPrimaryPrincipal();
//获取用户角色信息
List<String> userRoles= userService.getUserRoles(principal.getUsername());
//获取角色权限信息
List<String> userPermissions = userService.getUserPermissions(userRoles);
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addRoles(userRoles);
info.addStringPermissions(userPermissions);
return info;
}

//自定义登录
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取用户名
String userName = authenticationToken.getPrincipal().toString();
//数据库查询用户信息
User userByName = userService.getUserByName(userName);
if(userByName.getStatus()==1) {//用户状态为1则表示封禁状态
throw new LockedAccountException();
}
//判断不为空则封装返回
if(userByName!=null){
AuthenticationInfo info = new SimpleAuthenticationInfo(
userByName,
userByName.getPassword(),
//数据加盐
ByteSource.Util.bytes("yahoo"),
userName
);
return info;
}
return null;
}
}

配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
@Configuration
public class ShiroConfig {
//自定义realm
@Autowired
private MyRealm myRealm;

//shiro-redis提供的
@Autowired
private RedisSessionDAO redisSessionDAO;

//shiro-redis提供的
@Autowired
private RedisCacheManager redisCacheManager;

@Bean
public DefaultWebSecurityManager defaultWebSecurityManager() {
//1创建DefaultWebSecurityManager对象
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//2创建加密对象,设置属性
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//2.1使用md5加密
matcher.setHashAlgorithmName("md5");
//2.2迭代加密次数
matcher.setHashIterations(3);
//3加密对象存储到myRealm
myRealm.setCredentialsMatcher(matcher);
//4myRealm存入DefaultWebSecurityManager中
defaultWebSecurityManager.setRealm(myRealm);
//5设置rememberMe
defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
//6设置缓存
defaultWebSecurityManager.setCacheManager(redisCacheManager);
defaultWebSecurityManager.setSessionManager(sessionManager());
//返回
return defaultWebSecurityManager;
}

//配置sessionManager
@Bean(name = "sessionManager")
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
// 设置session过期时间(10分钟)。单位:ms,默认为30分钟。
sessionManager.setGlobalSessionTimeout(600000L);
sessionManager.setSessionDAO(redisSessionDAO);
return sessionManager;
}

//配置rememberMemanag和cookie
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
cookieRememberMeManager.setCipherKey("1234567890987654".getBytes());
return cookieRememberMeManager;
}
public SimpleCookie rememberMeCookie() {
SimpleCookie cookie = new SimpleCookie("rememberMe");
//设置跨域
//cookie.setDomain(domain);
cookie.setPath("/");
cookie.setHttpOnly(true);
cookie.setMaxAge(30 * 24 * 60 * 60);
return cookie;
}

//配置shiro内置拦截范围(自己根据需要配置)
@Bean("shiroFilterFactoryBean")
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//给ShiroFilter配置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//配置系统受限资源
//配置系统公共资源
Map<String, String> urlMap = new LinkedHashMap<>();
//map.put("/","authc");//表示这个资源需要认证和授权
urlMap.put("/user/login", "anon");//表示不需要认证

shiroFilterFactoryBean.setLoginUrl("/user/login");

shiroFilterFactoryBean.setFilterChainDefinitionMap(urlMap);
return shiroFilterFactoryBean;
}

//引入shiro-redis依赖后在有自定义realm的情况下启动项目会报错
//解决shiro-redis包与自定义realm冲突
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
Map<String, String> filterMap = new LinkedHashMap<>();
chainDefinition.addPathDefinitions(filterMap);
return chainDefinition;
}
@Bean
public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {

DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setUsePrefix(true);

return defaultAdvisorAutoProxyCreator;
}
}

Controller相关示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@PostMapping("/login")
public R<String> userLogin(User userInWeb, @RequestParam(defaultValue = "false") boolean rememberMe){
//1获取subject对象
Subject subject= SecurityUtils.getSubject();
//2封装token
AuthenticationToken token=new UsernamePasswordToken(userInWeb.getUsername(),userInWeb.getPassword(),rememberMe);
//3调用login
try {
subject.login(token);
return R.success("登录成功");
} catch (UnknownAccountException e) {//UnknownAccountException用户不存在
e.printStackTrace();
return R.error("用户不存在");
}catch (IncorrectCredentialsException e){//IncorrectCredentialsException密码错误
e.printStackTrace();
return R.error("密码错误");
}catch (LockedAccountException e){//LockedAccountException账号被封
e.printStackTrace();
return R.error("账户被封禁");
} catch (Exception e){//其他异常
e.printStackTrace();
return R.error("程序异常");
}
}

//有关权限或是否登录的方法可以在方法前使用注解
//@RequiresRoles("admin")
//@RequiresPermissions("admin:edit")
//根据需要添加相关注解
//public R<String> test(){...}
其他文章