shiro實現登錄安全認證


shiro實現登錄安全認證

shiro的優勢,不需要再代碼里面判斷是否登錄,是否有執行的權限,實現了從前端頁面到后台代碼的權限的控制非常的靈活方便

傳統的登錄認證方式是,從前端頁面獲取到用戶輸入的賬號和密碼之后,直接去數據庫查詢賬號和密碼是否匹配和存在,如果匹配和存在就登錄成功,沒有就提示錯誤

而shiro的認證方式則是,從前端頁面獲取到用戶輸入的賬號和密碼之后,傳入給一個UsernamePasswordToken對象也就是令牌,

然后再把令牌傳給subject,subject會調用自定義的 realm,

realm做的事情就是用前端用戶輸入的用戶名,去數據庫查詢出一條記錄(只用用戶名去查,查詢拿到返回用戶名和密碼),然后再把兩個密碼進行對比,不一致就跑出異常

也就是說如果subject.login(token);沒有拋出異常,就表示用戶名和密碼是匹配的,表示登錄成功

1.在pom.xml中引入shiro依賴

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

2.在web.xml中配置過濾器

<!-- 配置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>

3.在applicationContext.xml中配置DelegatingFilterProxy的Bean

<!-- 配置一個shiro框架的過濾器工廠bean,用於創建shiro框架的過濾器 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- 注入安全管理器對象 -->
		<property name="securityManager" ref="securityManager"/>
		<!-- 注入登錄頁面訪問URL -->
		<property name="loginUrl" value="/login.jsp"/>
		<!-- 注入權限不足提供頁面訪問URL -->
		<property name="unauthorizedUrl" value="/unauthorized.jsp"/><!-- 已經登錄,但是用戶沒有權限的時候才跳轉 -->
		<!-- 配置URL攔截規則 -->
		<property name="filterChainDefinitions">
			<value>
				/css/** = anon
				/js/** = anon
				/images/** = anon
				/validatecode.jsp* = anon
				/login.jsp* = anon
				/userAction_login.action = anon
				/page_base_staff.action = perms["staff"]
				/** = authc<!-- 其他設置用戶認證才能使用-->
			</value>
		</property>
	</bean>
	
	<!-- 注冊安全管理器 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"></bean>

常用過濾器

常用過濾器:
anon:例子/admins/**=anon表示可以匿名訪問
authc:例如/admins/user/**=authc表示需要認證才能使用,沒有參數
perms:例子/page_base_staff.action = perms["staff"],當前用戶需要有staff權限才可以訪問。
roles:例子/admins/user/**=roles[admin],當前用戶是否有這個角色權限。

登錄方法的編寫

傳統的登錄方法

	
	public String login(){
				//調用service層查詢賬號和密碼是否一致
				UserBean user= userService.login(model);
				if(user!=null)
				{
					return "index";
				}
				else
				{
					addActionError("用戶名和密碼不匹配...");
					return "login";
				}
				
			}
	}

shiro的登錄認證方法

	public String login(){           
				if((!StringUtils.isBlank(checkcode))&&key.contentEquals(checkcode) )
				{
					Subject subject = SecurityUtils.getSubject();//獲取當前用戶對象
					//生成令牌(傳入用戶輸入的賬號和密碼)
					UsernamePasswordToken token=new UsernamePasswordToken(model.getUsername(),MD5Utils.md5(model.getPassword()));
					
					//認證登錄
					try {
						//這里會加載自定義的realm
				subject.login(token);//把令牌放到login里面進行查詢,如果查詢賬號和密碼時候匹配,如果匹配就把user對象獲取出來,失敗就拋異常
				UserBean user= (UserBean) subject.getPrincipal();//獲取登錄成功的用戶對象(以前是直接去service里面查)
				ServletActionContext.getRequest().getSession().setAttribute("user", user);
						return "index";
					} catch (Exception e) {
						//認證登錄失敗拋出異常
						addActionError("用戶名和密碼不匹配...");
						return "login";
					}
				}
		}
	
	
					

自定義realm的編寫

public class Bos_realm extends AuthorizingRealm {

	@Resource
	private IUserDao<UserBean> userDao;
	//授權
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	//認證
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		
	UsernamePasswordToken usertoken=(UsernamePasswordToken) token;//獲取令牌(里面存放new UsernamePasswordToken放入的賬號和密碼)
      
		//得到賬號和密碼
		String username = usertoken.getUsername();
		
		UserBean findusername = userDao.findByusername(username);//去sql查詢用戶名是否存在,如果存在返回對象(賬號和密碼都有的對象)
      
		if(findusername!=null)//如果用戶名存在
		{
			//參數1.用戶認證的對象(subject.getPrincipal();返回的對象),
			//參數2.從數據庫根據用戶名查詢到的用戶的密碼
			//參數3.把當前自定義的realm對象傳給SimpleAuthenticationInfo,在配置文件需要注入
			AuthenticationInfo Info = new SimpleAuthenticationInfo(findusername, findusername.getPassword(),this.getName());
			return Info;
		
		}else
		{
			return null;
		}
	}

}

在安全管理器里面注入自定義的realm

	<!-- 注冊安全管理器 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
	<!-- 注入realm到安全管理器進行密碼匹配 -->
	<property name="realm" ref="BosRealm"></property>
	</bean>
	<!-- 自定義的realm -->
	<bean id="BosRealm" class="com.itheima.bos.action.Bos_realm"></bean>

添加權限四方式

1_url

在里面添加攔截規則

<!-- 配置URL攔截規則 -->
		<property name="filterChainDefinitions">
			<value>
				/css/** = anon
				/js/** = anon
				/images/** = anon
				/validatecode.jsp* = anon
				/login.jsp* = anon
				/User_login.action= anon
				/page_base_staff.action = perms["staff"] <!-- 攔截page_base_staff.action這個方法必須有staff權限才能使用 -->
				/** = authc
			</value>
		</property>

2_注解

需要在中配置開啟注解掃描才能使用

開啟添加權限的注解掃描

	<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("staff.delete")//為delete這個方法添加staff.delete權限
	public String delete()
	{
		//得到id
		staffService.deleteBatch(ids);
		return "staff";
	}

3_jsp頁面

需要導入shiro標簽庫

<%@ taglib uri="http://shiro.apache.org/tags"  prefix="shiro"%>
	/* 有staff權限才能顯示此按鈕 */
