1.入门案例
导入maven依赖
shiro-core:核心包 shiro-web:主要用于整合web项目 shiro-pring:主要用于整合spring框架 shiro-quartz:主要用于整合任务调度quartz shiro-ehcache:主要用于整合ehcache缓存
pom.xml
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
shiro.ini
[users]
admin=123456
认证代码:
@Test
public void loginTest(){
//认证操作
//加载资源文件
Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:config/shiro.ini");
//创建安全管理器
SecurityManager securityManager = factory.getInstance();
//把安全管理器设置到SecurityUtils中
SecurityUtils.setSecurityManager(securityManager);
//通过安全工具类创建当前Subject主体对象
Subject subject = SecurityUtils.getSubject();
//创建用户认证用的令牌
UsernamePasswordToken token=new UsernamePasswordToken("admin","admin");
//通过login方法进行认证
try {
subject.login(token);
System.out.println("通过验证,可以登陆");
} catch (AuthenticationException e) {
System.out.println("登陆失败");
}
//判断认证结果
boolean authenticated = subject.isAuthenticated();
System.out.println("认证结果:"+authenticated);
//退出系统
subject.logout();
}
认证成功:
通过验证,可以登陆 认证结果:true
认证失败:
登陆失败 认证结果:false
-
原理分析
-
通过加载shiro.ini配置文件创建securityManager
-
通过subject.login方法提交认证,提交token封装的用户信息
-
securityManager进行认证,securityManager最终由ModularRealmAuthenticator进行认证
-
ModularRealmAuthenticator通过调用iniRealm去ini配置文件中查询用户信息
-
iniRealm根据输入的token从ini配置文件中查询用户信息,根据帐号查询用户信息(用户名和密码),如果查询到用户信息,就返回用户信息,查询不到,返回null
-
ModularRealmAuthenticator根据iniRealm返回的认证信息,如果是null,抛出异常。如果不是null,说明找到了用户,将返回的用户密码和token中的密码进行对比,如果不一致则抛出异常
-
1.自定义realm认证
实际开发过程中,realm域主要用于数据库的交互,我们可以自定义realm类,从数据库中获取信息
自定义realm的步骤:
-
自定义realm类继承AuthorizingRealm
-
重写验证方法,连接数据库,获取数据
-
自定义ini配置文件
-
通过junit进行测试
MyRealm.java
public class MyRealm extends AuthorizingRealm {
/**
* 授权方法
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 认证方法
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//通过token令牌获取用户账户信息
String username = (String)authenticationToken.getPrincipal();
//根据用户名从数据库中查询用户密码
String password="admin";
if(password==null||"".equals(password)){
return null;
}
//把用户名密码和域的简写类封装到SimpleAuthenticationInfo
return new SimpleAuthenticationInfo(username,password,"myRealm");
}
}
shiro-realm.ini
[main]
authRealm=com.yfy.realm.MyRealm
securityManager.realms=$authRealm
Test.java
@Test
public void loginTest1(){
//认证操作
//加载资源文件
Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:config/shiro-realm.ini");
//创建安全管理器
SecurityManager securityManager = factory.getInstance();
//把安全管理器设置到SecurityUtils中
SecurityUtils.setSecurityManager(securityManager);
//通过安全工具类创建当前Subject主体对象
Subject subject = SecurityUtils.getSubject();
//创建用户认证用的令牌
UsernamePasswordToken token=new UsernamePasswordToken("admin","admin");
//通过login方法进行认证
try {
subject.login(token);
System.out.println("通过验证,可以登陆");
} catch (AuthenticationException e) {
System.out.println("登陆失败");
}
//判断认证结果
boolean authenticated = subject.isAuthenticated();
System.out.println("认证结果:"+authenticated);
//退出系统
subject.logout();
}
3.散列加密算法
在实际开发过程中,一般密码都是以密文的形式进行保存的。shiro也对数据加密提供了支持,常见的加密算法有:md5,sha等
1.Md5Hash类 :通过带参构造器可以实现带验证的加密
2.SimpleHash类:通过带参构造器可以指定加密方式
/**
* md5和sha的加密算法
*/
@Test
public void testMd5(){
String password="admin";
String salt="123456";
int times=1;
//参数:原始密码的明文,盐值随机数,数列次数
Md5Hash md=new Md5Hash(password,salt,times);
System.out.println(md);
System.out.println("---------------");
//参数:加密方式,原始密码的明文,盐值随机数,数列次数
SimpleHash sh=new SimpleHash("sha",password,salt,times);
System.out.println(sh);
}
4.散列加密算法实现步骤
-
数据插入到数据库的时候,先根据加密算法加密后再保存
-
自定义realm类,继承AuthorizingRealm抽象类
-
重写验证方法,根据用户名查询加密后的用户密码和盐值
-
编写ini配置文件,设置匹配器
Md5AutoRealm.java
public class Md5AuthRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
/**
* 认证方法
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//通过token对象获取用户账号,用户自己输入的账号
String username = token.getPrincipal().toString();
//根据获取到的用户账号查询数据表中对应密码和盐值 加密后的密码值
String password = "50317b958ee25a1e14449aeb95db5245";
//密码加密到数据库时使用的盐值
String salt = "abcd";
//封装到SimpleAuthenticationInfo实现类对象中
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,ByteSource.Util.bytes(salt),"md5AuthRealm");
return authenticationInfo;
}
}
shiro-md5.ini
[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#定义散列算法
credentialsMatcher.hashAlgorithmName=md5
#定义散列次数
credentialsMatcher.hashIterations=1
#将凭证匹配器设置到域
md5AuthRealm=com.yfy.realm.Md5AuthRealm
md5AuthRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$md5AuthRealm
5.shiro通过ini配置文件授权
shiro-perm.ini
[users]
#用户admin的密码是admin,此用户具有role1和role2两个角色
admin=admin,role1,role2
#用户test的密码是test,此用户具有role2角色
test=test,role2
[roles]
#角色role1对资源user拥有create、update权限
role1=user:create,user:update
#角色role2对资源user拥有create、delete权限
role2=user:create,user:delete
#配置文件中的内容属于静态的资源配置定义,动态的数据配置需要从数据库中获取
#user:*代表通配符,匹配所有user操作权限
Test.java
@Test
public void testPerm() {
// 加载资源文件
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:config/shiro-perm.ini");
// 创建安全管理器
SecurityManager securityManager = factory.getInstance();
// 把安全管理器设置到SecurityUtils
SecurityUtils.setSecurityManager(securityManager);
// 通过安全工具类创建subject主体对象
Subject subject = SecurityUtils.getSubject();
// 创建用户认证用的令牌
UsernamePasswordToken token = new UsernamePasswordToken("test", "test");
try {
// 通过subject主体的login方法来进行认证
subject.login(token);
System.out.println("通过验证,可以登录系统");
} catch (Exception e) {
System.out.println("验证失败。。。。");
e.printStackTrace();
}
// 判断认证结果
boolean authenticated = subject.isAuthenticated();
System.out.println(authenticated);
// 判断当前主体对象是否属于指定的角色
boolean hasRole = subject.hasRole("role1");
System.out.println("当前主体是否拥有role1 :" + hasRole);
// 判断是否具有自定的权限
boolean permitted = subject.isPermitted("test");
System.out.println("当前主体具有创建用户的权限:" + permitted);
// 多角色判断
boolean flag = subject.hasAllRoles(Arrays.asList("role1", "role2", "role3"));
System.out.println("当前主体具有role1和role2两个角色:" + flag);
// 多权限判断
boolean ppflag = subject.isPermittedAll("user:create", "user:delete");
System.out.println("ppflag:" + ppflag);
}
输出结果:
通过验证,可以登录系统 true admin的输入role1 :false 当前主体具有创建用户的权限:false 当前主体具有role1和role2两个角色:false ppflag:true
6.自定义realm授权
-
自定义realm授权的目的是为了访问数据库,操作数据库中的数据进行验证、授权判断
MyPermRealm.java
public class MyPermRealm extends AuthorizingRealm {
/**
* 授权操作
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 获取用户名
String username = principals.getPrimaryPrincipal().toString();
List<String> perms = new ArrayList<String>();
//根据用户名从数据库中获取角色信息
String[] roles = {"role1","role2"};
//遍历角色,根据角色获取每一个角色具有权限信息
for(String role : roles){
//获取权限信息,并且保存到权限列表中
perms.add("user:create");
perms.add("user:delete");
perms.add("user:update");
}
//把权限列表封装到SimpleAuthorizationInfo对象中
SimpleAuthorizationInfo saif = new SimpleAuthorizationInfo();
saif.addStringPermissions(perms);
saif.addRoles(Arrays.asList(roles));
return saif;
}
/**
* 认证方法
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = token.getPrincipal().toString();
//根据用户获取用户密码
String password = "admin"; //从数据库中获取到的密码的值
//把用户名和密码封装到AuthenticationInfo的实现类对象中
SimpleAuthenticationInfo shinfo = new SimpleAuthenticationInfo(username,password,"authRealm");
return shinfo;
}
}
shiro-perm-realm.ini
[main]
authRealm=com.yfy.realm.MyPermRealm
securityManager.realms=$authRealm
Test.java
@Test
public void testPermRealm() {
// 加载资源文件
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:config/shiro-perm-realm.ini");
// 创建安全管理器
SecurityManager securityManager = factory.getInstance();
// 把安全管理器设置到SecurityUtils
SecurityUtils.setSecurityManager(securityManager);
// 通过安全工具类创建subject主体对象
Subject subject = SecurityUtils.getSubject();
// 创建用户认证用的令牌
UsernamePasswordToken token = new UsernamePasswordToken("admin", "admin");
try {
// 通过subject主体的login方法来进行认证
subject.login(token);
System.out.println("通过验证,可以登录系统");
} catch (Exception e) {
System.out.println("验证失败。。。。");
e.printStackTrace();
}
// 判断认证结果
boolean authenticated = subject.isAuthenticated();
System.out.println(authenticated);
if (authenticated) {
// 判断当前主体对象是否属于指定的角色
//boolean hasRole = subject.hasRole("role1");
//System.out.println("admin的输入role1 :" + hasRole);
// 判断是否具有自定的权限
boolean permitted = subject.isPermitted("user:create");
System.out.println("当前主体具有创建用户的权限:" + permitted);
// 多角色判断
boolean flag = subject.hasAllRoles(Arrays.asList("role1", "role2"));
System.out.println("当前主体具有role1和role2两个角色:" + flag);
// 多权限判断
boolean ppflag = subject.isPermittedAll("user:create", "user:delete");
System.out.println("ppflag:" + ppflag);
}
}
输出结果:
通过验证,可以登录系统 true 当前主体具有创建用户的权限:true 当前主体具有role1和role2两个角色:true ppflag:true
本文详细介绍了Apache Shiro框架在权限管理方面的应用,包括基本的认证流程、自定义Realm的实现、散列加密算法的使用,以及如何进行授权操作。通过实例展示了如何配置Shiro,实现用户认证和权限控制。
543

被折叠的 条评论
为什么被折叠?



