SSM整合Shiro

本文轉載自【通往架構師的路上】的以下文章

https://blog.csdn.net/caiqing116/article/details/84637699

1.Maven配置

修改pom.xml文件

    <!--Shiro配置-->
	 <dependency>
	      <groupId>org.apache.shiro</groupId>
	      <artifactId>shiro-core</artifactId>
	      <version>1.3.2</version>
	 </dependency>

	 <dependency>
	      <groupId>org.apache.shiro</groupId>
	      <artifactId>shiro-web</artifactId>
	      <version>1.3.2</version>
	 </dependency>

	 <dependency>
	      <groupId>org.apache.shiro</groupId>
	      <artifactId>shiro-spring</artifactId>
	      <version>1.3.2</version>
	 </dependency>

	 <dependency>
	      <groupId>org.apache.shiro</groupId>
	      <artifactId>shiro-ehcache</artifactId>
	      <version>1.3.2</version>
	  </dependency>

2.修改web.xml

在web.xml中增加Shiro過濾器
注意:這裏的filter-name和shiro配置文件中名字保持一致

<!-- 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>/*</url-pattern>  
</filter-mapping>

3.編寫shiro配置文件

編寫applicationContext-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:context="http://www.springframework.org/schema/context" 
	   xmlns:util="http://www.springframework.org/schema/util"
	   xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
		http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.1.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd"
	    default-lazy-init="true">
	
	<description>Spring_Shiro整合配置文件</description>

    <!--1. 配置securityManager安全管理器 -->
    <!-- 
    	SecurityManager:安全管理器;即所有與安全有關的操作都會與SecurityManager交互;
		且它管理着所有Subject;可以看出它是Shiro 的核心,它負責與後邊介紹的其他組件進行交互
     -->
 	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="shiroDbRealm" />
    </bean>
    
    <!--2. 配置 CacheManager. 2.1需要加入 ehcache 的 jar 包及配置文件. -->
    <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"> </bean> 
	
	<!--3.配置realm 自定義的Realm-->
    <!-- 
    	Shiro 從從Realm獲取安全數據(如用戶、角色、權限),就是說SecurityManager要驗證用戶身份,
    	那麼它需要從Realm獲取相應的用戶進行比較以確定用戶身份是否合法;
		也需要從Realm得到用戶相應的角色/權限進行驗證用戶是否能進行操作;
		可以把Realm看成DataSource , 即安全數據源 
	-->
    <bean id="shiroDbRealm" class="com.test.security.ShiroRealm"></bean>
    
    <!--4.配置lifecycleBeanPostProcessor,可以自動調用spring ioc 容器中的shiro bean 的生命週期方法  -->
    <!-- 開啓Shiro註解的Spring配置方式的beans。在lifecycleBeanPostProcessor之後運行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
    
    <!--5. 啓用 IOC 容器中使用 shiro 的註解. 但必須在配置了 LifecycleBeanPostProcessor 之後纔可以使用. -->     
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
          <property name="proxyTargetClass" value="true" />
    </bean>
    
    <!-- Shiro Filter id值和web.xml文件配置的過濾器名稱相同 -->
    <bean id="shiroFilter"
        class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <!-- 登錄頁面 -->
        <property name="loginUrl" value="/jsp/login.jsp" />
        <!-- 登錄成功頁面 -->
        <property name="successUrl" value="/jsp/home.jsp"/>
        <!-- 沒有權限的頁面 -->
        <!-- <property name="unauthorizedUrl" value="/unauthorized.jsp"/> -->
      	<!--  
        	配置哪些頁面需要受保護. 
        	以及訪問這些頁面需要的權限. 
        	1). anon 可以被匿名訪問
        	2). authc 必須認證(即登錄)後纔可能訪問的頁面. 
        	3). logout 登出.
        	4). roles 角色過濾器
        -->
        <property name="filterChainDefinitions">
            <value>
            	<!-- 登錄可匿名訪問 -->
            	/img/**=anon
            	/shirologin/** = anon
            	/shirologout = logout
                <!-- 其他的需要授權訪問authc -->
                /** = authc
            </value>
        </property>
    </bean>

  	<!-- 開啓Shiro註解的Spring配置方式的beans。在lifecycleBeanPostProcessor之後運行 -->
    <bean
        class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>
    
    <!-- shiro爲集成spring -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
            	<!-- 無權限跳轉到登錄頁,可自行定義 -->
                <prop key="org.apache.shiro.authz.UnauthorizedException">/shiro_login</prop>
            </props>
        </property>
    </bean>
</beans>

4.實現Shiro Realm

4.1創建類ShiroRealm

創建包security, 在該包下創建類ShiroRealm, 且繼承AuthorizingRealm

package com.test.security;

import org.springframework.beans.factory.annotation.Autowired;
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 com.test.service.AccountException;
import com.test.service.UsersService;


public class ShiroRealm extends AuthorizingRealm{

@Autowired
private UsersService usersService;

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		return null;
	}

	/**
	 * 授權認證
	 */
	@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
		String username = usernamePasswordToken.getUsername();
		String password = String.valueOf(usernamePasswordToken.getPassword());
		//開始根據用戶名和密碼查找用戶
		Users user = usersService.selectByUsername(username);
        if(user == null) {
				throw new AccountException("賬號或密碼錯誤");
		} 
        if(!password.equals(basicUser.getPassword())) {
				throw new AccountException("賬號或密碼錯誤");
		 }
		SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getUsername(),user.getAccount());
		return simpleAuthenticationInfo;
	}

}

