基於cookie使用過濾器實現客戶每次訪問自登陸一次

来源:http://www.cnblogs.com/zhaixiajiao/archive/2017/06/05/6895284.html
-Advertisement-
Play Games

原創聲明:本文為本人原創作品,絕非他處摘取,轉載請聯繫博主 相信大家在各大網站都會遇到,登錄時,在登錄框出現下次免登陸/一個月免登陸的類似選項,本次博文就是講解如何實現,在這記錄一下,也算是做個備忘錄合集,如果文中有錯,歡迎大家指出 為啥說自登陸一次呢,因為當訪問某個頁面時,如果第一次自動登錄失敗時 ...


原創聲明:本文為本人原創作品,絕非他處摘取,轉載請聯繫博主

相信大家在各大網站都會遇到,登錄時,在登錄框出現下次免登陸/一個月免登陸的類似選項,本次博文就是講解如何實現,在這記錄一下,也算是做個備忘錄合集,如果文中有錯,歡迎大家指出

為啥說自登陸一次呢,因為當訪問某個頁面時,如果第一次自動登錄失敗時,你下次刷新訪問時還再次走自動登錄流程,就會出現死迴圈。

本篇博文代碼示例框架為Spring MVC,下麵就講解實現該功能的需要掌握哪些知識:cookies與過濾器

1.cookies

何為Cookies:Cookies為 Web 應用程式保存用戶相關信息提供了一種有用的方法。例如,當用戶訪問您的站點時,您可以利用 Cookie 保存用戶首選項或其他信息,這樣,當用戶下次再訪問您的站點時,應用程式就可以檢索以前保存的信息。

我們看一下是如何保存cookies和如何刪除cookies

  • 保存cookies
String newUserName = null;
try {
	newUserName = URLEncoder.encode(username, "UTF-8");//把用戶名轉碼,防止用戶名是中文,cookies保存中文取出會亂碼
} catch (UnsupportedEncodingException e) {
	e.printStackTrace();
}
Cookie nameCookie = new Cookie("username", newUserName);
String pwdMd5Cook = MD5Util.MD5(Pwd);
Cookie pwdCookie = new Cookie("pwd", pwdMd5Cook);// 保存加密後的密碼
nameCookie.setMaxAge(60 * 60 * 24 * 365);// 用戶名保存一年
pwdCookie.setMaxAge(60 * 60 * 24 * 30);// 密碼保存30天
// 發送Cookie信息到瀏覽器
response.addCookie(nameCookie);
response.addCookie(pwdCookie);

刪除cookies,刪除很簡單,但值得註意的時,刪除cookies,跟保存cookies一定要在同一個控制層,不然會找不到保存的cookies,導致刪除不了

Cookie cookie = new Cookie("pwd", null);
cookie.setMaxAge(0);// 刪除密碼cookie
response.addCookie(cookie);

2.Filter-過濾器

Filter也稱之為過濾器,它是Servlet技術中最實用的技術,Web開發人員通過Filter技術,對web伺服器管理的所有web資源:例如Jsp, Servlet, 靜態圖片文件或靜態 html 文件等進行攔截,從而實現一些特殊的功能。例如實現URL級別的許可權訪問控制、過濾敏感辭彙、壓縮響應信息等一些高級功能。

實現方法:繼承Filter介面,並實現其doFilter方法。在web.xml文件中對編寫的filter類進行註冊,並設置它所能攔截的資源

<filter>指定一個過濾器。
<filter-name>用於為過濾器指定一個名字,該元素的內容不能為空。
<filter-class>元素用於指定過濾器的完整的限定類名。
<init-param>元素用於為過濾器指定初始化參數,它的子元素<param-name>指定參數的名字,<param-value>指定參數的值。
在過濾器中,可以使用FilterConfig介面對象來訪問初始化參數。
<filter-mapping>元素用於設置一個 Filter 所負責攔截的資源。一個Filter攔截的資源可通過兩種方式來指定:Servlet 名稱和資源訪問的請求路徑
<filter-name>子元素用於設置filter的註冊名稱。該值必須是在<filter>元素中聲明過的過濾器的名字
<url-pattern>設置 filter 所攔截的請求路徑(過濾器關聯的URL樣式)
<servlet-name>指定過濾器所攔截的Servlet名稱。
<filter>
	<filter-name>suicaiFilter</filter-name>
	<filter-class>com.suicai.filter.suicaiFilter</filter-class>
