shiro入門實例



Web.xml配置

<context-param>
		<param-name>contextConfigLocation</param-name>		<param-value>classpath:applicationContext.xml,classpath:spring-shiro.xml</param-value>
	</context-param>
<!-- apache shiro權限 -->
	<filter>  
        <filter-name>shiroFilter</filter-name>  
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
        <init-param>  
            <param-name>targetFilterLifecycle</param-name>  
            <param-value>true</param-value>  
        </init-param>  
    </filter>  
  
    <filter-mapping>  
        <filter-name>shiroFilter</filter-name>  
        <url-pattern>*.do</url-pattern>  
    </filter-mapping>  
    <filter-mapping>  
        <filter-name>shiroFilter</filter-name>  
        <url-pattern>*.jsp</url-pattern>  
    </filter-mapping>  

第一部分是將shiro的配置文件引入到web.xml中,我這裏是spring-shiro.xml;
下面的是一個過濾器,過濾.do,.jsp的請求,引入shiro web.xml就配這麼多。
spring-shiro.xml配置文件

<?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:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
    http://www.springframework.org/schema/util 
    http://www.springframework.org/schema/util/spring-util-3.0.xsd">
	<description>Shiro 配置</description>
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/login.jsp" />
		<property name="successUrl" value="/login.jsp" />
		<property name="unauthorizedUrl" value="/error/noperms.jsp" />
		<property name="filterChainDefinitions">
			<value>
				/login.jsp* = anon
				/login.do* = anon
				/index.jsp*= anon
				/error/noperms.jsp*= anon
				/*.jsp* = authc
				/*.do* = authc
			</value>
		</property>
	</bean>

	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<!--設置自定義realm -->
		<property name="realm" ref="monitorRealm" />
	</bean>

	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

	<!--自定義Realm 繼承自AuthorizingRealm -->
	<bean id="monitorRealm" class="com.springmvc.service.MonitorRealm"></bean>
	<!-- securityManager -->
	<bean
		class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
		<property name="staticMethod"
			value="org.apache.shiro.SecurityUtils.setSecurityManager" />
		<property name="arguments" ref="securityManager" />
	</bean>

	<!-- Enable Shiro Annotations for Spring-configured beans. Only run after -->
	<!-- the lifecycleBeanProcessor has run: -->
	<bean
		class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
		depends-on="lifecycleBeanPostProcessor" />
	<bean
		class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager" />

	</bean>

</beans>


這裏不想說太多,我這裏沒什麼特別的,很多都是用的shiro自己的原有的,只有一個realm是我自己定義的,可能自己定義的會更好用點吧,如果不用自己定義的就用shiro的jdbcrealm,我自定義的也是跟jdbcrealm差不多的,後面我們再說我的自定義realm。另外就是給頁面指定過濾器
/login.jsp* = anon /login.do* = anon /index.jsp*= anon /error/noperms.jsp*= anon /*.jsp* = authc /*.do* = authc


Anon:不指定過濾器,不錯是這個過濾器是空的,什麼都沒做,跟沒有一樣。
Authc:驗證,這些頁面必須驗證後才能訪問,也就是我們說的登錄後才能訪問。
這裏還有其他的過濾器,我沒用,比如說授權,這個比較重要,但是這個過濾器有個不好的地方,就是要帶一個參數,所以如果配在這裏就不是很合適,因爲每個頁面,或是.do的權限不一樣,而我們也沒法事先知道他需要什麼權限。所以這裏不配,我們在代碼中再授權。這裏.do和.jsp後面的*表示參數,比如login.jsp?main這種,是爲了匹配這種。好行了,繼續往下吧。
驗證:
驗證我們就弄一個登錄頁面,然後提交到後臺的action

@RequestMapping(params = "main")
	public ModelAndView login(User user,HttpSession session, HttpServletRequest request) {

		ModelAndView modelView = new ModelAndView();
		Subject currentUser = SecurityUtils.getSubject();
		UsernamePasswordToken token = new UsernamePasswordToken(
				user.getUsercode(), EncryptUtils.encryptMD5(user.getPassword()));
		token.setRememberMe(true);
		try {
			currentUser.login(token);
		} catch (AuthenticationException e) {
			modelView.addObject("message", "login errors");
			modelView.setViewName("/login");
			e.printStackTrace();
			
		}
		if(currentUser.isAuthenticated()){
			
			session.setAttribute("userinfo", user);
			modelView.setViewName("/main");
		}else{
			modelView.addObject("message", "login errors");
			modelView.setViewName("/login");
		}
		return modelView;
	}

這裏我用的是spring MVC,你不用管他用什麼mvc,我們只要知道,前臺.do登錄以後進入這個方法就行
Subject currentUser = SecurityUtils.getSubject()
;就是代表當前的用戶。
UsernamePasswordToken token = new UsernamePasswordToken( user.getUsercode(),EncryptUtils.encryptMD5(user.getPassword()));
這裏的token大家叫他令牌,也就相當於一張表格,你要去驗證,你就得填個表,裏面寫好用戶名密碼,交給公安局的同志給你驗證。
currentUser.login(token);
這句是提交申請,驗證能不能通過,也就是交給公安局同志了。這裏會回調reaml裏的一個方法
protected AuthenticationInfo doGetAuthenticationInfo()
驗證是否通過
if(currentUser.isAuthenticated())
通過則轉到你的頁面,不通過到login頁面並返回錯誤信息。
現在我們看看我們的reaml類,這是一個自定義的realm,

@Service("monitorRealm")
public class MonitorRealm extends AuthorizingRealm {
	/*
	 * @Autowired UserService userService;
	 * 
	 * @Autowired RoleService roleService;
	 * 
	 * @Autowired LoginLogService loginLogService;
	 */

	public MonitorRealm() {
		super();

	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		/* 這裏編寫授權代碼 */
		Set<String> roleNames = new HashSet<String>();
	    Set<String> permissions = new HashSet<String>();
	    roleNames.add("admin");
	    permissions.add("user.do?myjsp");
	    permissions.add("login.do?main");
	    permissions.add("login.do?logout");
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
	    info.setStringPermissions(permissions);
		return info;
	}
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		/* 這裏編寫認證代碼 */
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
//		User user = securityApplication.findby(upToken.getUsername());
		User user = new User();
		user.setUsercode(token.getUsername());
		user.setUserName("admin");
		user.setPassword(EncryptUtils.encryptMD5("admin"));
