• 基于cookie使用过滤器实现客户每次访问自登陆一次


    原创声明:本文为本人原创作品,绝非他处摘取,转载请联系博主

    相信大家在各大网站都会遇到,登录时,在登录框出现下次免登陆/一个月免登陆的类似选项,本次博文就是讲解如何实现,在这记录一下,也算是做个备忘录合集,如果文中有错,欢迎大家指出

    为啥说自登陆一次呢,因为当访问某个页面时,如果第一次自动登录失败时,你下次刷新访问时还再次走自动登录流程,就会出现死循环。

    本篇博文代码示例框架为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";
    	}
    }

    到此,该功能示例讲解全部完成,如有不对的地方,欢迎大家在评论区指出。

  • 相关阅读:
    C#在window服务配置Log4Net.dll
    致于即将逝去的2108年,2019年您好
    关于:未能加载文件或程序集“ICSharpCode.SharpZipLib”或它的某一个依赖项异常的解决方案
    Vs 中关于项目中的某 NuGet 程序包还原失败:找不到“xxx”版本的程序包“xxx”
    Git分布式版本控制器常用命令和使用
    微信公众平台网页登录授权多次重定向跳转,导致code使用多次问题
    Visual Studio高效实用的扩展工具、插件
    关于微信企业付款到零钱X509Certificate2读取证书信息,发布到服务器访问不到的解决方案
    关于ASP.NET MVC 项目在本地vs运行响应时间过长无法访问时,解决方法!
    彻底关闭windows10自动更新解决方案
  • 原文地址:https://www.cnblogs.com/zhaixiajiao/p/6895284.html
Copyright © 2020-2023  润新知