4.2創建AccountException

package com.test.service;

import org.apache.shiro.authc.AuthenticationException;

public class AccountException extends AuthenticationException {
	private static final long serialVersionUID = 6423461337343398987L;
	public AccountException(String msg) {
		super(msg);
	}
}

5實現登錄功能

5.1實現相關的Controller

執行登錄操作的時候,如果處於未登錄狀態執行currentUser.login(usernamePasswordToken);跳轉到ShiroRealm的doGetAuthenticationInfo方法執行授權認證

package com.test.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.test.commons.EncryptKit;
import com.test.commons.ResultModel;
import com.test.service.AccountException;

@Controller
public class Login_Shiro_Controller {


    // 登錄
	@RequestMapping("/shirologin")
	@ResponseBody
	public ResultModel shirologin(String username, String password) {
     		try {
			Subject currentUser = SecurityUtils.getSubject();
			// 未認證登錄
			if (!currentUser.isAuthenticated()) {
				// 密碼進行MD5加密
 				UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, EncryptKit.MD5(password));
 				// 認證登錄
				currentUser.login(usernamePasswordToken);
			}
		} catch (AuthenticationException e) {
			if (e instanceof AccountException) {
				return new ResultModel(1, "賬號或密碼錯誤");
			}
		}
		return new ResultModel(0, "登錄成功");
	}

	// 退出
	@RequestMapping("/shirologout")
	public String shirologout() {
		try {
			Subject subject = SecurityUtils.getSubject();
			if (subject.isAuthenticated()) {
				subject.logout();
				// 退出成功,回到登錄頁面
				return "redirect:/jsp/login.jsp";
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "redirect:/goHome";
	}
	
	
    // 進入主頁,登錄成功後就進入主頁
	@RequestMapping("/goHome")
	public String home() {
		return "/jsp/home.jsp";
	}

}

5.2加密工具類EncryptKit

package com.test.commons;

import java.security.MessageDigest;

public class EncryptKit {
	private static String MD5 = "MD5";
	private static String SHA = "SHA-1";
    // MD5加密
	public static String MD5(String string) {
		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
		try {
			byte[] older = string.getBytes();
			MessageDigest md5 = MessageDigest.getInstance(MD5);
			md5.update(older);
			byte[] newer = md5.digest();
			int j = newer.length;
			char[] chars = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte b = newer[i];
				chars[k++] = hexDigits[b >>> 4 & 0xf];
				chars[k++] = hexDigits[b & 0xf];
			}
			return new String(chars);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

     // SHA-1加密
	public static String SHA(String info) {
		try {
			MessageDigest md = MessageDigest.getInstance(SHA);
			md.update(info.getBytes());
			byte[] digest = md.digest();

			StringBuffer hexstr = new StringBuffer();
			String shaHex = "";
			for (int i = 0; i < digest.length; i++) {
				shaHex = Integer.toHexString(digest[i] & 0xFF);
				if (shaHex.length() < 2) {
					hexstr.append(0);
				}
				hexstr.append(shaHex);
			}
			return hexstr.toString();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
}

5.3回傳結果類ResultModel

package com.test.commons;

public class ResultModel {
	// 返回值 0成功 1失敗
	private Integer resultCode;
	// 返回的數據
	private Object data;
	// 返回的信息
	private String msg;

	public ResultModel(Integer resultCode, String msg) {
		super();
		this.resultCode = resultCode;
		this.msg = msg;
	}

	public ResultModel(Integer resultCode, Object data, String msg) {
		super();
		this.resultCode = resultCode;
		this.data = data;
		this.msg = msg;
	}

	public Integer getResultCode() {
		return resultCode;
	}

	public void setResultCode(Integer resultCode) {
		this.resultCode = resultCode;
	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}
}

6.登錄頁面

編寫登錄界面 /jsp/login.jsp

<%@page import="org.apache.shiro.SecurityUtils"%>
<%@page import="org.apache.shiro.subject.Subject"%>
<%@ page language="java"  pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%
	//如果登錄成功,則直接跳轉到主頁
	Subject subject = SecurityUtils.getSubject();
	if(subject.isAuthenticated()){
		response.sendRedirect("/goHome");
	}
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>shiro_登錄</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="keywords" content="" />
<script type="application/x-javascript"> addEventListener("load", function() { setTimeout(hideURLbar, 0); }, false); function hideURLbar(){ window.scrollTo(0,1); } </script>
<script type="text/javascript" src="../js/jquery.min.js"></script>
</head>
<body>
	 賬號:  <br/>
	<input id="name"  type="text" ><br/>
	
	 密碼: <br/>
	<input id="pwd" type="text" ><br/>
	
	<input type="button"  value="登錄" onclick="login()"><br/>
</body>
<script type="text/javascript">
function login(){
	var username = document.getElementById("name");
	var password = document.getElementById("pwd");
	$.ajax({
                url: "/shirologin",
                dataType: "json",
                type:"POST",
              data:{"username":username.value,"password":password.value},  
                success: function (data) {  
                     if(data.resultCode == 0){
                    	 window.location.href = "/goHome";
                     }else{
                    	 alert(data.msg);
                     }
                }
            });
}
</script>
</html>

7.登錄成功頁面

編寫登錄成功界面 /jsp/home.jsp

<%@ page language="java"  pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登錄成功</title>
</head>
<body>
	<h1>登錄成功</h1>
	<h2>
		<input type="button" value="退出" onclick='window.location.href="/shirologout"'>
	</h2> 
</body>
</html>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章