Spring Boot集成shiro步骤

标签: Springboot 分类: Java 创建时间:2019-01-07 01:38:51 更新时间:2024-11-15 10:49:43

这篇文章不是在第一次集成shiro的时候编写的,都是后来回忆的,随着对代码的理解和框架的学习,东西也都慢慢的熟悉了。

参考文章:
1.Shiro拦截AJAX的解决方案
2.Shiro学习笔记(2)——身份验证之Realm
3.使用 Shiro 设计基于用户、角色、权限的通用权限管理系统
4.在 SpringBoot 项目中,Spring Security 和 Shiro 该如何选择? (刚开始我是接触的Shiro,后来也写过Security,确实感觉后者要比较复杂,毕竟我是一个半吊子,所以很长时间都无法理解Security都精神内涵,只是停留在表面功夫,甚至自己都无法将整个流程说的很明白)

1.maven的pom.xml中加入shiro依赖

1
2
3
4
5
6
 <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.5</version>
</dependency>

2.配置数据库

在application.yml中配置数据库连接。

3.添加数据表

用户表、权限表等,根据自己需要。如果不需要很高的要求,可以只有一个用户表,然后只要判断用户用户名密码是否输入正确,就判断其是否有权限进行成功页,等慢慢熟悉之后,再丰富自己的权限设置。可以参考我整理的网上的用户角色和权限数据库设计方案Post not found: Spring Boot用户角色和权限管理 Spring Boot用户角色和权限管理

4.编写页面

登录页、权限页等,根据自己需要。可以只设置一个登录页,然后设置一个登陆成功的页面

5.配置shiro

1)实现一个自己的AuthorizingRealm,重写里面的权限验证doGetAuthorizationInfo和身份验证doGetAuthenticationInfo的方法

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
public class MyShiroRealm extends AuthorizingRealm {
/**
* 认证信息.(身份验证)
* :
* Authentication 是用来验证用户身份
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户的输入的账号.
String username = (String)token.getPrincipal();
//通过username从数据库中查找 User对象,如果找到,没找到.
//实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
UserInfo userInfo = userInfoService.findByUsername(username);

if(userInfo == null){
return null;
}
/*
* 获取权限信息:这里没有进行实现,
* 请自行根据UserInfo,Role,Permission进行实现;
* 获取之后可以在前端for循环显示所有链接;
*/
//userInfo.setPermissions(userService.findPermissions(User));
//加密方式;
//交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
try{
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userInfo.getUsername(), //用户名
userInfo.getPassword(), //密码
getName() //realm name
);
//这里使用的是密码加盐两次md5之后的结果
authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(userInfo.getCredentialsSalt()));
return authenticationInfo;
}catch (Exception e){
System.out.println("授权失败");
logger.error("doGetAuthenticationInfo",userInfo);
return null;
}

//明文: 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
// SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
// userInfo.getName(), //用户名
// userInfo.getPassword(), //密码
// getName() //realm name
// );

}

/**
* 此方法调用 hasRole,hasPermission的时候才会进行回调.
*
* 权限信息.(授权):
* 1、如果用户正常退出,缓存自动清空;
* 2、如果用户非正常退出,缓存自动清空;
* 3、如果我们修改了用户的权限,而用户不退出系统,修改的权限无法立即生效。
* (需要手动编程进行实现;放在service进行调用)
* 在权限修改后调用realm中的方法,realm已经由spring管理,所以从spring中获取realm实例,
* 调用clearCached方法;
* :Authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
/*
* 当没有使用缓存的时候,不断刷新页面的话,这个代码会不断执行,
* 当其实没有必要每次都重新设置权限信息,所以我们需要放到缓存中进行管理;
* 当放到缓存中时,这样的话,doGetAuthorizationInfo就只会执行一次了,
* 缓存过期之后会再次执行。
*/
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
String username=(String)principals.getPrimaryPrincipal();
UserInfo userInfo = userInfoService.findByUsername(username);

//添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色
authorizationInfo.addRole(userInfo.getRoles());

return authorizationInfo;
}
}

2)新建配置类,这里是通过代码进行的权限配置,可以通过配置文件进行文件配置

1
2
3
4
5
6
7
8
9
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
System.out.println("ShiroConfiguration.shirFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//拦截器.
}

说明:这里的shiroFilter、securityManager是必须的,myShiroRealm是自己实现的验证流程,shiroFilter可以使用代码配置,也可以使用从ini文件中读取配置,所有的类配置sessionmanager,cachemanager都以Bean的方式注入到spring boot中,区别与传统的spring的xml配置方式。shirFilter中调用setSecurityManager(),securityManager中注入sesssionManager和realm,以及cacheManager等。

6.实现登录方法

主要代码:

1
2
3
4
5
6
7
8
public void login(){
Subject currentUser = SecurityUtils.getSubject();
// 开始进入shiro的认证流程
// 此方法不处理登录成功,由shiro进行处理.
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
currentUser.login(token);
}

如此调用时,会进入到MyShiroRealm中的doGetAuthenticationInfo进行验证。

7.编写shiro.ini文件

主要是url路由的定义,哪些需要访问权限,哪些不需要访问权限等。

1
2
3
4
5
6
7
8
9
#url=拦截器[参数],拦截器[参数]……
[urls]
/static/** = anon
/assets/** = anon
/pdfjs/** = anon

#先进入authc的拦截器,然后进入自定义的roles拦截器
/**=authc

8.配置SessionManager

小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。