</filter>

<filter-mapping>
	<filter-name>suicaiFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

下麵看一下實際應用代碼:

public class suicaiFilter implements Filter {
	@Override
	public void destroy() {
	}
	@Override
	public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req=(HttpServletRequest)request;
		HttpServletResponse res=(HttpServletResponse)response;
		HttpSession session = req.getSession();
		String requestURI = req.getRequestURI();
		String param = req.getQueryString();
		String url = req.getServletPath();
		if(param!=null){
			url = url+"?"+param;
		}
		if(requestURI.contains("js") || requestURI.contains("css") ||  requestURI.contains("images")){
			//不過濾css,js,images等靜態資源
			chain.doFilter(request, response);
		}else if(requestURI.contains("/info/")||requestURI.contains("/gys/")){
			//過濾前臺訪問頁面,跟前臺個人中心(供應商後臺),自動登錄一次,登錄不成功不進行操作,個人中心登錄不成功,則跳到登錄頁面
			ProviderInfo providerInfo = (ProviderInfo) session.getAttribute("providerInfo_gys");
			String IsAutomaticLogin = (String) session.getAttribute("IsAutomaticLogin");//是否已經走過自動登錄流程標識
			if(requestURI.contains("/info/") && !requestURI.contains("/login")){
				//訪問門戶等不需要必須登錄的(登錄除外),只嘗試登錄一次,如果不成功,不進行操作
				if(providerInfo==null && IsAutomaticLogin == null){
					req.getSession().setAttribute("goURL", url);
					res.sendRedirect(req.getContextPath() + "/common/automaticLogin");
				}else if(providerInfo==null && IsAutomaticLogin != null ){
					chain.doFilter(request, response);
				}else{
					chain.doFilter(request, response);
				}
			}else if(requestURI.contains("/gys/")){//訪問個人中心,自登陸一次,不成功跳轉到登錄頁面
				if(providerInfo==null && IsAutomaticLogin == null){
					req.getSession().setAttribute("goURL", url);
					res.sendRedirect(req.getContextPath() + "/common/automaticLogin");
				}else if(providerInfo==null && IsAutomaticLogin != null ){
					session.setAttribute("redirectUrl", url);
					res.sendRedirect(req.getContextPath() + "/login.jsp?redirectUrl="+url);
				}else{
					chain.doFilter(request, response);
				}
			}else{
				chain.doFilter(request, response);
			}
		}else{
			//不過濾
			chain.doFilter(request, response);
		}
	}
	@Override
	public void init(FilterConfig arg0) throws ServletException {
	}
}

從代碼中可知,需要一個是否已經自動登錄過的標識(IsAutomaticLogin),該標識是在走自動登錄時(不管成不成功)保存起來的

3.結合上面提供知識,下麵為整體代碼展示,如發現不對地方,歡迎大家指出

