- 引入相關jar包
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.3.2</version>
</dependency>
- 在web.xml中配置spring框架提供的用于整合shiro框架的過濾器
<!-- 配置spring框架提供的用于整合shiro框架的過濾器,注意放其他過濾器前面 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 在spring配置文件中配置bean,id為shiroFilter
<!-- 配置shiro框架的過濾器工廠對象 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 注入安全管理器對象 -->
<property name="securityManager" ref="securityManager"/>
<!-- 注入相關頁面訪問URL -->
<!-- 注入跳轉到登陸的URL,還沒登陸情況下 -->
<property name="loginUrl" value="/login.jsp"/>
<!-- 注入登陸成功后訪問的URL,這個配置可以不配,因為本身登陸邏輯就會跳轉到index -->
<property name="successUrl" value="/index.jsp"/>
<!-- 注入權限不足時訪問的URL -->
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<!--注入URL攔截規則 -->
<property name="filterChainDefinitions">
<value>
/css/** = anon //anon是匿名訪問過濾器,相當于不過濾,不用登陸也可以訪問,放行
/js/** = anon
/images/** = anon
/validatecode.jsp* = anon
/login.jsp = anon
/userAction_login.action = anon
/page_base_staff.action = perms["staff-list"] //perms是權限檢查過濾器
/* = authc //這個是框架提供的過濾器的別名,檢查當前用戶是否認證過
</value>
</property>
</bean>
<!-- 注冊安全管理器對象 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm"/>
</bean>
<!-- 注冊realm -->
<bean id="myRealm" class="com.xxx.xxx.realm.MyRealm"></bean>
使用場景一:登陸認證
認證流程
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
//使用shiro框架提供的方式進行認證操作
Subject subject = SecurityUtils.getSubject();//獲得當前用戶對象,狀態為“未認證”
AuthenticationToken token = new UsernamePasswordToken(model.getUsername(),MD5Utils.md5(model.getPassword()));//創建用戶名密碼令牌對象,兩個參數為賬號和密碼
try{
subject.login(token);//這個方法會去調SecurityManager,沒有返回值,用try catch來判斷登陸是否成功
}catch(Exception e){
e.printStackTrace();
return LOGIN;//返回登陸界面
}
//SecurityManager要去調用Realm,所以要寫個Realm,請先看下面的MyRealm代碼
User user = (User) subject.getPrincipal();//把MyRealm里簡單認證信息對象取出來
ServletActionContext.getRequest().getSession().setAttribute("loginUser", user);//存到Session里去
return HOME;
創建個自定義Realm
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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
public class MyRealm extends AuthorizingRealm{
@Autowired
private UserDao userDao;
//認證方法
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("自定義的realm中認證方法執行了。。。。");
UsernamePasswordToken passwordToken = (UsernamePasswordToken)token;
//獲得頁面輸入的用戶名
String username = passwordToken.getUsername();
//根據用戶名查詢數據庫中的密碼
User user = userDao.findUserByUsername(username);
if(user == null){
//頁面輸入的用戶名不存在,認證失敗
return null;
}
//簡單認證信息對象
AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
//框架負責比對數據庫中的密碼和頁面輸入的密碼是否一致
return info;
}
//授權方法
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//為用戶授權
info.addStringPermission("staff-list");//"staff-list"對應前面配置的perms權限檢查過濾器,在請求對應的url時會去獲取權限,具體實現可以根據業務需求展開
return info;
}
}
使用場景二:權限控制
注解式權限控制(代理模式)
- 在spring配置文件中配置bean
!-- 開啟shiro框架注解支持 -->
<bean id="defaultAdvisorAutoProxyCreator"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<!-- 必須使用cglib方式為Action對象創建代理對象 -->
<property name="proxyTargetClass" value="true"/>
</bean>
<!-- 配置shiro框架提供的切面類,用于創建代理對象 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>
- 在要控制的方法里加上注解
@RequiresPermissions("domethod")//執行這個方法,需要當前用戶具有domethod這個權限
public String method(){
return "index";
}
- 需要在表現層配置全局異常處理器
3.1.0 Struts2全局異常配置(struts.xml)
<!-- 全局結果集定義 -->
<global-results>
<result name="login">/login.jsp</result>
<result name="unauthorized">/unauthorized.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping result="unauthorized"
exception="org.apache.shiro.authz.UnauthorizedException"></exception-mapping>
</global-exception-mappings>
3.2.0 SpringMVC全局異常配置(springmvc.xml)
<!-- 全局異常處理器 -->
<bean class="cn.exception.GlobalExceptionResolver"/>
需要自定義一個全局異常處理器,實現HandlerExceptionResolver接口
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionResolver.class);
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
//打印控制臺
ex.printStackTrace();
//寫日志
logger.debug("測試輸出的日志。。。。。。。");
logger.info("系統發生異常了。。。。。。。");
logger.error("系統發生異常", ex);
//發郵件、發短信
//使用jmail工具包。發短信使用第三方的Webservice。
//顯示錯誤頁面
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error/exception");
return modelAndView;
}
頁面標簽方式權限控制(標簽模式)
- 在jsp頁面中引入shiro的標簽庫
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
- 使用shiro的標簽控制頁面元素展示,在要控制權限的元素上
<shiro:hasPermission name="staff-delete">
{
id : 'button-delete',
text : '刪除',
iconCls : 'icon-cancel',
handler : doDelete
},
</shiro:hasPermission>
注:如果沒有權限,那么shiro:hasPermission包裹的元素無法展示