- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章spring-shiro权限控制realm实战教程由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
Role.java 。
1
2
3
4
5
6
7
8
9
|
@Data
@Entity
public
class
Role {
@Id
@GeneratedValue
private
Integer id;
private
Long userId;
private
String role;
}
|
User.java 。
1
2
3
4
5
6
7
8
9
|
@Data
@Entity
public
class
User {
@Id
@GeneratedValue
private
Long id;
private
String username;
private
String password;
}
|
首先建立 Realm 类,继承自 AuthorizingRealm,自定义我们自己的授权和认证的方法。Realm 是可以访问特定于应用程序的安全性数据(如用户,角色和权限)的组件.
Realm.java 。
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
|
public
class
Realm
extends
AuthorizingRealm {
@Autowired
private
UserService userService;
//授权
@Override
protected
AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//从凭证中获得用户名
String username = (String) SecurityUtils.getSubject().getPrincipal();
//根据用户名查询用户对象
User user = userService.getUserByUserName(username);
//查询用户拥有的角色
List<Role> list = roleService.findByUserId(user.getId());
SimpleAuthorizationInfo info =
new
SimpleAuthorizationInfo();
for
(Role role : list) {
//赋予用户角色
info.addStringPermission(role.getRole());
}
return
info;
}
//认证
@Override
protected
AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws
AuthenticationException {
//获得当前用户的用户名
String username = (String) authenticationToken.getPrincipal();
//从数据库中根据用户名查找用户
User user = userService.getUserByUserName(username);
if
(userService.getUserByUserName(username) ==
null
) {
throw
new
UnknownAccountException(
"没有在本系统中找到对应的用户信息。"
);
}
SimpleAuthenticationInfo info =
new
SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),getName());
return
info;
}
}
|
ShiroConfig.java 。
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
|
@Configuration
public
class
ShiroConfig {
@Bean
public
ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean =
new
ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap =
new
LinkedHashMap<String, String>();
//以下是过滤链,按顺序过滤,所以/**需要放最后
//开放的静态资源
filterChainDefinitionMap.put(
"/favicon.ico"
,
"anon"
);
//网站图标
filterChainDefinitionMap.put(
"/**"
,
"authc"
);
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return
shiroFilterFactoryBean;
}
@Bean
public
DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager defaultWebSecurityManager =
new
DefaultWebSecurityManager(myRealm());
return
defaultWebSecurityManager;
}
@Bean
public
MyRealm myRealm() {
MyRealm myRealm =
new
MyRealm();
return
myRealm;
}
}
|
UserController.java 。
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
|
@Controller
public
class
UserController {
@Autowired
private
UserService userService;
@GetMapping
(
"/"
)
public
String index() {
return
"index"
;
}
@GetMapping
(
"/login"
)
public
String toLogin() {
return
"login"
;
}
@GetMapping
(
"/admin"
)
public
String admin() {
return
"admin"
;
}
@PostMapping
(
"/login"
)
public
String doLogin(String username, String password) {
UsernamePasswordToken token =
new
UsernamePasswordToken(username, password);
Subject subject = SecurityUtils.getSubject();
try
{
subject.login(token);
}
catch
(Exception e) {
e.printStackTrace();
}
return
"redirect:admin"
;
}
@GetMapping
(
"/home"
)
public
String home() {
Subject subject = SecurityUtils.getSubject();
try
{
subject.checkPermission(
"admin"
);
}
catch
(UnauthorizedException exception) {
System.out.println(
"没有足够的权限"
);
}
return
"home"
;
}
@GetMapping
(
"/logout"
)
public
String logout() {
return
"index"
;
}
}
|
UserService.java 。
1
2
3
4
5
6
7
8
9
10
11
12
|
@Service
public
class
UserService {
@Autowired
private
UserDao userDao;
public
User getUserByUserName(String username) {
return
userDao.findByUsername(username);
}
@RequiresRoles
(
"admin"
)
public
void
send() {
System.out.println(
"我现在拥有角色admin,可以执行本条语句"
);
}
}
|
-项目中使用shiro做登录校验和权限管理,在配置权限时遇到小坑,记录一下.
权限标签定义如下:
标签定义 | 页面一 | 页面二 |
---|---|---|
第一层级 | one:view | two:view |
第二层级 | one:page1:view | two:page2:view |
第三层级 | one:page1:view:add | two:page2:view:add |
开始怀疑是数据库没有录入,查看后权限标签与角色已对应,排除.
后面怀疑是页面问题,后面把第三层级标签与第一二层级同一页面,依然不起作用,排除.
后面怀疑是权限标签定义问题,把第三层级标签改为one:page1:data:add,奇迹出现,权限生效。证实权限标签定义出了问题.
但是后来想想为什么会出现这种问题,每个标签都是独一无二的,对此我对shiro对于权限标签的校验产生了兴趣,查看源码,一路debug后最终在org.apache.shiro.authz.permission中看到了关键所在,核心代码如下 。
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
|
//当这个方法返回true时说明有此权限
//这个p是代表当前循环匹配到的权限标签
public
boolean
implies(Permission p) {
// By default only supports comparisons with other WildcardPermissions
if
(!(p
instanceof
WildcardPermission)) {
return
false
;
}
WildcardPermission wp = (WildcardPermission) p;
//把当前标签转分割成一个set集合(如one:page1:view:add 会分割成[[one], [page1], [view], [add]])
List<Set<String>> otherParts = wp.getParts();
int
i =
0
;
//循环匹配权限标签
for
(Set<String> otherPart : otherParts) {
// If this permission has less parts than the other permission, everything after the number of parts contained
// in this permission is automatically implied, so return true
//当全部循环匹配完没有返回false,则返回true,这个getparts()方法是获取当前角色当前循环的权限标签([[one], [page1], [view]])
if
(getParts().size() -
1
< i) {
return
true
;
}
else
{
Set<String> part = getParts().get(i);
/*如果包含有‘*'而且不包含当前分割后的标签则返回
false
,
*当用户可以查看页面,也就是说当前角色拥有one:page1:view标签
*这里【!part.contains(WILDCARD_TOKEN)】返回
true
,第二个【part.containsAll(otherPart)】one会跟当前标签匹**配one,
*也就是说这里全部循环完返回的都是
false
,所以最后都没
true
,于是在上面返回了一个
true
。
if
(!part.contains(WILDCARD_TOKEN) && !part.containsAll(otherPart)) {
return
false
;
}
i++;
}
}
|
小结一下:通过分析,我们看到了shiro在定义权限标签时,要主意匹配问题,不要存在包含问题,类似aaa 和aaab ,会导致后面标签失效.
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我.
原文链接:https://zhengkai.blog.csdn.net/article/details/80153421 。
最后此篇关于spring-shiro权限控制realm实战教程的文章就讲到这里了,如果你想了解更多关于spring-shiro权限控制realm实战教程的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
大家好,我完成了这个基本的 C 程序,它向输入任何给定数字集的用户显示有序集、最小值、最大值、平均值和中值。我遇到的问题是,当我打印数字时,我必须使用诸如“3.2%f”之类的东西来设置标准的精度,我怎
我有这个基于 Python 的服务守护进程,它正在执行大量多路复用 IO(选择)。 从另一个脚本(也是 Python)我想查询这个服务守护进程的状态/信息和/或控制处理(例如暂停它、关闭它、更改一些参
我读到 Fortran 对表达式求值的顺序有严格的规则。对于某些数值算法来说,这一点非常重要。 数值 C 程序如何控制浮点运算的顺序并防止编译器“优化”到不需要的运算顺序,例如将 (a*b)*c 更改
上下文: 整个问题可以概括为我正在尝试复制调用system(或fork)的行为,但在 mpi 环境中。 (事实证明,你不能并行调用system。)这意味着我有一个程序在许多节点上运行,每个节点上有一个
我考虑过控制scanf来接受c中的任何输入。我的概念是等待10秒(或任何其他时间)来接受任何输入。10秒后它将退出并且不再接收任何输入。 int main(){ int a,b,c,d; sca
我正在尝试使用生成器停止 setTimeOut 上的执行流程。我究竟做错了什么?我无法让 console.log 每 1500 毫秒退出一次。我是 node 的新手,如果我在做一件非常愚蠢的事情,请不
我希望我的应用程序的 Activity 堆栈包含同一 Activity 的多个实例,每个实例处理不同的数据。因此,我将让 Activity A 在我的 Activity 堆栈中处理数据 a、b、c 和
我有这个 bash 文件,它向设备询问 OpenSSH 的 IP、密码等。 现在,如果我使用 ssh root@ip,我必须输入密码。这真的很烦人。第二;我不能让我的脚本向它发送命令。 这就是我想要的
我正在尝试测试我有权访问的机器的缓存属性。为此,我正在尝试读取内存并对其计时。我改变工作集大小和步幅访问模式以获得不同的测量值。 代码如下所示: clock1 = get_ticks() for (i
我正在尝试编写一个 makefile 来替换用于构建相当大的应用程序的脚本之一。 当前脚本一次编译一个文件,使用 make 的主要原因是并行化构建过程。使用 make -j 16 我目前在办公室服务器
我正在制作一个小的测试程序,它演示了一个粗糙的控制台界面。 该程序是一个低于标准的典型获取行、响应程序,它甚至不识别“退出”,并希望您通过按 control-c 强制退出。在 Mingw32 上完成。
好的,我有一个 VOIP 电话。我知道电话的 IP 地址和端口,并且可以完全访问电话,我正在使用它通过 SIP 中继调用 SIP 电话。 我基本上想随时查看手机上发生的事情,但我不知道从哪里开始。 如
是否可以指定 CWinApp::WriteProfileString() 使用的应用程序名称? 如果我使用 CWinApp::SetRegistryKey 将我的公司名称设置为“MyCompany”,
我正在尝试用 Python 控制 Tor。我在 stackoverflow 上阅读了其他几个关于这个主题的问题,但没有一个能回答这个问题。 我正在寻找一种方法,以便在命令运行时为您提供“新身份”、新
最近在做一个项目,涉及到iPhone设备和手表传输数据、控制彼此界面跳转,在网上找了很多资料,发现国内的网站这方面介绍的不多,而国外的网站写的也不是很全,所以在这写这篇文章,给大家参考一下,望大神指
我想增加图中值的范围。在示例中,值的范围从 50 到 200。但是,我需要按如下方式分配值:50 75 100 125 150 175 200 并且最好使用 scale_fill_gradientn
我有一个IconButton,当按下时波纹效果是圆形的并且比按钮的面积大,我怎样才能减少点击按钮时波纹效果的大小? IconButton( constraints
我正在使用代码契约(Contract)为我的项目生成附属程序集。基本上它为项目的 MyAssembly.dll 创建一个 MyAssembly.Contracts.dll。这应该放在你的程序集旁边,但
我想使用分面绘制图形,其中面板之间的边缘不同。面板按字母顺序自动排序(按照 ggplot 中的惯例)。一个简单的例子: library(igraph) library(ggraph) g <- mak
我想为我的 Android 应用程序创建一个小部件,以显示有关位置的一些实时详细信息,例如天气。但我想在任何时候允许最多 3 个小部件实例,每个实例都有不同的位置。我不确定该怎么做,也找不到任何信息。
我是一名优秀的程序员,十分优秀!