<shiro:hasPermission name="staff1">
	{
		id : 'button-delete',
		text : '作廢',
		iconCls : 'icon-cancel',
		handler : doDelete
	},
	</shiro:hasPermission>

4_代碼(幾乎不用)

在要設置權限的代碼中添加一下兩行代碼就可以了

	//修改
	public String edit()
	{
		Subject subject = SecurityUtils.getSubject();
		subject.checkPermission("staff.edit");//要運行此方法下面的代碼,必須要擁有staff.edit的權限
		//更新model
		staffService.update(model);
		return "staff";
	}

授權

手動授權和認證

因為要授權的權限太多,所以需要一張權限表

public class Bos_realm extends AuthorizingRealm {

	@Resource
	private IUserDao<UserBean> userDao;
	//授權
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {

      
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.addStringPermission("staff");//為page_base_staff.action請求授權staff權限
		info.addStringPermission("staff.delete");//為page_base_staff.action請求授權staff權限
		info.addStringPermission("staff.edit");
		return info;
     
	}

	//用戶的登錄認證
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//這里添加認證代碼
      
      UsernamePasswordToken usertoken=(UsernamePasswordToken) token;//獲取令牌(里面存放的有賬號和密碼)
		
		//查詢用戶名是否存在
		String username = usertoken.getUsername();
		
		UserBean findusername = userDao.findByusername(username);//去sql查詢用戶名是否存在
		if(findusername!=null)//如果用戶名存在
		{
			//參數1.用戶認證的對象(subject.getPrincipal();返回的對象),
			//參數2.從數據庫根據用戶名查詢到的用戶的密碼
			//參數3.把當前自定義的realm對象傳給SimpleAuthenticationInfo,在配置文件需要注入
			AuthenticationInfo Info = new SimpleAuthenticationInfo(findusername, findusername.getPassword(),this.getName());
			return Info;
		
		}else
		{
			return null;
		}
      

}

遍歷數據庫授權

獲取當前登錄的用戶,去數據庫查詢當前用戶的所有權限,然后添加

	SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();		

		//獲取當前用戶
		UserBean findusername = session.get......;
		
		//結果集
		List<AuthFunction> functionList =null;

		//去sql查詢當前用戶的權限
		if("admin".equals(findusername.getUsername()))//如果是管理員,獲取所有權限
		{
			 functionList = functionDao.findAll();
		}else
		{
			String hql = "SELECT DISTINCT f FROM AuthFunction f LEFT OUTER JOIN f.authRoles r LEFT 				OUTER JOIN r.userBeans u WHERE u.id = ?";
			functionList = functionDao.findByHQL(hql,findusername.getId());
		}
		
		//遍歷結果集授權
		for (AuthFunction authFunction : functionList) {
			info.addStringPermission(authFunction.getCode());
		}

		return info;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM