1. 程式人生 > >javaEE shiro框架,許可權控制。基於Spring框架的shiro許可權控制

javaEE shiro框架,許可權控制。基於Spring框架的shiro許可權控制

許可權控制的方式: 方式一:通過過濾器或Struts2的攔截器實現許可權控制 方式二:為Struts2的Action加入註解(標識),然後為Action建立代理物件;代理物件進行許可權校驗,校驗通過後通過反射呼叫目標方法。

shiro框架可以進行認證、授權、會話管理、加密等。

shiro框架認證/授權流程:

web.xml(web核心配置檔案,配置Spring提供的shiro過濾器):

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <display-name>MyWeb</display-name>
  
  <!-- 配置spring框架提供的用於整合shiro框架的過濾器。(要在Struts2的過濾器前面配置) -->
  <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>
  
  <!-- 配置過濾器,解決hibernate延遲載入no-session的問題 -->
  <filter>
  	<filter-name>openSessionInView</filter-name>
  	<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>openSessionInView</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <!-- 通過上下文引數指定spring配置檔案位置 -->
  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  
  <!-- 配置spring框架的監聽器 -->
  <listener>
  	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  
  <!-- 配置struts2的過濾器 -->
  <filter>
  	<filter-name>struts2</filter-name>
  	<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>struts2</filter-name>
  	<url-pattern>/*</url-pattern>
  	<dispatcher>REQUEST</dispatcher>
  	<dispatcher>FORWARD</dispatcher>
  </filter-mapping>
  
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

applicationContext.xml(Spring的核心配置檔案):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jaxws="http://cxf.apache.org/jaxws"
	xmlns:soap="http://cxf.apache.org/bindings/soap"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
						http://www.springframework.org/schema/beans/spring-beans.xsd
						http://www.springframework.org/schema/context
						http://www.springframework.org/schema/context/spring-context.xsd
						http://www.springframework.org/schema/aop
						http://www.springframework.org/schema/aop/spring-aop.xsd
						http://www.springframework.org/schema/tx 
						http://www.springframework.org/schema/tx/spring-tx.xsd
						http://cxf.apache.org/bindings/soap 
						http://cxf.apache.org/schemas/configuration/soap.xsd
						http://cxf.apache.org/jaxws 
						http://cxf.apache.org/schemas/jaxws.xsd
						">

	<!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -->

	<!-- ====================================================================== -->
		
	<!-- 配置shiro框架的過濾器工廠物件。"shiroFilter"要和web.xml中配置的過濾器名保持相同 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- 注入安全管理器物件 -->
		<property name="securityManager" ref="securityManager"/>
		<!-- 注入訪問相關頁面的URL -->
		<property name="loginUrl" value="/login.jsp"/>
		<property name="successUrl" value="/index.jsp"/>
		<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"]  <!-- 必須先認證(登入)後,才會進行授權(許可權分配)。"staff-list"是自定義的許可權名 -->
				/* = authc    <!-- authc表示是否已認證(已登入) -->
			</value>
		</property>
	</bean>
	
	<!-- 註冊安全管理器物件 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="bosRealm"/>  <!-- 將Realm注入安全管理器 -->
	</bean>
	
	<!-- 註冊realm -->
	<bean id="bosRealm" class="com.xxx.bos.realm.BOSRealm"></bean>
</beans>

UserAction.java(Struts2的Action):

package com.xxx.bos.web.action;

import java.io.IOException;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.struts2.ServletActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import com.xxx.bos.domain.User;
import com.xxx.bos.service.IUserService;
import com.xxx.bos.utils.BOSUtils;
import com.xxx.bos.utils.MD5Utils;
import com.xxx.bos.web.action.base.BaseAction;

@Controller
@Scope("prototype")
public class UserAction extends BaseAction<User> {
	
	/**
	 * 使用者登入,使用shiro框架提供的方式進行認證操作
	 */
	public String login(){
		//使用shiro框架提供的方式進行認證操作
		Subject subject = SecurityUtils.getSubject();//獲得當前使用者物件,狀態為"未認證"
		//建立使用者名稱密碼令牌物件
		AuthenticationToken token = new UsernamePasswordToken(model.getUsername(),MD5Utils.md5(model.getPassword()));//建立使用者名稱密碼令牌物件
		try{
			//認證(登入) (和注入了Realm的安全管理器(SecurityManager)進行互動,認證)
			subject.login(token);  //登入失敗(認證失敗)就會拋異常
		}catch(Exception e){  //如果拋異常說明登入失敗(認證失敗)。 沒有該使用者和使用者密碼錯誤丟擲的異常是不同的,可以分開catch。
			e.printStackTrace();
			return LOGIN;
		}
		//沒拋異常說明認證成功
		User user = (User) subject.getPrincipal();  //返回的是例項化SimpleAuthenticationInfo()時的第一個引數
		ServletActionContext.getRequest().getSession().setAttribute("loginUser", user);
		return HOME;
	}
	
}

BOSRealm.java(繼承AuthorizingRealm):

package com.xxx.bos.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;

import com.xxx.bos.dao.IUserDao;
import com.xxx.bos.domain.User;

public class BOSRealm extends AuthorizingRealm{
	@Autowired
	private IUserDao userDao;
	
	//認證方法
	@Override
	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;  //return null 說明認證失敗,安全管理器(SecurityManager)就會拋異常
		}
		//簡單認證資訊物件  (引數二:資料庫中的密碼;引數三:類名"BOSRealm")
		AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
		//框架負責比對資料庫中的密碼和頁面輸入的密碼是否一致
		return info;  //交給安全管理器(SecurityManager)去比對密碼。比對不一致也會拋異常(認證失敗)。
	}

	//授權方法
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		return null;
	}
}

applicationContext.xml(Spring的核心配置檔案)中的shiro過濾器: