当前运行环境:eclipse 、shiro 1.4.1
1.配置依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.0-alpha1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.0-alpha1</version>
</dependency>
</dependencies>
当前的shiro依赖于slf4j,没有slf4j的话就会报错!
2.开始简单的demo(ini配置文件版)
创建shiroIniApp类
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.apache.shiro.mgt.SecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ShiroIniApp
{
private Logger logger;
private Factory<SecurityManager> factory;
private SecurityManager securityManager;
private Subject subject;
private UsernamePasswordToken token;
@Before
public void init() {
logger = LoggerFactory.getLogger(ShiroIniApp.class);
//1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
factory =initSecurityManagerFactory();
//2、得到SecurityManager实例 并绑定给SecurityUtils
securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
subject = SecurityUtils.getSubject();
token = new UsernamePasswordToken("zhangsan", "123456");
}
public Factory<SecurityManager> initSecurityManagerFactory() {
return new IniSecurityManagerFactory("classpath:shiro.ini");
}
@Test
public void testDefaultDemo() {
try {
//4、登录,即身份验证
subject.login(token);
logger.info("身份验证成功!");
} catch (AuthenticationException e) {
//5、身份验证失败
logger.info("身份验证失败!");
}
Assert.assertEquals(true, subject.isAuthenticated()); //断言用户已经登录
//判断当前用户是否具有admin角色
boolean hasAdminRole = subject.hasRole("user");
logger.info("是否具有user权限:"+hasAdminRole);
if(hasAdminRole) {
boolean hasAllPermission = subject.isPermitted("update");
logger.info("是否拥有update权限:"+hasAllPermission);
}
//6、退出
subject.logout();
}
当前的shiro.ini文件的内容为:
[users]
zhangsan = 123456,user,guest
admin = 123456,admin
[roles]
admin = *
guest = select
user = select,update,add
3.测试当前配置文件版的shiro
[main] INFO org.apache.shiro.session.mgt.AbstractValidatingSessionManager - Enabling session validation scheduler...
[main] INFO com.hy.shiro.demo.ShiroIniApp - 身份验证成功!
[main] INFO com.hy.shiro.demo.ShiroIniApp - 是否具有user权限:true
[main] INFO com.hy.shiro.demo.ShiroIniApp - 是否拥有update权限:true
结果成功!
但是当前的类IniSecurityManagerFactory
已经被废弃
,下面定义管理工厂
4.创建自定义的Factory和RolePermissionResolver
1.通过查看源码发现当前的Facorty接口只有一个方法:getInstance()
所以决定自己实现这个接口
2.所以泛型的类型就是org.apache.shiro.mgt.SecurityManager
这个类
3.查看org.apache.shiro.mgt.SecurityManager这个类的源码和结构树
4.发现只有一个类DefaultSecurityManager
所以直接返回这个类即可
5.查看当前DefaultSecurityManager的构造函数发现需要一个或者多个Realm
再次查看Realm的机构树
6.查看结构树,我选择的是TextConfigurationRealm
,而且这个类中有一个addAccount和setRolePermissionResolver
方法
7.而RolePermissionResolver中的为接口,直接实现即可
8.通过RolePermissionResolver接口中的方法发现需要Permission
,所以查看Permission结构树:
这里的Permission实现类就三个,从字面意思可看出AllPermission表示*(拥有所有权限),WildcardPermission(通配符权限),DomainPermission(域权限),这里可以直接使用WildcardPermission即可
通过debug发现解析ini文件生成的也是WildcardPermission这个类
以上的问题全部解决所以实现代码如下:
import java.util.Arrays;
import java.util.List;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.TextConfigurationRealm;
import org.apache.shiro.util.Factory;
public class MyShiroFacroty implements Factory<org.apache.shiro.mgt.SecurityManager> {
//创建全局的权限解析器
MyRolePermissionResolver resolver=new MyRolePermissionResolver();
//创建默认的校验管理器
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
public SecurityManager getInstance() {
//创建第一个用户:admin ,密码为123456 ,拥有角色为admin
TextConfigurationRealm realm1=new TextConfigurationRealm();
realm1.addAccount("admin", "123456","admin");
realm1.setRolePermissionResolver(resolver);//设置角色权限解析器
//创建第二个用户为zhangsan 密码为 123456 ,拥有角色:user、guest
TextConfigurationRealm realm2=new TextConfigurationRealm();
realm2.addAccount("zhangsan", "123456","user","guest");
realm2.setRolePermissionResolver(resolver);//设置角色权限解析器
Realm[] realms= {realm1,realm2};
List<Realm> asList = Arrays.asList(realms);
defaultSecurityManager.setRealms(asList);//向校验管理器中设置当前的用户
return defaultSecurityManager;
}
}
当前的权限解析类如下:
import java.util.Arrays;
import java.util.Collection;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.permission.AllPermission;
import org.apache.shiro.authz.permission.RolePermissionResolver;
import org.apache.shiro.authz.permission.WildcardPermission;
/**
* @description 自定义角色权限解析器
* @author hy
* @date 2019-10-03
*/
public class MyRolePermissionResolver implements RolePermissionResolver {
//实现通过角色解析权限的过程
public Collection<Permission> resolvePermissionsInRole(String roleString) {
Permission[] permissions= null;
if("admin".equalsIgnoreCase(roleString)) {
//AllPermission表示具有所有的权限
permissions=new Permission[]{new AllPermission()};
}else if("user".equalsIgnoreCase(roleString)) {
//通过查看发现应该创建wildCardPermission这个类的实例,并向parts中添加权限
permissions=new Permission[]{
new WildcardPermission("select,update,add")
};
//通过查看源码发现当前的WildcardPermission中的有参构造函数中向其中添加的字符会转换成parts字符集合
}else if("guest".equalsIgnoreCase(roleString)) {
permissions=new Permission[]{
new WildcardPermission("select")
};
}
return Arrays.asList(permissions);
}
}
5.测试自定义Facroty以及自定义RolePermissionResolver
直接将其中的initFactory方法换成
public Factory<SecurityManager> initSecurityManagerFactory() {
/* return new IniSecurityManagerFactory("classpath:shiro.ini"); */
return new MyShiroFacroty();
}
结果:
[main] INFO org.apache.shiro.session.mgt.AbstractValidatingSessionManager - Enabling session validation scheduler...
[main] INFO com.hy.shiro.demo.ShiroIniApp - 身份验证成功!
[main] INFO com.hy.shiro.demo.ShiroIniApp - 是否具有user权限:true
[main] INFO com.hy.shiro.demo.ShiroIniApp - 是否拥有update权限:true
与上面完全一致!
6.总结
1.使用配置文件编写shiro.ini的时候需要
在[users]下使用用户名=密码,角色1,角色2...
在[roles]下使用角色1=权限1,权限2...
2.在自定义的Factory中需要
- 使用默认的校验管理器
(DefaultSecurityManager)
和TextConfigurationRealm来创建用户名、密码和权限
- 需要使用
WildcardPermission来创建Permission(权限)
3.当前的shiro通过SecurityManager来管理校验
,通过Subject来进行每一次操作
,通过创建token来管理用户登录的用户名和密码
4.通过使用发现当前的Shiro框架相对于Spring Security来说,继承层次比较简单,对象关系简单,容易上手!
以上纯属个人见解,如有问题请联系本人!