基于Cookie使用過濾器實現(xiàn)客戶每次訪問只登錄一次
相信大家在各大網(wǎng)站都會遇到,登錄時,在登錄框出現(xiàn)下次免登陸/一個月免登陸的類似選項,本文就是講解如何實現(xiàn),在這記錄一下,也算是做個備忘錄合集,如果文中有錯,歡迎大家指出
為啥說自登陸一次呢,因為當訪問某個頁面時,如果第一次自動登錄失敗時,你下次刷新訪問時還再次走自動登錄流程,就會出現(xiàn)死循環(huán)。
本文代碼示例框架為Spring MVC,下面就講解實現(xiàn)該功能的需要掌握哪些知識:cookies與過濾器
1.cookies
何為Cookies:Cookies為 Web 應用程序保存用戶相關(guān)信息提供了一種有用的方法。例如,當用戶訪問您的站點時,您可以利用 Cookie 保存用戶首選項或其他信息,這樣,當用戶下次再訪問您的站點時,應用程序就可以檢索以前保存的信息。
我們看一下是如何保存cookies和如何刪除cookies
保存cookies
String newUserName = null;
try {
newUserName = URLEncoder.encode(username, "UTF-8");//把用戶名轉(zhuǎn)碼,防止用戶名是中文,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天
// 發(fā)送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技術(shù)中最實用的技術(shù),Web開發(fā)人員通過Filter技術(shù),對web服務器管理的所有web資源:例如Jsp, Servlet, 靜態(tài)圖片文件或靜態(tài) html 文件等進行攔截,從而實現(xiàn)一些特殊的功能。例如實現(xiàn)URL級別的權(quán)限訪問控制、過濾敏感詞匯、壓縮響應信息等一些高級功能。
實現(xiàn)方法:繼承Filter接口,并實現(xiàn)其doFilter方法。在web.xml文件中對編寫的filter類進行注冊,并設置它所能攔截的資源
<filter>指定一個過濾器。 <filter-name>用于為過濾器指定一個名字,該元素的內(nèi)容不能為空。 <filter-class>元素用于指定過濾器的完整的限定類名。 <init-param>元素用于為過濾器指定初始化參數(shù),它的子元素<param-name>指定參數(shù)的名字,<param-value>指定參數(shù)的值。 在過濾器中,可以使用FilterConfig接口對象來訪問初始化參數(shù)。 <filter-mapping>元素用于設置一個 Filter 所負責攔截的資源。一個Filter攔截的資源可通過兩種方式來指定:Servlet 名稱和資源訪問的請求路徑 <filter-name>子元素用于設置filter的注冊名稱。該值必須是在<filter>元素中聲明過的過濾器的名字 <url-pattern>設置 filter 所攔截的請求路徑(過濾器關(guān)聯(lián)的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等靜態(tài)資源
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");//是否已經(jīng)走過自動登錄流程標識
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/")){//訪問個人中心,自登陸一次,不成功跳轉(zhuǎn)到登錄頁面
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 {
}
}
從代碼中可知,需要一個是否已經(jīng)自動登錄過的標識(IsAutomaticLogin),該標識是在走自動登錄時(不管成不成功)保存起來的
3.結(jié)合上面提供知識,下面為整體代碼展示,如發(fā)現(xiàn)不對地方,歡迎大家指出
@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");//轉(zhuǎn)義,防止中文
} 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 {
// 已經(jīng)登錄,不再進入這個方法
return "redirect:" + goURL;
}
} else {
// cookie中有密碼,判斷session為不為空,如果為空,說明沒有登錄,如果不為空,說明已經(jīng)登錄
ProviderInfo customer1 = (ProviderInfo) session.getAttribute("providerInfo_gys");
if (customer1 == null) {// 當前沒有登錄,調(diào)用cookies中的用戶名跟密碼進行登錄
// 進行自動登錄操作,登錄成功后返回原來頁面
ProviderInfo customer3 = ValidateDate(username);
customer3.setPwd(pwd);
customer3.setAccountType(6);
ProviderInfo customer2 = infoService.login(customer3);//調(diào)用登錄方法
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) {
// 登陸失敗,重新跳轉(zhuǎn)到登陸頁面
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天
// 發(fā)送Cookie信息到瀏覽器
response.addCookie(nameCookie);
response.addCookie(pwdCookie);
session.setAttribute("IsAutomaticLogin",null);
}else{//沒有選擇,刪除上次可能已經(jīng)選擇自動登錄時的密碼
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";
}
}
以上所述是小編給大家介紹的基于Cookie使用過濾器實現(xiàn)客戶每次訪問只登錄一次,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Win 2000下ASP.NET開發(fā)環(huán)境的配置
Win 2000在默認情況下是不支持ASP.NET的。必須對它進行一個環(huán)境的配置,本文將圖文介紹,在配置過程中遇到困難的朋友可以參考下2012-11-11
詳解ASP.NET Core 之 Identity 入門(一)
本篇文章主要介紹了ASP.NET Core 之 Identity 入門,主要負責對用戶的身份進行認證,有興趣的可以了解一下。2016-12-12
ADO.NET獲取數(shù)據(jù)(DataSet)同時獲取表的架構(gòu)實例
下面小編就為大家分享一篇ADO.NET獲取數(shù)據(jù)(DataSet)同時獲取表的架構(gòu)實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12
ajaxToolkit:ModalPopupExtender演示及實現(xiàn)代碼
ajaxToolkit:ModalPopupExtender可以讓用戶模擬新開一個窗口,就是在模擬新開窗口作多項選項的功能,感興趣的朋友可以了解下,希望此文對你有所幫助2013-01-01
ASP.NET將Session保存到數(shù)據(jù)庫中的方法
因為ASP.NET中Session的存取機制與ASP相同,都是保存在進行中, 一旦進程崩潰,所有Session信息將會丟失,所以我采取了將Session信息保存到SQL Server中,盡管還有其它的2013-08-08
ASP.NET批量操作基于原生html標簽的無序列表的三種方法
無序列表被大量使用,ASP.NET雖然內(nèi)置了BulletedList控件,用于創(chuàng)建和操作無序列表,但感覺不太好用2014-09-09