@Controller
@RequestMapping("/common")
public class CommonController{
	/**
	 * 自動登錄方法
	 * @param request
	 * @param response
	 * @param username
	 * @param pwd
	 * @param ProviderInfo 供應商賬戶信息model
	 * @return
	 */
	@RequestMapping("/automaticLogin")
	public String automaticLogin(HttpServletRequest request,ServletResponse response,@CookieValue(value = "username", required = false) String username,@CookieValue(value = "pwd", required = false) String pwd,ProviderInfo ProviderInfo) {
		// 保存需求登錄前的鏈接
		String goURL = (String) session.getAttribute("goURL");
		if (username == null) {//cookies中沒有用戶名,肯定不需要自動登錄
			session.setAttribute("IsAutomaticLogin", "0");
			return "redirect:" + goURL;
		} else {
			try {
				username = URLDecoder.decode(username, "UTF-8");//轉義,防止中文
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		// cookie失效 session一定為空,因為登錄時,一定會把用戶名保存在cookie中
		if ("".equals(username) || username == null) {// 使用session登錄不了,不進行任何操作,不在進入這個方法
			session.setAttribute("IsAutomaticLogin", "0");
			return "redirect:" + goURL;
		} else {
			// cookie中沒有密碼,判斷session為不為空,如果為空,說明沒有登錄,如果不為空,說明,用戶是選擇不記住密碼登錄(所以cookie中沒有密碼)
			if ("".equals(pwd) || pwd == null) {
				ProviderInfo customer1 = (ProviderInfo) session.getAttribute("providerInfo_gys");
				if (customer1 == null) {// 使用session登錄不了,不進行任何操作,不在進入這個方法
					session.setAttribute("IsAutomaticLogin", "0");
					return "redirect:" + goURL;
				} else {
					// 已經登錄,不再進入這個方法
					return "redirect:" + goURL;
				}
			} else {
				// cookie中有密碼,判斷session為不為空,如果為空,說明沒有登錄,如果不為空,說明已經登錄
				ProviderInfo customer1 = (ProviderInfo) session.getAttribute("providerInfo_gys");
				if (customer1 == null) {// 當前沒有登錄,調用cookies中的用戶名跟密碼進行登錄
					// 進行自動登錄操作,登錄成功後返回原來頁面
					ProviderInfo customer3 = ValidateDate(username);
					customer3.setPwd(pwd);
					customer3.setAccountType(6);
					ProviderInfo customer2 = infoService.login(customer3);//調用登錄方法
					if (customer2 == null) {// 自動登錄失敗,不再進入這個方法
						session.setAttribute("IsAutomaticLogin", "0");
						return "redirect:" + goURL;
					} else {
						// 登陸成功保存客戶信息到session
						session.setAttribute("providerInfo_gys",customer2);
						return "redirect:" + goURL;
					}
				} else {
					return "redirect:" + goURL;
				}
			}
		}
	}
	/**
	 * 用戶登陸
	 * @param request
	 * @param response
	 * @param cus
	 * @return
	 */
	@RequestMapping("/UserLogin")
	@ResponseBody
	public Map<String, Object> goLogin(HttpServletRequest request,HttpServletResponse response,@ModelAttribute("ProviderInfo") ProviderInfo cus) {
		/*省略一些邏輯判斷*/
		cus.setPwd(MD5Util.MD5(Pwd));
		ProviderInfo providerInfo = infoService.login(cus);
		Map<String, Cookie> cookieMap = new HashMap<String, Cookie>();
		if (providerInfo == null) {
			// 登陸失敗,重新跳轉到登陸頁面
			map.put("error", "密碼錯誤");
			return map;
		}else{
			String newUserName = null;
			if (remember_me.equals("1")) {// 有選擇一個月免登錄
				try {
					newUserName = URLEncoder.encode(username, "UTF-8");
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
				Cookie nameCookie = new Cookie("username", newUserName);
				String pwdMd5Cook = MD5Util.MD5(Pwd);
				Cookie pwdCookie = new Cookie("pwd", pwdMd5Cook);// 保存加密後的密碼+"create"
				nameCookie.setMaxAge(60 * 60 * 24 * 365);// 用戶名保存一年
				pwdCookie.setMaxAge(60 * 60 * 24 * 30);// 密碼保存30天
				// 發送Cookie信息到瀏覽器
				response.addCookie(nameCookie);
				response.addCookie(pwdCookie);
				session.setAttribute("IsAutomaticLogin",null);
			}else{//沒有選擇,刪除上次可能已經選擇自動登錄時的密碼
				Cookie[] cookies = request.getCookies();
				if (null != cookies) {
					for (Cookie cookie : cookies) {
						cookieMap.put(cookie.getName(), cookie);
					}
				}
				if (cookies != null) {
					for (int i = 0; i < cookies.length; i++) {
						if (cookieMap.containsKey("pwd")) {
							Cookie cookie = new Cookie("pwd", null);
							cookie.setMaxAge(0);// 刪除密碼cookie
							response.addCookie(cookie);
						}
					}
				}
			}
			// 登陸成功,保存當前user信息,保存客戶信息到session
			map.put("ProviderInfo", providerInfo);
			map.put("goURL", session.getAttribute("goURL"));
			session.setAttribute("providerInfo_gys", providerInfo);
			return map;
		}else {
			map.put("error", "該供應商賬號不存在");
			return map;
		}
	}
	/**
	 * 註銷
	 * @return
	 */
	@RequestMapping("/logout")
	public String logout(HttpServletResponse response) {
		Map<String, Cookie> cookieMap = new HashMap<String, Cookie>();
		Cookie[] cookies = request.getCookies();
		if (null != cookies) {
			for (Cookie cookie : cookies) {
				cookieMap.put(cookie.getName(), cookie);
			}
		}
		if (cookies != null) {
			for (int i = 0; i < cookies.length; i++) {
				if (cookieMap.containsKey("pwd")) {
					Cookie cookie = new Cookie("pwd", null);
					cookie.setMaxAge(0);// 刪除密碼cookie
					response.addCookie(cookie);
				}
			}
		}
		session.setAttribute("providerInfo_gys", null);
		return "/index";
	}
}

到此,該功能示例講解全部完成,如有不對的地方,歡迎大家在評論區指出。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 分享一個由於KDE未被正確安裝導致ubuntu 無法用ssh正常訪問的問題解決過程 ...
  • 大家在學習正則表達式之前,首先要明確一點,並把它牢牢記在心裡,那就是: 在linux中,通配符是由shell解釋的,而正則表達式則是由命令解釋的,不要把二者搞混了。切記!!! 通常有三種文本處理工具/命令:grep、sed、awk,它們三者均可以解釋正則。下麵我就為大家介紹grep命令的使用方法。 ...
  • 一.介紹 二.服務端配置 1.關閉系統防火牆和selinux 查看系統防火牆的狀態,可以看到防火牆是開著的 [root@bogon ~] systemctl status firewalld ● firewalld.service firewalld dynamic firewall daemon ...
  • . NET Core 從2016年6月28日發佈,過去了將近一年的時間,但是在工作中發現大家對.net core的接受程度並不高,這隻是一個感覺,俗話說“沒有調查就沒有發言權”, 這兩天通過微信小程式在微信群里做了一個調查,參與的人數大概230人,從結果看大家都在等待.NET Core 2.0, 期 ...
  • 淺談orm 記得四年前在學校第一次接觸到 Ling to Sql,那時候瞬間發現不用手寫sql語句是多麼的方便,後面慢慢的接觸了許多orm框架,像 EF,Dapper,Hibernate,ServiceStack.OrmLite 等。當然每種orm都有各自的優勢,也有不足的地方。園子里也有很多大神開 ...
  • python2.7的編碼格式不再是ASCII碼,直接就是UTF-8. 導入sys模塊,通過getdefaultencoding方法可以查看編碼格式。 因此,python2.7解決中文字元的編碼問題可以直接聲明編碼格式,不再通過麻煩的decode和encode進行轉換。 此處仍然需要在中文字元前加入u ...
  • 網上商城實戰3 今日任務 完成購物模塊的功能 完成訂單模塊的功能 1.1 購物模塊: 1.1.1 功能演示: 商品詳情: 購物車模塊: 1.1.2 代碼實現: 1.在商品詳情的頁面中點擊【加入購物車】鏈及. 2.提交到Servlet中: * 提交購買的商品的數量. * 提交購買的商品的ID. 3.將 ...
  • 一、後臺日期類型解析到前端 1.在springmvc的配置文件中添加這個.annotation-driven在配置文件中只配置一次 (此方法全局作用)<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springfra ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...