精华内容
下载资源
问答
  • 前言 网络早期最大问题之一是如何管理状态。简而言之,服务器无法知道个请求是否来自同一个浏览器。当时最简单方法是在请求时,在页面插入一些参数,并...存储数据,当用户访问了某个网站(网页时候...

    前言

     网络早期最大的问题之一是如何管理状态。简而言之,服务器无法知道两个请求是否来自同一个浏览器。当时最简单的方法是在请求时,在页面中插入一些参数,并在下一个请求中传回参数。这需要使用包含参数的隐藏的表单,或者作为URL参数的一部分传递。这两个解决方案都手动操作,容易出错。cookie出现来解决这个问题。
    

    作用

    cookie是纯文本,没有可执行代码。存储数据,当用户访问了某个网站(网页)的时候,我们就可以通过cookie来向访问者电脑上存储数据,或者某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)
    

    如何工作

      当网页要发http请求时,浏览器会先检查是否有相应的cookie,有则自动添加在request header中的cookie字段中。这些是浏览器自动帮我们做的,而且每一次http请求浏览器都会自动帮我们做。这个特点很重要,因为这关系到“什么样的数据适合存储在cookie中”。
    

    存储在cookie中的数据,每次都会被浏览器自动放在http请求中,如果这些数据并不是每个请求都需要发给服务端的数据,浏览器这设置自动处理无疑增加了网络开销;但如果这些数据是每个请求都需要发给服务端的数据(比如身份认证信息),浏览器这设置自动处理就大大免去了重复添加操作。所以对于那种设置“每次请求都要携带的信息(最典型的就是身份认证信息)”就特别适合放在cookie中,其他类型的数据就不适合了。

    特征

    不同的浏览器存放的cookie位置不一样,也是不能通用的。

    cookie的存储是以域名形式进行区分的,不同的域下存储的cookie是独立的。

    我们可以设置cookie生效的域(当前设置cookie所在域的子域),也就是说,我们能够操作的cookie是当前域以及当前域下的所有子域

    一个域名下存放的cookie的个数是有限制的,不同的浏览器存放的个数不一样,一般为20个。

    每个cookie存放的内容大小也是有限制的,不同的浏览器存放大小不一样,一般为4KB。

    cookie也可以设置过期的时间,默认是会话结束的时候,当时间到期自动销毁

    设置
    客户端设置

    document.cookie = ‘名字=值’;

    document.cookie = ‘username=cfangxu;domain=baike.baidu.com’//并且设置了生效域
    注意:客户端可以设置cookie 的下列选项:expires、domain、path、secure(有条件:只有在https协议的网页中,客户端设置secure类型的 cookie 才能成功),但无法设置HttpOnly选项。

    服务器端设置

    不管你是请求一个资源文件(如 html/js/css/图片),还是发送一个ajax请求,服务端都会返回response。而response header中有一项叫set-cookie,是服务端专门用来设置cookie的。

    Set-Cookie 消息头是一个字符串,其格式如下(中括号中的部分是可选的):

    Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
    注意:一个set-Cookie字段只能设置一个cookie,当你要想设置多个 cookie,需要添加同样多的set-Cookie字段。

    服务端可以设置cookie 的所有选项:expires、domain、path、secure、HttpOnly

    通过 Set-Cookie 指定的这些可选项只会在浏览器端使用,而不会被发送至服务器端。

    读取
    我们通过document.cookie来获取当前网站下的cookie的时候,得到的字符串形式的值,它包含了当前网站下所有的cookie(为避免跨域脚本(xss)攻击,这个方法只能获取非 HttpOnly 类型的cookie)。它会把所有的cookie通过一个分号+空格的形式串联起来,例如 username=chenfangxu;job=coding

    修改cookie
    要想修改一个cookie,只需要重新赋值就行,旧的值会被新的值覆盖。但要注意一点,在设置新cookie时,path/domain这几个选项一定要旧cookie 保持一样。否则不会修改旧值,而是添加了一个新的 cookie。

    删除
    把要删除的cookie的过期时间设置成已过去的时间,path/domain/这几个选项一定要旧cookie 保持一样。

    注意
    如果只设置一个值,那么算cookie中的value; 设置的两个cookie,key值如果设置的相同,下面的也会把上面的覆盖。

    cookie的属性(可选项)
    过期时间
    如果我们想长时间存放一个cookie。需要在设置这个cookie的时候同时给他设置一个过期的时间。如果不设置,cookie默认是临时存储的,当浏览器关闭进程的时候自动销毁。

    注意:document.cookie = ‘名称=值;expires=’ + GMT(格林威治时间)格式的日期型字符串;

    一般设置天数: newDate().setDate(oDate.getDate()+5);比当前时间多5天

    一个设置cookie时效性的例子:

    function setCookie(c_name, value, expiredays){
    var exdate=new Date();
    exdate.setDate(exdate.getDate() + expiredays);
    document.cookie=c_name+ “=” + escape(value) + ((expiredays==null) ? “” : “;expires=”+exdate.toGMTString())
    }
    使用方法;
    setcookie(‘username’,‘zxy’,30);
    expires 是 http/1.0协议中的选项,在新的http/1.1协议中expires已经由 max-age 选项代替,两者的作用都是限制cookie 的有效时间。expires的值是一个时间点(cookie失效时刻= expires),而max-age 的值是一个以秒为单位时间段(cookie失效时刻= 创建时刻+ max-age)。
    另外,max-age 的默认值是 -1(即有效期为 session );max-age有三种可能值:负数、0、正数。

    负数:有效期session;

    0:删除cookie;

    正数:有效期为创建时刻+ max-age

    cookie的域概念

      domain指定了 cookie 将要被发送至哪个或哪些域中。默认情况下,domain 会被设置为创建该 cookie 的页面所在的域名,所以当给相同域名发送请求时该 cookie 会被发送至服务器。
     浏览器会把 domain 的值与请求的域名做一个尾部比较(即从字符串的尾部开始比较),并将匹配的 cookie 发送至服务器
    

    document.cookie = “username=cfangxu;path=/;domain=qq.com
    如上:“www.qq.com" 与 “sports.qq.com” 公用一个关联的域名"qq.com",我们如果想让 “sports.qq.com” 下的cookie被 “www.qq.com” 访问,我们就需要用到 cookie 的domain属性,并且需要把path属性设置为 “/”。
    服务端设置
    Set-Cookie:username=zxy;path=/;domain=qq.com;
    注:一定的是同域之间的访问,不能把domain的值设置成非主域的域名。

    cookie的路径概念(path选项)
    cookie 一般都是由于用户访问页面而被创建的,可是并不是只有在创建 cookie 的页面才可以访问这个 cookie。 因为安全方面的考虑,默认情况下,只有与创建 cookie 的页面在同一个目录或子目录下的网页才可以访问。即path属性可以为服务器特定文档指定cookie,这个属性设置的url且带有这个前缀的url路径都是有效的。
    客户端设置

    最常用的例子就是让 cookie 在根目录下,这样不管是哪个子页面创建的 cookie,所有的页面都可以访问到了。

    document.cookie=“username=zxy;path=/”

    服务端设置

    Set-Cookie:name=zxy;path=/blog’

      如上设置:path 选项值会与 /blog,/blogrool 等等相匹配;任何以 /blog 开头的选项都是合法的。需要注意的是,只有在 domain 选项核实完毕之后才会对 path 属性进行比较。path 属性的默认值是发送 Set-Cookie 消息头所对应的 URL 中的 path 部分。
    

    domain和path总结

    domain是域名,path是路径,两者加起来就构成了 URL,domain和path一起来限制 cookie 能被哪些 URL 访问。

    所以domain和path2个选项共同决定了cookie何时被浏览器自动添加到请求头部中发送出去。如果没有设置这两个选项,则会使用默认值。domain的默认值为设置该cookie的网页所在的域名,path默认值为设置该cookie的网页所在的目录。

    cookie的安全性(secure选项)

      通常 cookie 信息都是使用HTTP连接传递数据,这种传递方式很容易被查看,所以 cookie 存储的信息容易被窃取。假如 cookie 中所传递的内容比较重要,那么就要求使用加密的数据传输。
    
      secure选项用来设置cookie只在确保安全的请求中才会发送。当请求是HTTPS或者其他安全协议时,包含 secure 选项的 cookie 才能被发送至服务器。
    

    document.cookie="username=zxy;secure’

    把cookie设置为secure,只保证 cookie 与服务器之间的数据传输过程加密,而保存在本地的 cookie文件并不加密。就算设置了secure 属性也并不代表他人不能看到你机器本地保存的 cookie 信息。机密且敏感的信息绝不应该在 cookie 中存储或传输,因为 cookie 的整个机制原本都是不安全的。

    注意:如果想在客户端即网页中通过 js 去设置secure类型的 cookie,必须保证网页是https协议的。在http协议的网页中是无法设置secure类型cookie的。

    httpOnly
    这个选项用来设置cookie是否能通过 js 去访问。默认情况下,cookie不会带httpOnly选项(即为空),所以默认情况下,客户端是可以通过js代码去访问(包括读取、修改、删除等)这个cookie的。当cookie带httpOnly选项时,客户端则无法通过js代码去访问(包括读取、修改、删除等)这个cookie。

    在客户端是不能通过js代码去设置一个httpOnly类型的cookie的,这种类型的cookie只能通过服务端来设置。

    cookie的编码

    cookie其实是个字符串,但这个字符串中等号、分号、空格被当做了特殊符号。所以当cookie的 key 和 value 中含有这3个特殊字符时,需要对其进行额外编码,一般会用escape进行编码,读取时用unescape进行解码;当然也可以用encodeURIComponent/decodeURIComponent或者encodeURI/decodeURI,查看关于编码的介绍

    第三方cookie

    通常cookie的域和浏览器地址的域匹配,这被称为第一方cookie。那么第三方cookie就是cookie的域和地址栏中的域不匹配,这种cookie通常被用在第三方广告网站。为了跟踪用户的浏览记录,并且根据收集的用户的浏览习惯,给用户推送相关的广告。
    关于第三方cookie和cookie的安全问题可以查看

    localStorage(本地存储)
    HTML5新方法,不过IE8及以上浏览器都兼容。

    特点:

    生命周期:持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

    存储的信息在同一域中是共享的。

    当本页操作(新增、修改、删除)了localStorage的时候,本页面不会触发storage事件,但是别的页面会触发storage事件。

    大小:据说是5M(跟浏览器厂商有关系)

    在非IE下的浏览中可以本地打开。IE浏览器要在服务器中打开。

    localStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡

    localStorage受同源策略的限制

    设置
    lacalStorage.setItem(‘username’,‘zxy’);

    获取

    localStorage.getItem(‘username’);

    删除

    localStorage.remove(‘username’);

    也可以一次清除所有存储

    localStorage.clear();

    storage事件

    当storage发生改变的时候触发。

    注意:当前页面对storage的操作会触发其他页面的storage事件。

    事件的回调函数中有一个参数event,是一个StorageEvent对象,提供了一些实用的属性,如下表:

    Property Type Description
    key String The named key that was added, removed, or moddified
    oldValue Any The previous value(now overwritten), or null if a new item was added
    newValue Any The new value, or null if an item was added
    url/uri String The page that called the method that triggered this change
    sessionStorage
    其实跟localStorage差不多,也是本地存储,会话本地存储

    特点:

    用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。也就是说只要这个浏览器窗口没有关闭,即使刷新页面或进入同源另一页面,数据仍然存在。关闭窗口后,sessionStorage即被销毁,或者在新窗口打开同源的另一个页面,sessionStorage也是没有的。

    cookie,localStorage,sessionStorage区别

    相同:在本地(浏览器端)存储数据。

    不同:

    localStorage只要在相同的协议、相同的主机名、相同的端口下,就能读取/修改到同一份localStorage数据。

    sessionStorage比localStorage更严苛一点,除了协议、主机名、端口外,还要求在同一窗口(也就是浏览器的标签页)下。

    localStorage是永久存储,除非手动删除。

    sessionStorage当会话结束(当前页面关闭的时候,自动销毁)

    cookie的数据会在每一次发送http请求的时候,同时发送给服务器而localStorage、sessionStorage不会。

    展开全文
  • 掌握基于WEB数据库应用,理解在B/S模式下网页如何同数据库之间建立联系,重点了解基于IDC和ASP两种方式以及各自原理和运行环境,学会使用ASP基本语法、内建对象、内建组件以及ASP访问数据库方法,能够读懂并...
  • ASP.NET的网页代码模型及生命周期

    热门讨论 2009-07-28 14:22:11
    ASP.NET页面包含两种代码模型,一种是单文件页模型,另一种是代码隐藏页模型。这两个模型功能完全一样,都支持控件拖拽,以及智能代码生成。 4.1.2 单文件页模型 单文件页模型中的所有代码,包括控件代码、...
  • 浏览器访问服务器时,要让服务器知道你是谁,只有两种方式: 方式一:把“你是谁”写入cookie。它会随每次HTTP请求带到服务端; 方式二:在URL、表单数据带上你用户信息(也可能在HTTP头部)。这种方式依赖于从...

    前言

    http协议是无状态协议。浏览器访问服务器时,要让服务器知道你是谁,只有两种方式:

    • 方式一:把“你是谁”写入cookie。它会随每次HTTP请求带到服务端;
    • 方式二:在URL、表单数据中带上你的用户信息(也可能在HTTP头部)。这种方式依赖于从特定的网页入口进入,因为只有走特定的入口,才有机会拼装出相应的信息,提交到服务端。

    大部分SSO需求都希望不依赖特定的网页入口(集成门户除外),所以后一种方式有局限性。适应性强的方式是第一种,即在浏览器通过cookie保存用户信息相关凭据,随每次请求传递到服务端。本文的方案是第一种。

    如果了解shiro可以知道,shiro默认使用ServletContainerSessionManager来做 session管理,它是依赖于浏览器的cookie来维护 session的,调用storeSessionId方法保存sesionId到cookie中。很多情况下,我们需要前端与后台是分离的且跨域的,比如手机APP登录或者第三方非浏览器端登录,依靠浏览器默认的session管理是没法满足我们的需要的,所以我们需要实现前后端分离,使用自定义token实现用户登录或验证通过的情况,那么面对的问题就是自定义会话的改造。那么如何改造session呢。

    首先,我们来看看shiro的整体架构图,如下所示。在这里插入图片描述
    SecurityManager中包含了Authenticator认证部分、Authrizer权限部分以及、Session管理和缓存管理,那么我们只需要默认改造SessionManager即可,也就是改造shiro的默认会话管理DefaultWebSessionManager。那么我们只要实现自定义的会话管理即可。

    主要设计两点:
    (1)如何从Http头或Http参数中获取对应token并将token有session一一映射
    (2)在登录的时候如何获取token并返回给前端

    实现步骤

    (1)自定义会话管理
    shiro的默认会话管理器是DefaultWebSessionManager,我们只需要自己实现DefaultWebSessionManager并覆盖其对应方法getSessionId即可将自定义的session返回给shiro,实现token与session的一一映射。

    package com.dondown.session;
    import java.io.Serializable;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import org.apache.shiro.web.servlet.Cookie;
    import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
    import org.apache.shiro.web.servlet.SimpleCookie;
    import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
    import org.apache.shiro.web.util.WebUtils;
    import org.springframework.util.StringUtils;
    /**
     * 目的: shiro 的 session 管理
     *      自定义session规则,实现前后分离,在跨域等情况下使用token方式进行登录验证才需要,否则没必须使用本类。
     *      shiro默认使用 ServletContainerSessionManager来做 session管理,
     *      它是依赖于浏览器的 cookie来维护 session的,调用 storeSessionId方法保存sesionId到cookie中
     *      为了支持无状态会话,我们就需要继承 DefaultWebSessionManager
     *      自定义生成sessionId则要实现 SessionIdGenerator
     * 备注说明:
     * @author Administrator
     */
    public class ShiroSessionManager extends DefaultWebSessionManager{
        // 定义的请求参数中使用的标记key,用来传递 token
        private static final String AUTH_TOKEN = "access_token";
        //private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
       
        public ShiroSessionManager(){
         super();
        }
       
        /**
         * 获取sessionId,原本是根据sessionKey来获取一个sessionId
         * 重写的部分多了一个把获取到的token设置到request的部分。
         * 这是因为app调用登陆接口的时候,是没有token的,登陆成功后,产生了token,我们把它放到request中,返回结果给客户端的时候,
         * 把它从request中取出来,并且传递给客户端,客户端每次带着这个token过来,就相当于是浏览器的cookie的作用,也就能维护会话了
         * @param request
         * @param response
         * @return
         */
        @Override
        protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
            // 获取请求参数中的 AUTH_TOKEN 的值,如果请求参数中有 AUTH_TOKEN 则其值为sessionId。shiro就是通过sessionId 来控制的
            String sessionId = WebUtils.toHttp(request).getParameter(AUTH_TOKEN);
            if (StringUtils.isEmpty(sessionId)){
                // 如果没有携带id参数则按照父类的方式在cookie进行获取sessionId
                return super.getSessionId(request, response);
            } else {
              // 是否将sid保存到cookie,浏览器模式下使用此参数。
              if (WebUtils.isTrue(request, "__cookie")){ 
                    Cookie template = getSessionIdCookie(); 
                    Cookie cookie = new SimpleCookie(template); 
                    cookie.setValue(sessionId);
                    cookie.saveTo(WebUtils.toHttp(request), WebUtils.toHttp(response)); 
                } 
                // session来源于哪里:url
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
                // 请求参数中如果有 access_token, 则其值为sessionId
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
                return sessionId;
            }
        }
    }
    

    这里要注意的是:
    A、有token的时候使用自定义token,否则使用默认的token获取实现。
    B、有token的时候返回token并且存储到对应请求中。

    (2)应用自定义会话管理器

    在shiro配置时候注入自己的会话管理

        /**
         * 自定义的 shiro session 缓存管理器,用于跨域等情况下使用 token 进行验证,不依赖于sessionId
         * @return
         */
        @Bean
        public SessionManager sessionManager(){
            // 将我们继承后重写的shiro session 注册
         ShiroSessionManager shiroSession = new ShiroSessionManager();
            // 如果后续考虑多tomcat部署应用,可以使用shiro-redis开源插件来做session的控制,或者nginx的负载均衡
            shiroSession.setSessionDAO(new EnterpriseCacheSessionDAO());
            return shiroSession;
        }
         
         /**
          * 注入shiro安全管理器设置realm认证
          * @return
          */
         @Bean("securityManager")
         public org.apache.shiro.mgt.SecurityManager securityManager(@Qualifier("myRealm") ShiroUserRealm MyRealm) {
              DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
              // 设置realm数据源
              securityManager.setRealm(MyRealm);
              // 注入ehcache缓存管理器;
              //securityManager.setCacheManager(ehCacheManager());
              securityManager.setCacheManager(redisCacheManager());
              // 注入shiro自带的内存缓存管理器
              //securityManager.setCacheManager(memoryCacheManager());
              // 注入Cookie记住我管理器
              // securityManager.setRememberMeManager(rememberMeManager());
              // 自定义的shiro session 缓存管理器实现前后端分离无状态会话-自定义token而不是使用浏览器session
              securityManager.setSessionManager(sessionManager());
              
              return securityManager;
         }
    

    (3)登录成功返回对应token给前端

        /**
          * 登录接口,地址需要与shiro的登录地址一一对应
          * 登录后浏览器传过来的session与被后台记住,session与对应用户进行了绑定
          * 可以通过SecurityUtils.getSubject();来获取当前用户session对应的认证信息
          * @param loginName
          * @param password
          * @param request
          * @param session
          * @param response
          * @return
          */
        @RequestMapping(value = "/login", method = RequestMethod.GET)
        @ResponseBody
        public ReturnValue<String> authenticate(@RequestParam("userName") String loginName,
                                    @RequestParam("password") String password,
                                   HttpServletRequest request,
                                   HttpServletResponse response) {
      
            // 把前端输入的username和password封装为token
            // 使用realm指定的盐值+password进行配置的算法类型加密(加密次数也是配置)
            // 然后与数据库存储的秘钥解密后进行匹配(根据存储为HEX或Base64解密)
            //UsernamePasswordToken token = new UsernamePasswordToken(loginName, EncryptUtil.md5(password));
            UsernamePasswordToken token = new UsernamePasswordToken(loginName, password);
            // 认证身份
            Subject subject = SecurityUtils.getSubject();
            try {
                subject.login(token);
                log.info("******登陆成功******");
               
                // 设置session时间
                //SecurityUtils.getSubject().getSession().setTimeout(1000*60*30);
               
                // 登录成功则返回token,用于无状态会话
                return new ReturnValue<String>(subject.getSession().getId().toString());
            } catch (UnknownAccountException e){
              log.info("******用户不存在******");
              return new ReturnValue<String>(ErrorCode.ERROR_OBJECT_EXIST, "该用户不存在!");
            } catch (LockedAccountException e){
              log.info("******用户未启用******");
              return new ReturnValue<String>(ErrorCode.ERROR_USER_PASSWORD, "该用户被锁定!");
            } catch (DisabledAccountException e){
              log.info("******用户未启用******");
              return new ReturnValue<String>(ErrorCode.ERROR_USER_PASSWORD, "该用户未启用!");
            }  catch (Exception e) {
              log.info("******未知错误******");
              return new ReturnValue<String>(ErrorCode.ERROR_SERVER_ERROR, "未知错误,用户登录失败,请联系管理员!");
            }
        }
    

    重点就是:return new ReturnValue(subject.getSession().getId().toString());从当前的Subject中获取会话id并返回给前端。

    (4)处理跨域预检验请求
    前后端分离项目中,由于跨域,会导致复杂请求,即会发送preflighted request,这样会导致在GET/POST等请求之前会先发一个OPTIONS请求,但OPTIONS请求并不带shiro的令牌,所以会被拦截导致无法发送GET或POST请求。所以我们直接拦截并允许即可。

    package com.dondown.session;
    import java.io.PrintWriter;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
    import com.alibaba.fastjson.JSONObject;
    import com.dondown.error.ErrorCode;
    import com.dondown.error.ReturnValue;
    /**
     * 目的: 过滤OPTIONS请求
     *      继承shiro 的form表单过滤器,对 OPTIONS 请求进行过滤。
     *      前后端分离项目中,由于跨域,会导致复杂请求,即会发送preflighted request,这样会导致在GET/POST等请求之前会先发一个OPTIONS请求,但OPTIONS请求并不带shiro
     *      的'authToken'字段(shiro的SessionId),即OPTIONS请求不能通过shiro验证,会返回未认证的信息。
     * 备注说明: 需要在 shiroConfig 进行注册
     */
    public class CORSAuthenticationFilter extends FormAuthenticationFilter {
        // 直接过滤可以访问的请求类型
        private static final String REQUET_TYPE = "OPTIONS";
        public CORSAuthenticationFilter() {
            super();
        }
        @Override
        public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
            if (((HttpServletRequest) request).getMethod().toUpperCase().equals(REQUET_TYPE)) {
                return true;
            }
            return super.isAccessAllowed(request, response, mappedValue);
        }
        @Override
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
            HttpServletResponse res = (HttpServletResponse)response;
            res.setHeader("Access-Control-Allow-Origin", "*");
            res.setStatus(HttpServletResponse.SC_OK);
            res.setCharacterEncoding("UTF-8");
           
            PrintWriter writer = res.getWriter();
            writer.write(JSONObject.toJSONString(new ReturnValue<String>(ErrorCode.ERROR_NOT_LOGIN, "请先登录系统!")));
            writer.close();
            return false;
        }
    }
    

    此时配置我们的shiro并设置我们的过滤器:

    @Bean
         public ShiroFilterFactoryBean shirFilter(org.apache.shiro.mgt.SecurityManager securityManager) {
             // shiroFilterFactoryBean对象
              ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
              // 配置shiro安全管理器 SecurityManager
              shiroFilterFactoryBean.setSecurityManager(securityManager);
              // 指定要求登录时的链接
              shiroFilterFactoryBean.setLoginUrl("/login");
              // 登录成功后要跳转的链接
              shiroFilterFactoryBean.setSuccessUrl("/index");
              // 未授权时跳转的界面;
              //shiroFilterFactoryBean.setUnauthorizedUrl("/403");
              
              // 配置拦截器.
              Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
              // 配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
              filterChainDefinitionMap.put("/logout", "anon");
              filterChainDefinitionMap.put("/afterlogout", "anon");
              
              // 配置访问权限
              // 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
              // authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
              filterChainDefinitionMap.put("/static/**", "anon");
              filterChainDefinitionMap.put("/templates/**", "anon");
              filterChainDefinitionMap.put("/swagger-*/**", "anon");
              filterChainDefinitionMap.put("/swagger-ui.html/**", "anon");
              filterChainDefinitionMap.put("/webjars/**", "anon");
              filterChainDefinitionMap.put("/v2/**", "anon");
              filterChainDefinitionMap.put("/afterlogin", "anon");
              // add操作,该用户必须有【addOperation】权限
              // filterChainDefinitionMap.put("/add", "perms[addOperation]");
              // 表示admin权限才可以访问
              // filterChainDefinitionMap.put("/admin/**", "roles[admin]");
              filterChainDefinitionMap.put("/**", "authc");
              filterChainDefinitionMap.put("/**/*", "authc");
         
              // 拦截器工厂类注入
              shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
              
            // 自定义拦截器限制并发人数
            LinkedHashMap<String, Filter> filtersMap = new LinkedHashMap<>();
            // 统计登录人数:限制同一帐号同时在线的个数
            //filtersMap.put("kickout", kickoutSessionControlFilter());
            // 自定义跨域前后端分离验证过滤器-自定义token情况
            filtersMap.put("corsAuthenticationFilter", new CORSAuthenticationFilter());
            shiroFilterFactoryBean.setFilters(filtersMap);
           
              return shiroFilterFactoryBean;
         }
    

    (5)前端带自定义token测试
    http://192.168.8.8:7004/shiro/user/find/lixx?access_token=登录返回的token值
    在这里插入图片描述
    可以发现使用自定义token即可穿过网关访问后台服务或夸网服务。

    快来成为我的朋友或合作伙伴,一起交流,一起进步!:
    QQ群:961179337
    微信:lixiang6153
    邮箱:lixx2048@163.com
    公众号:IT技术快餐

    展开全文
  •  其中save(FileActionForm fileForm)方法,将封装在fileForm的上传文件保存到数据库,这里我们使用FileActionForm作为方法入参,FileActionForm是Web层的表单数据对象,它封装了提交表单的数据。将...
  • get和post请求区别

    2019-12-11 19:48:46
    我们在前面介绍了servlet构造方法,生命周期,还连带着网页进行了完整的访问演示,我们知道,在form表单中两种请求方式,一种是get,一种是post,这是两种不同请求方式,那么他们都有着什么区别呢?...

    我们在前面介绍了servlet的构造方法,生命周期,还连带着网页进行了完整的访问演示,我们知道,在form表单中有两种请求方式,一种是get,一种是post,这是两种不同的请求方式,那么他们都有着什么区别呢?


    get和post请求的区别

    我们在浏览器中有很多中发起请求的方式,其中:

    Get请求:

                         超链接、浏览器地址栏直接输入、<form method=”GET”>

    Post请求:

                         只有在<form method=”post”>时会发送post请求。

    区别有:

    ①地址栏后是否带有传输信息

                                       get方式传参会将表单中的信息使用URL拼接的方式显示到浏览器的地址栏中,多个参数使用&形式拼接,不安全:                                       如果我们做的是一个需要输入密码的页面,我们的密码会完整的显示在地址栏中。

                                       post传参不会暴露信息,会将信息放在请求主体中隐藏传送

    ②传输的信息是否有长度限制

                                       get传参数有长度限制,超过限制后直接报错。因为浏览器的地址栏也是有长度限制的,不可能无限制存储着传输的                                     内容

                                       post传参长度不受限制。

     

                                                                     GET唯一的好处就是比post快。

    展开全文
  • 202 第10章 DOM:文档对象模型 203 10.1 两种接口故事 204 10.2 DOM和兼容浏览器 205 10.3 DOMHTML API 206 10.4 理解DOM:核心API 213 10.5 DOM核心文档对象 220 10.6 Element及在上下文中访问元素 ...
  • 计算机科学——web

    千次阅读 2020-11-10 21:31:33
    # 第七章 在网页中创建表单 ## 第一节 表单 ...3.访问者输入信息可以使用get和post这两种方式提交到服务器。 标签 1.;定义一个单元区域以及其相关信息 2.;设置输入表单元素 3.;设置列表元素 4.<option&...
           #  第七章 在网页中创建表单
                   ## 第一节 表单
    
    • 表单的定义
      用表单可以收集网页访问者输入的相关信息。
    • 特性
      1.表单中包括多种不同的元素,eg文本框、文本域、下拉式菜单等元素。
      2.访问者输入的信息需要由服务器端处理程序处理。
      3.访问者输入的信息可以使用get和post这两种方式提交到服务器。
    • 标签
      1.<form>定义一个单元区域以及其相关信息
      2.<input>设置输入表单元素
      3.<select>设置列表元素
      4.<option>设置列表元素中的项目
      5.<textarea>设置表单文本域元素
      ## 第二节 <form>标签
    • 作用:1.限定表单范围
      2.携带表单的相关信息
    • 语法:<form name=“表单名单” method=“提交方法” action=“处理程序”> </form>
    • 属性
      name 名称
      method定义表单数据从客户端传送到服务器的方法。
      action 用于指定处理表单的服务端程序 。
      onsubmit 用于指定处理表单的脚本函数。
      enctype 设置MIME类型,需要上传文件到服务器时,设置为multipart/form-data。
      target 设置在何处打开下一个网页 。
      • 注意:
        get:是以ttp头的形式附加到url地址后,不安全,有字符限制,只转送ascII的字符。
        post:是以http正文体形式发送,相对安全,无字节限制,传送所有字符。
    • input元素
      一.定义:设置输入表单元素
      二.语法:<input type=“元素类型” name=“表单元素名称”/>
      三.属性
      text 单行文本框元素
      password 设置密码元素(字符显示为"•")
      file 文件元素 hidden 隐藏元素
      radio 单选按钮元素 checkbox 复选按钮元素
      button 普通按钮元素 submit 提交按钮元素
      reset 重置按钮元素 image 图像提交按钮元素
    • 文本框(用于提供给访问者输入文本信息)
      1.语法<input type=“text” name=“文本框名称”/>
      2.属性 name 名称 maxlength 设置最多字符数
      size 控制文本框的长度(默认为20个像素)
      value 设置文本框的默认值
    • 补充:以下密码框,隐藏域,文本域,单选框,复选框,提交按钮,button按钮语法与文本框语法相似。(在单选框中同一组的单选框的name元素要相同。)

    (不允许转发)

    展开全文
  • 正文开始…… 三本地存储方式 cookie 前言 网络早期最大问题之一是如何管理状态。...存储数据,当用户访问了某个网站(网页时候,我们就可以通过cookie来向访问者电脑上存储数据,或者
  • 1.在Tomcat下部署A.首先需要在Web.xml设置三个元素,, 指明了受到限制URL...如果是FORM方式的话,则需要个JSP文件,文件名可以随意指定,但是自定义验证网页的表单名和字段名则需要按照如下定义:j_security_chec
  • 1、servlet是什么? servlet是一个连通前、后端的java类,只会在第一次加载时调用init()方法被初始化,后来不再初始化。第一次被调用后会进入休眠状态,等待再次被调用或被销毁(destroy...3、表单中action的两种写...
  • JavaEE(初始JSP,Servlet)

    2019-08-19 21:39:07
    目录 什么是JavaEE?: 如何在IDEA部署WEB项目到服务器并且访问...静态包含和动态包含的两种不同的包含方式的区别: 练习:编写提交表单(新建html文件 新建jsp文件): HTTP介绍: Servlet使用: 什么是...
  • 下面就以两种不同用户来分析博客网站需求。 4.2.1注册博友 首先必须在博客首页登录填写用户名和密码,这样才能执行一些相关操作,不然就是普通用户只能查看一些信息,而不能发表博文。可以在管理页面上添加...
  • [ ] 用户访问浏览器,一般两种方式,get获取网页和post提交数据,get也可以提交数据,以一种明文形式显示在url,post提交数据url不显示,一种安全数据提交方式,get方式提交数据一般应用于一些排序方式和...
  • php快速入门小高手

    2009-03-05 15:31:13
    引用文件方法有两种:require 及 include。 require 使用方法如 require("MyRequireFile.php"); 。这个函数通常放在 PHP 程序最前面,PHP 程序在执行前,就会先读入 require 所指定引入文件,使它变成 ...
  • 14. jsp中的数据库连接方式 15. 在jsp,怎么实现按回车就可提交表单? 16. 在JSP如何传递数组? 17. 按地址取图片? 18. JSP如何上传图片到数据库字段? 19. 页面自动刷新? 20. 表单自动提交? 21. 从JSP传...
  • cangkuguanli.zip

    2020-07-21 14:56:11
    库存管理系统 10个模块,每一个模块要求如下: 准备工作创建数据库stock创建指定名字表格,输入图片中的所有记录。...2)使用JDBC访问数据库,两种方式:基础代码,Dao. 3)使用核心标签库+sql标签库,访问数据库。
  • 爬虫学习----登录处理

    2019-01-17 16:08:33
    这里涉及到提交表单网页上传数据,我们通常发送请求有两种方式GET和POST。我们一般使用POST请求提交数据,因为查询字符串(名称/值)在POST请求HTTP消息主体,敏感信息不会出现在URL,参数也不会被保存在...
  • 爬虫学习笔记1

    2018-11-06 22:28:28
    访问网站时,向服务器发送请求主要有两种方式 GET方法 请求指定页面信息,并且返回实体主体。 POST方法 向指定资源提交数据进行处理请求(例如提交表单或者上传文件),数据被包含在请求体,POST请求可能会...
  • html入门到放弃笔记

    2018-05-15 15:06:12
    2、显示在自己的网页中 3、超链接 1、语法 标记:内容 属性: 1、href : 要链接HTML页面URL 2、target : 目标,指定新网页打开形式 取值: 1、_blank : 在新标签页中打开网页 2、_self : 在自身标签页...
  • javascript函数解释

    2011-02-26 11:03:52
    25.取出窗体的所有表单的数量:document.forms.length 26.关闭文档的输出流:document.close(); 27.字符串追加连接符:+= 28.创建一个文档元素:document.createElement(),document.createTextNode() 29.得到元素的...
  • 主要有两种类型,一种是类似QQ,MSN类型,需要用户安装软件才能聊天,另一种即是只需打开WEB浏览器就可以聊天,类似QQ聊天室功能 ,本系统目标即模仿QQ聊天室,开发一个简单能在机房里供大家聊天Web程序...
  • 34、两种编辑器选择,可视化编辑器,类似word所件即所得在线内容编辑功能,支持表格、图片、FLASH、多种格式播放器插入,支持图片和附件上传。 35、字符过滤,自动过滤敏感字符,避免损害网站形象、避免网站...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 124
精华内容 49
关键字:

网页中访问表单的两种方式