
Shiro
介绍
- Shiro与SpringSecurity类似;
- Apache Shiro是一个Java的安全(权限)框架;
- Shiro可以完成认证、授权、加密、会话管理、Web集成、缓存等。
subject:应用代码直接交互的对象Subject,即Shiro的对外API核心就是Subject,Subject代表了当前的用户。
SecurityManager:安全管理器,管理所有的Subject,负责与Shiro其他组件交互。
Realm:Shiro从Realm获取安全数据(用户,角色,权限)。SecurityManager要验证用户身份,需要从Realm获取相应的用户进行比较。
第一个Shiro程序
依赖
pom.xml
1 | <dependencies> |
shiro.ini
1 | # ============================================================================= |
主程序
1 | import org.apache.shiro.SecurityUtils; |
运行结果
1 | [main] INFO com.yn.Hello - My First Apache Shiro Application |
Subject对象的方法
在Shiro里,Subject对象用来表示一个用户;
可以使用SecurityUtils.getSubject()方法获得这个对象。
方法
- isAuthenticated():返回boolean,当前用户是否经过验证(登录);
- login(token):登录一个用户,通过try-catch捕获登录错误时的操作
- UnknownAccountException:没有这个用户
- IncorrectCredentialsException:错误的密码
- LockedAccountException:锁定的账户
- getSession():获取当前用户的Session。可以使用Session的setAttribute方法和getAttribute方法存或取值。
- getPrincipal():获取当前用户名;
- hasRole(“admin”):当前用户是否拥有角色admin;
- isPermitted(“eat:Obsidian”):是否被允许有“eat:Obsidian”权限。另外一个如:**isPermitted(“drink:Cola”)**则为是否拥有drink:Cola权限;
- logout():登出。
SpringBoot与Shiro集成
可能是Spring与Shiro集成?!
简易配置
创建ShiroConfig配置类和UserRealm;
UserRealm类继承AuthorizingRealm对象,重写相关方法;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18//一个自定义的UserRealm
//继承AuthorizingRealm对象
public class UserRealm extends AuthorizingRealm {
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行了 -> 授权 PrincipalCollection");
//授权
return null;
}
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了 -> 认证 AuthenticationToken");
//有用户登录时会进入这里
//这里负责判断账号密码正确与否
return null;
}
}ShiroConfig下创建三个@Bean,
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
public class ShiroConfig {
//@Bean方式 创建 Realm 对象 自定义类
public UserRealm userRealm(){
return new UserRealm();
}
//DefaultWebSecurityManager
public DefaultWebSecurityManager getDefaultWebSessionManager({ UserRealm realm)
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联UserRealm
securityManager.setRealm(realm);
return securityManager;
}
//ShiroFilterFactoryBean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(
{ DefaultWebSecurityManager securityManager)
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//关联securityManager 设置安全管理器
bean.setSecurityManager(securityManager);
//这里进行一些授权的配置,如:url与角色的绑定
//配置登录API和登录页相关信息
return bean;
}
}分别返回UserRealm、DefaultWebSecurityManager、ShiroFilterFactoryBean三个对象,其中:
- UserRealm直接新建一个刚刚创建的Realm并返回就可;
- DefaultWebSecurityManager,使用@Qualifier注解将刚刚创建的Realm Bean作为方法的参数,新建一个DefaultWebSecurityManager对象,使用setRealm方法绑定刚刚绑定的Realm,然后返回;
- ShiroFilterFactoryBean,使用@Qualifier注解将刚刚创建的DefaultWebSecurityManager Bean作为方法的参数,新建一个ShiroFilterFactoryBean对象,使用setSecurityManager方法绑定刚刚创建的DefaultWebSecurityManager,然后返回。
配置结束。
配置
UserRealm
创建一个UserRealm类,继承AuthorizingRealm类,重写:
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
两个方法。
doGetAuthorizationInfo(PrincipalCollection principals)
这个方法负责授权。
下面的方法执行结束后,会执行这个方法,负责为登录的用户添加权限(加载权限)。
这里要做的事:
创建SimpleAuthorizationInfo对象。
1
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
从principals中获取用户的权限列表。(下面的方法为当前用户配置了principals属性,这里指用户的User对象,这里通过User.getPerms()获得用户的权限)
1
2
3//拿到当前登录的对象
Subject subject = SecurityUtils.getSubject();
User currentUser = (User) subject.getPrincipal();为用户添加权限
1
2//设置当前用户的权限
info.addStringPermission(currentUser.getPerms());//currentUser.getPerms()是从user对象获取用户的权限返回AuthorizationInfo对象。
示例
1 |
|
doGetAuthenticationInfo(AuthenticationToken token)
这个方法负责认证。
有用户登录时会进入这个方法。
这里要做的事:
从数据库中获取用户相关信息;
判断用户是否存在,不存在返回null;
创建一个AuthenticationInfo类型的对象,将主体对象和密码传入,然后将该对象返回。
(将密码交给Shiro,由Shiro完成密码判断和其他操作。)
示例
1 | //认证 |
- 首先将
AuthenticationToken token
强制转换为UsernamePasswordToken
对象,然后就可以获取到登录用户的一些信息- getUsername():用户名
- getPassword():密码
- 然后通过用户名从数据库中获取用户;
- 最后创建一个验证对象将密码传入然后将对象返回。
ShiroConfig
创建一个@Configuration配置类,用于存放Shiro类的一些@Bean配置。
(这里设置类名为ShiroConfig用于示例)
UserRealm
1 |
|
创建UserRealm对象并返回。
DefaultWebSecurityManager
1 |
|
创建Bean DefaultWebSecurityManager getDefaultWebSessionManager(@Qualifier("userRealm")
用于创建SecurityManager,绑定realm,并返回对象。
- 创建SecurityManager对象 (指定SecurityManager)
- 绑定realm (指定realm对象)
ShiroFilterFactoryBean
1 |
|
创建ShiroFilterFactoryBean对象,并将SecurityManager绑定到对象;
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //关联securityManager 设置安全管理器 bean.setSecurityManager(securityManager);
1
2
3
4
5
6
7
8
9
10
- 进行“授权”相关的配置:绑定url和角色;
- ```java
//进行配置
Map<String,String> filterMap = new LinkedHashMap<>();//配置
bean.setFilterChainDefinitionMap(filterMap);
//授权 url和角色的绑定
filterMap.put("/user/add","anon");//设置url可访问角色
filterMap.put("/user/update","authc");
配置登录API和登录页相关配置
//配置登录API和登录页相关信息 //设置登录请求 bean.setLoginUrl("/login"); //设置用户进入未经授权的页面要跳转的页面 bean.setUnauthorizedUrl("/noauth");
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
- 返回ShiroFilterFactoryBean对象。
### shiro.ini配置
```ini
# =======================
# Shiro INI configuration
# =======================
[main]
# 放一些配置
# 配置密码编码:sha256
sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
iniRealm.credentialsMatcher = $sha256Matcher
[users]
# 放一些静态用户 ,一般在数据库中,不在这里编写。
# 用户名 = 密码,角色1,角色2
yn = 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92,admin,eater
[roles]
# 这里放角色以及一些权限
# 角色名 = 权限
# 访客可以注册账户,登录账户
guest = user:reg,login
# 登录用户可以更新自己的信息
user = user:update
# vip1可以自定义主页CSS
vip1 = user:index:update:css
# vip2可以自定义主页HTML和CSS
vip2 = user:index:update:html,css
# vip3可以自定义主页的HTML、CSS和JS(JS需要经过审核)
vip3 = user:index:update:*
# admin可以为所欲为
admin = *
#
[urls]
# 为url绑定 角色/权限
# 允许任何人访问根目录
/ = anon
# 允许任何人创建用户
/user/create = anon
# 允许任何人进行登录
/user/login = anon
# 仅允许登录的用户进入/user/根目录下页面
/user/* = authc
# 仅允许管理员且被认证的用户进入/admin/下所有页面
/admin/** = authc,roles[admin]
# 拥有user:index:update:html权限的用户可以进入/user/index/html
/user/index/html = perms[user:index:update:html]
/user/index/css = perms[user:index:update:css]
/user/index/js = perms[user:index:update:js]
一些Filter
Filter Name | Class(基于org.apache.shiro.web.filter) | 介绍 |
---|---|---|
anon | authc.AnonymousFilter | 匿名用户 |
authc | authc.FormAuthenticationFilter | 认证用户 |
authcBasic | authc.BasicHttpAuthenticationFilter | |
authcBearer | authc.BearerHttpAuthenticationFilter | |
invalidRequest | InvalidRequestFilter | 无效请求 |
logout | authc.LogoutFilter | 登出请求 |
noSessionCreation | session.NoSessionCreationFilter | 在此页面不能创建Session |
perms | authz.PermissionsAuthorizationFilter | 当用户具有指定权限,则允许访问 |
port | authz.PortFilter | 位于特定端口上的过滤器。 |
rest | authz.HttpMethodPermissionFilter | RESTful环境 |
roles | authz.RolesAuthorizationFilter | 判断用户拥有指定角色 |
ssl | authz.SslFilter | 必须使用ssl访问 |
user | authc.UserFilter | 若是已知用户且已登录,则允许访问该页面,否则不允许访问。 |
Thymeleaf与Shiro集成
https://github.com/theborakompanioni/thymeleaf-extras-shiro
依赖
HTML
1 | <html xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> |
pom.xml
1 | <dependency> |
配置类
1 | //整合ShiroDialect:用来整合shiro和thymeleaf |
添加一个返回ShiroDialect对象的@Bean方法就可。
可以放在ShrioConfig类下。
作用
可以在Thymeleaf下的HTML文件里添加Shiro为JSP设计的页面控制标签;
1
<shiro:guest>未登录的标志</shiro:guest>
可以将标签作为属性写在HTML元素中。
1
<p shiro:guest>未登录的标志2</p>
一些标签/属性
guest
当前用户是访客,未登录状态;
1 | <shiro:guest>请登录</shiro:guest> |
1 | <p shiro:guest>请登录</p> |
user
当前用户已登录;
1 | <shiro:user>Welcome back!张三</shiro:user> |
1 | <p shiro:user>Welcome back!张三</p> |
authenticated
在当前会话期间,用户通过身份验证。(与user不同,authenticated不能在只有remember-me没有会话的情况下有效,如:重新打开浏览器/会话关闭)
1 | <shiro:authenticated>身份通过验证,可以访问隐私内容</shiro:authenticated> |
1 | <p shiro:authenticated>身份通过验证,可以访问隐私内容</p> |
notAuthenticated
在当前会话期间未成功验证。(与authenticated相反)
1 | <shiro:notAuthenticated>需要二次验证才能访问当前内容 / 请登录</shiro:notAuthenticated> |
1 | <p shiro:notAuthenticated>需要二次验证才能访问当前内容 / 请登录</p> |
principal
将输出在后端配置的principal属性,toString()方法的返回值;
1 | <shiro:principal></shiro:principal> |
类型type
指定principal的类型,指定后将按照不同方式进行输出。不指定则按照toString输出。
1 | <principal type="java.lang.Integer"/> |
属性值property
若principal是一个对象,可以通过这种方式指定要输出的对象的属性值。
1 | <shiro:principal type="User" property="lastname"/> |
hasRole
用户拥有指定角色时。
1 | <shiro:hasRole name="admin">管理员你好</shiro:hasRole> |
1 | <p shiro:hasRole="admin">管理员你好</p> |
lacksRole
用户没有指定角色时。
1 | <shiro:lacksRole name="admin">你不是管理员吧?</shiro:lacksRole> |
1 | <p shiro:lackRole="admin">闲杂人等不得入内</p> |
缺少admin角色的用户会看到上面的内容。
hasAnyRoles
用户拥有以下任意角色时。
1 | <shiro:hasAnyRoles name="developer, project manager, administrator">你好,管理员</shiro:hasAnyRoles> |
1 | <p shiro:hasAnyRoles="developer, project manager, administrator">你好,管理员</p> |
当访问这是developer, project manager, administrator其中任意一种角色时,可以看到上面内容。
hasAllRoles
用户拥有以下所有角色时。
1 | <shiro:hasAllRoles name="developer, project manager, administrator">拥有前面所有角色的用户能看得见</shiro:hasAllRoles> |
1 | <p shiro:hasAllRoles="developer, project manager, administrator"> |
hasPermission
用户拥有具有指定的权限。(暗示:通过角色获取的权限)
1 | <shiro:hasPermission name="user:create"> |
1 | <p shiro:hasPermission="user:create"> |
lacksPermission
用户缺少指定权限时。
1 | <shiro:lacksPermission name="user:delete"> |
1 | <p shiro:lacksPermission="user:create"> |