Shiro执行流程
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进 程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
使用shiro验证和授权
- 准备工作:导入shiro jar包,添加applicationContext_shiro.xml,web.xml添加的过滤器链.txt
使用shiro进行认证
1、创建令牌
2、得到主题subject
3、执行认证
4、自定义realm
5、配置自定义realm
6、修改配置资源访问规则
public void checkUser(){
/**
* 使用shiro认证方式步骤
* 1、创建令牌
* 2、得到subject
* 3、执行认证
* 4、自定义realm
* 5、配置自定义realm
* 6、修改配置资源访问规则
*/
/**
* 加密明文密码
*/
Md5Hash md5Hash = new Md5Hash(pwd, username, 2);
System.out.println("md5Hash===="+md5Hash);
//创建认证
UsernamePasswordToken token = new UsernamePasswordToken(username,md5Hash.toString());
//获得subject
Subject subject = SecurityUtils.getSubject();
try {
//执行认证
subject.login(token);
//将登陆的用户保存到session域中
//获得登陆用户
Emp user = (Emp) subject.getPrincipal();//执行此行代码有安全管理器调用自定义realm
ActionContext.getContext().getSession().put("user", user);
//向客户端写登陆成功信息
write(ajaxReturn(true, "登陆成功"));
} catch (Exception e) {
e.printStackTrace();
write(ajaxReturn(false, "用户名或密码不正确"));
}
//传统方式登录校验
/*Emp emp = empBiz.findByUsernameAndPwd(username, pwd);
if(emp==null){
write(ajaxReturn(false, "用户名和密码错误!"));
}else
{
//将emp对象放入session
ActionContext.getContext().getSession().put("user", emp);
write(ajaxReturn(true, "登陆成功"));
}*/
}
自定义realm
package cn.itcast.erp.realm;
import java.util.List;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import cn.itcast.erp.biz.IEmpBiz;
import cn.itcast.erp.biz.IMenuBiz;
import cn.itcast.erp.entity.Emp;
import cn.itcast.erp.entity.Menu;
public class ErpRealm extends AuthorizingRealm {
//注入empBiz对象
IEmpBiz empBiz;
IMenuBiz menuBiz;
public void setMenuBiz(IMenuBiz menuBiz) {
this.menuBiz = menuBiz;
}
public void setEmpBiz(IEmpBiz empBiz) {
this.empBiz = empBiz;
}
/**
* 授权。控制用户可以访问到的资源
* 1、通过主角得到当前登录的用户对象
* 2、实例化授权信息
* 3、获取访问资源集合
* 4、绑定授权资源信息
* 5、编写规则
*/
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
System.out.println("runing..................");
//通过主角得到当前登录的用户对象
Emp emp = (Emp) principals.getPrimaryPrincipal();
//实例化授权信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//获取访问资源集合
List<Menu> menuList = menuBiz.getMenusByEmpuuid(emp.getUuid());
//绑定授权资源信息
for(Menu list:menuList){
info.addStringPermission(list.getMenuname());
}
return info;
}
/**
* 认证方法
* 1、获得令牌
* 2、调用业务逻辑进行登录判段
* 3、根据结果返回值
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
//获得令牌
UsernamePasswordToken userToken=(UsernamePasswordToken)token;
//获取用户名和和密码
String username = userToken.getUsername();//获取的用户名
String password = new String(userToken.getPassword()); //获取密码
//调用业务逻辑进行登录判段
Emp emp = empBiz.findByUsernameAndPwd(username,password);
//根据结果返回值
if(emp==null){
return null;
}
//返回认证实例
/**
* emp,登录用户
* emp.getPwd(),密码
* getName(),realm类名
*/
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(emp, emp.getPwd(), getName());
return simpleAuthenticationInfo;
}
}
配置
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" depends-on="myFilter">
<!-- 安全管理器 -->
<property name="securityManager" ref="securityManager" />
<!-- 认证相关的配置,当用户没有登录,自动跳转到登录页面 -->
<property name="loginUrl" value="/login.html" />
<!-- 授权相关的配置:当用户没有权限访问时自动条状到该页面 -->
<property name="unauthorizedUrl" value="/error.html" />
<!-- 配置自定义过滤器 -->
<property name="filters">
<map>
<entry key="perms" value-ref="myFilter"></entry>
</map>
</property>
<!-- 过滤链的定义:配置资源访问规则 -->
<property name="filterChainDefinitions">
<value>
/error.html = anon
/login_*.action = anon
<!-- 安全管理器核心组件 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 注入自定义realm -->
<property name="realm" ref="erpRealm"></property>
</bean>
<!-- 自定义realm .注入empBiz -->
<bean id="erpRealm" class="cn.itcast.erp.realm.ErpRealm">
<property name="empBiz" ref="empBiz"></property>
<property name="menuBiz" ref="menuBiz"></property>
</bean>
<!-- 自定义授权过滤器 -->
<bean id="myFilter" class="cn.itcast.erp.filter.MyFilter"></bean>
</beans>
授权操作步骤:
- 通过主角得到当前登录用户对象
- 实例化授权信息
- 获取访问资源集合
- 绑定授权资源信息
- 编写规则(必须有)
/**
* 授权。控制用户可以访问到的资源
* 1、通过主角得到当前登录的用户对象
* 2、实例化授权信息
* 3、获取访问资源集合
* 4、绑定授权资源信息
* 5、编写规则
*/
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
System.out.println("runing..................");
//通过主角得到当前登录的用户对象
Emp emp = (Emp) principals.getPrimaryPrincipal();
//实例化授权信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//获取访问资源集合
List<Menu> menuList = menuBiz.getMenusByEmpuuid(emp.getUuid());
//绑定授权资源信息
for(Menu list:menuList){
info.addStringPermission(list.getMenuname());
}
return info;
}
授权操作:
- url方式
- 自定义过滤器
1、编写自定义过滤器,继承AuthorizationFilter
2、在shiro配置文件中配置自定义过滤器,将自定义过滤器交给spring容器管理
3、在配置文件中将自定义过滤器资源加入到shiroFilter Bean配置中,必须加入depends-on="myFilter"属性
4、编码方式编写规则
4、细颗粒方式也就是编码方式控制
使用shiro加密
直接调用方法:
Md5Hash md5Hash = new Md5Hash(pwd, username, 2);
System.out.println("md5Hash===="+md5Hash);
使用shiro技术可能会遇到的问题
- 没有将相关资源注入spring容器
- 使用授权没有生效,没有配置规则或则配置规则无效