//		if (user != null) {
		return new SimpleAuthenticationInfo(user.getUserName(),
				user.getPassword(), getName());
	}
	public void clearCachedAuthorizationInfo(String principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(
				principal, getName());
		clearCachedAuthorizationInfo(principals);
	}
}


這裏我沒有跟數據庫打交道,如果要跟數據庫打交道很簡單,你調用一個service,service再調dao,根據用戶名去打該用戶的密碼。用戶我們可以前面的令牌也就是我說的表格來取的,我們前臺提交給公安同志一個表格,裏面有用戶密碼,但需要注意的是,我們在這裏並不把表格中的用戶密碼路數據庫中的用戶密碼進行比較,我們只是根據表格中的用戶名把密碼查出來,然後把數據庫的用戶密碼放在一個SimpleAuthenticationInfo對象中返回即可,這位公安同志不負責驗證,只負責驗證的材料。我這裏沒有查庫,僞造了一個用戶密碼放入了對象。密碼是admin。什麼時候驗證,就是我們前面調currentUser.isAuthenticated()時驗證,所有的材料都全了,需要驗證的時候就調一下這個方法就可以了。我們前面spring裏配了這個
/*.jsp* = authc
/*.do* = authc
你配了authc過濾器,shiro會自動調currentUser.isAuthenticated()這個方法,沒有登錄的將被返回
<property name="unauthorizedUrl" value="/error/noperms.jsp" />
配置的頁面。
好到這裏登錄就算是完成了。完成了登錄下面就是要授權了,我們已經登錄系統,我進入系統總要做點什麼吧,比如這個系統就是一個公司的話,我現在已經進入公司了,如果我要進辦公室,還得要授權(假如有門禁的話)刷卡。這們就裏就是訪問某個頁面或是某個.do,
授權:
因爲前面我們只配了驗證過濾器,現在已經登錄系統,如果我們請求一個*.do的話就會來到後臺的action,我們授權也將在這裏授。
Java代碼

@Controller
@RequestMapping(value="user")
public class UserController {
	
	/**
	 * 跳轉到myjsp頁面
	 * 
	 * @return
	 */
	@RequestMapping(params = "myjsp")
	public String home() {
		Subject currentUser = SecurityUtils.getSubject();
		if(currentUser.isPermitted("user.do?myjsp")){
			return "/my";
		}else{
			return "error/noperms";
		}
	}
}


我一直都說action,其實spring mvc裏不再是action了,叫controller,我們這裏的home方法的訪問路徑是user.do?myjsp,也就是我們登錄系統後請求一個這個方法user.do?myjsqp,轉到home方法後,我要看他有沒有權限訪問此方法,我就用下面的代碼
Subject currentUser = SecurityUtils.getSubject();
currentUser.isPermitted("user.do?myjsp");
首先得到當前的用戶,再看此用戶是否有權訪問user.do?myjsp,參數就是權限,這裏後臺數據庫就會有這麼一個權限,權限表中的權限地址就是user.do?myjsp,例如我們一般的系統左邊是一棵功能菜單樹,樹的結點會有一個url鏈接,這個鏈接就是在權限表中。當然可能前面還會一個http:\\什麼的。反正這裏也跟後臺的權限表中的地址一致就行了,shiro他是如何授權的。一樣的你調用currentUser.isPermitted("user.do?myjsp");此方法後會回調realm中的protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals)方法,這個reaml類是非常重要的。這個類上面已經給出了,我們看看他是如何授權的。因爲我沒有連數據庫,也是僞造了一個權限。如果是連數據庫也很簡單,用戶表,角色表,權限表這三個表是有關聯的,我們根據用戶名就能查出此用戶擁有的角色和所有的權限。

Java代碼

Set<String> roleNames = new HashSet<String>();
	    Set<String> permissions = new HashSet<String>();
	    roleNames.add("admin");
	    permissions.add("user.do?myjsp");
	    permissions.add("login.do?main");
	    permissions.add("login.do?logout");
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
	    info.setStringPermissions(permissions);
		return info;


最後構造一個對象並把權限給它就OK拉。如果是數據庫查出來的,直接我的字符串替成你查出來的就行了。這樣在你的controller中根據權限返回到指定的頁面。

Java代碼

if(currentUser.isPermitted("user.do?myjsp")){
			return "/my";
		}else{
			return "error/noperms";
		}
沒有權限就返回到沒有權限的頁面。那麼整個權限管理系統就算是差不多了,當然還有頁面標籤沒說,這部分不是難點,自己找找資料吧


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章