shiro的簡單使用

一.認證與授權

       認證:系統提供的用於識別用戶身份的功能,通常登錄功能就是認證,讓系統知道你是誰,qq登錄,微信登錄。

       授權:系統用戶可以訪問哪些功能,讓系統知道你能做什麼。

shiro核心功能,認證,授權、加密

二.基本使用

              1.引入框架依賴

<!-- 引入shiro框架的依賴 -->
			<dependency>
				<groupId>org.apache.shiro</groupId>
				<artifactId>shiro-all</artifactId>
				<version>1.2.2</version>
			</dependency>

           2.在web.xml中配置

<!-- 用於整合shiro框架的過濾器 -->
	
	<servlet>
		<servlet-name>shiroFilter</servlet-name>
		<servlet-class>org.springframework.web.filter.DelegatingFilterProxy</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>shiroFilter</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>

           3.在spring配置文件中配置bean,id和必須和我們web.xml中配置的名稱一致,因爲會根據id進行注入否則會報錯

            No bean named 'shiroFilter' available

 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
	 	<!-- 安全管理器對象 -->
	 	<property name="securityManager" ref="securityManager"></property>
	 	<!-- 注入相關頁面訪問URL-->
	 	<property name="loginUrl" value="/page/login"></property>
	 	<property name="successUrl" value="/page/index"></property>
	 	<property name="unauthorizedUrl" value="/Unauthorized"></property>
	 	<!-- 注入url攔截規則 -->
	 	<property name="filterChainDefinitions">
	 		<value>
	 			/css/** = anon
	 			/js/** =anon
	 			/images/** =anon
	 			/page/login = anon
	 			/login = anon
				/page/equipmentMessage/equipmentDetail  =  perms["equipment-list"]
	 			/** = authc
	 		</value>
	 	</property>
	</bean> 
	<!-- 註冊安全管理器對象 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="realm"></property>
	</bean>
	<!-- 註冊realm -->
	<bean id="realm" class="cn.tlj.login.serviceImpl.LoginRealm"></bean>

       shiroFilter中必須要注入安全管理器,否則會報錯,安全管理器對象中需要注入realm來實現我們的認證或是授權的邏輯,當然不注入就什麼也不幹。

package cn.tlj.login.serviceImpl;

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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import cn.tlj.pojo.RiEquipmentmessageEquipment;

public class LoginRealm extends AuthorizingRealm{
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
		//授權方法
		SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
		simpleAuthorizationInfo.addStringPermission("equipment-list");
		return simpleAuthorizationInfo;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//認證方法
		//根據用戶名查詢數據庫中usernmae的密碼 框架負責比對密碼是否符合
		UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
		System.out.println("自定義的realm方法執行了");
		//第一個參數會被放到theadLocal中,可以在後面取出     第二個參數爲查詢數據庫後得到的密碼 第三個參數爲任意的字符
		AuthenticationInfo info  = new SimpleAuthenticationInfo(new RiEquipmentmessageEquipment(),"123",this.getName());
		//返回空認爲用戶名不存在
		return info;
	}
}

實現類,我們繼承AuthorizingRealm類,而不是直接實現realm接口。 

登錄方法調用subject.login方法進入到realm中的認證與授權方法中。

	@RequestMapping("/login")
	public String login(String username,String password){
			//subject就是對象
			Subject subject = SecurityUtils.getSubject();
			//創建用戶名密碼令牌  123就是傳入的密碼
			AuthenticationToken passwordToken = new UsernamePasswordToken(username,"123");
			//高級  沒有報錯就是登陸成功了
			try{
				subject.login(passwordToken);
			}catch(Exception e){
				e.printStackTrace();
				return "/login/login";
			}
			//這裏取到後面加入到ThreadLocal中的值
			Object principal = subject.getPrincipal();
		return "index";
	}

 

org.apache.shiro.authc.UnknownAccountException  未知賬號異常realm返回努力

anon 匿名訪問過濾器(未登錄也可以訪問)

authc 檢查當前用戶是否已登錄

perms 檢查權限     /page/list  =  perms["staff-list"]

     3.配置shiro註解模式

配置類

<!-- spring的代理類  開啓shiro框架註解支持-->
	<bean id="defaultAdvisorAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
		<!-- 設置爲true強制對目標類進行代理 使用CGIB代理    JDK代理是實現接口-->
		<property name="proxyTargetClass" value="true"></property>
	</bean>
	<!-- 配置shiro框架提供的切面類,用於創建代理對象  通知+切入點=切面   我們前面寫的事務的切面表達式
	實際就是代理對象  切入點就是規則  規則滿足了就執行通知的邏輯 創建代理對象 -->
	<bean  class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"></bean>

 

/**
	 * Set whether to proxy the target class directly, instead of just proxying
	 * specific interfaces. Default is "false".
	 * <p>Set this to "true" to force proxying for the TargetSource's exposed
	 * target class. If that target class is an interface, a JDK proxy will be
	 * created for the given interface. If that target class is any other class,
	 * a CGLIB proxy will be created for the given class.
	 * <p>Note: Depending on the configuration of the concrete proxy factory,
	 * the proxy-target-class behavior will also be applied if no interfaces
	 * have been specified (and no interface autodetection is activated).
	 * @see org.springframework.aop.TargetSource#getTargetClass()
	 */
	public void setProxyTargetClass(boolean proxyTargetClass) {
		this.proxyTargetClass = proxyTargetClass;
	}

        默認爲false 爲jdk代理,設置爲true的話強制使用目標源進行代理,使用JDK代理創建是創建一個實現目標對象接口的類(如果目標對象不是接口,那麼會實現其父接口),如果目標對象是類,那麼會使用CGLIB代理方式實現代理(相當於實現一個繼承當前類的類)。  所以這裏要改爲true,使用CGLB模式進行代理,否則會報找不到方法錯誤。

使用方法,在方法上添加註解

	@RequestMapping(value="/equipmentMessage/equipmentDetail/list",method = RequestMethod.POST)
	@ResponseBody
	@RequiresPermissions("equipment-list")
	public EquiementPage findEquipmentByCondition(
			@RequestParam(value="rows",defaultValue="10")Integer rows,
			@RequestParam(value="page",defaultValue="1")Integer page,
			@RequestParam(value="workshopName",defaultValue="")String workshopName,
			@RequestParam(value="equipmentLevel",defaultValue="")String equipmentLevel,
			@RequestParam(value="equipmentName",defaultValue="")String equipmentName)
	{
		return equipmentService.findEquipmentByCondition(rows, page,workshopName,equipmentLevel,equipmentName);
	}

這裏如果沒有對應的權限會報錯: org.apache.shiro.authz.AuthorizationException

我們不希望錯誤返回頁面所以,需要對錯誤進行處理。

SpringMVC錯誤處理:https://blog.csdn.net/afdasfggasdf/article/details/84537386

3.使用shiro提供的頁面標籤方式權限控制

                 在頁面中加入shiro標籤庫

                  shiro頁面標籤庫的使用:https://blog.csdn.net/yaodieteng1510/article/details/79992247

4.代碼驗證權限方式(不提倡使用)

                 Subject subject = SecurityUtils.getSubject();  //內部使用ThreadLocal實現的線程間的通訊

                 subject .checkPermission("staff-edit");        //沒有權限拋出異常

boolean permitted = SecurityUtils.getSubject().isPermitted("equipment-query-only");  //返回是否有權限

 

 

 

 

 

 

 

 

 

       

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