精华内容
下载资源
问答
  • web登录注册,在Myeclipse里打开,可以进行mysql数据访问
  • web-登录界面html

    2019-12-05 18:18:52
    本资源为登陆界面,通过web显示,编程语言包括html、css、js、php,其中php负责与后端数据库连接,获取后端用户信息。
  • WEB网站访问的过程

    千次阅读 2020-08-11 19:42:58
    用户访问网站的基本流程(6个阶段): DNS解析 tcp三次握手 http请求报文 网站集群内部处理数据的一个过程 http响应报文 tcp四次挥手断开的过程 DNS解析过程 1)DNS解析2种查询方式:递归查询->迭代查询(见下...

    用户访问网站的基本流程(6个阶段):

    DNS解析   tcp三次握手  http请求报文  网站集群内部处理数据的一个过程   http响应报文  tcp四次挥手断开的过程

     DNS解析过程

     1)DNS解析2种查询方式:递归查询->迭代查询(见下图DNS部分)

         所谓 递归查询过程 就是 “查询的递交者” 更替, 而 迭代查询过程 则是 “查询的递交者”不变

           当用户在浏览器地址栏敲入域名地址回车后客户端首先检查本地DNS缓存和hosts文件,如果是第一次访问的话,本地DNS缓存是没有缓存记录的,而hosts文件是用来做测试使用的也是没有结果的,此时客户端会请求local DNS,local DNS是客户端在本地网卡中配置的DNS服务器,local DNS首先会检测DNS缓存,DNS缓存中如果有结果,会将结果返回给客户端,如果没有结果local DNS会负责域名解析,local DNS首先访问请求全球13台根服务器(据说美国有8台,日本2台,中国没有)根服务器会根据local DNS请求域名地址,将此域名地址的顶级域名服务器返回给local DNS,local DNS在继续访问顶级域名服务器,顶级域名服务器根据local DNS请求的地址将此地址的二级域名服务器返回给local DNS,local DNS又访问二级域名服务器,二级域名服务器我们又叫做授权DNS服务器,授权服务器检查自己的A记录将结果返回给local DNS,local DNS进行本地缓存并发给客户端。

    三次握手原理

    2) 客户端接到结果后与服务端建立TCP三次握手连接
           首先客户端发送syn seq序列给服务端,客户端从close的状态进入syn send状态,服务端接收到syn请求的时候, 从closed状态进入listen,服务端同时发送ack和syn请求,此时服务端从listen状态进入到syn received,客户端接收到ack确认和syn请求后进行返回ack确认,此时客户端进入establised状态, 服务端接收到ack确认也进入establised状态。

    《TCP连接11种状态详解》

    LISTEN: 侦听来自远方的TCP端口的连接请求
    SYN-SENT: 再发送连接请求后等待匹配的连接请求
    SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认
    ESTABLISHED: 代表一个打开的连接
    FIN-WAIT-1: 等待远程TCP连接中断请求,或先前的连接中断请求的确认
    FIN-WAIT-2: 从远程TCP等待连接中断请求
    CLOSE-WAIT: 等待从本地用户发来的连接中断请求
    CLOSING: 等待远程TCP对连接中断的确认
    LAST-ACK: 等待原来的发向远程TCP的连接中断请求的确认
    TIME-WAIT: 等待足够的时间以确保远程TCP接收到连接中断请求的确认
    CLOSED: 没有任何连接状态

    HTTP请求解释

    3)客户端发送http请求报文,http请求又分为四部分

    第一部分:请求行
    请求行又分为三块,第一块是请求方法,第二块是请求URL,第三块是请求的http协议版本,我们常用的方法有GET head POST等,get就是用来客户端向服务端获取资料的时候就是使用get方式,post是用来客户端向服务端注册一些信息等使用的是post方式,而我们使用curl -I 是使用服务端的响应头部信息head。
    第二部分:请求头部信息,包含媒体类型、语言类型、压缩方式、客户端类型主机名等
    媒体类型包含image/gif、jpeg图片类型,音频类型,这些类型起初是为了解决邮件系统的传输搬移数据,现在广泛应用于http协议当中
    第三部分是空行
    空行表示请求头部与请求主体的分隔行。
    第四部分:请求主体
    常用的get方式是没有请求主体的,post方式才有请求主体,这个请求发送到服务端。

    负载均衡

    4)负载均衡 首先接受请求

    负载均衡器:有软硬件2种
    1)企业常用的有硬件F5;
    2)软件应用层的nginx、haproxy 传输层的lvs等;
       然后负载均衡器会根据自己特殊的算法轮询啊,最小连接数将这些请求一一发送给web服务器,
    到了web服务器,这些请求又分为动态请求和静态请求,静态请求一般就是静态页面一般是用html css xml等语言编写的网页,静态网页的特点性能高速度快,
    在客户端的浏览器解析,不需要数据库的支持,容易被搜索引擎收录,缺点用户交互性比较差,不易于维护,常用的处理静态页面的软件有apache nginx等
    国内最为主流的就是nginx,动态网页一般是与aspx php jsp等结尾的,动态网页的url中,会有一些特殊字符,像= &符号等,动态网页的特点,
    与用户的交互性比较强,容易维护,但是在服务端进行解析,并不容易被搜索引擎收录,因此性能会比较差,
    常用处理动态页面的软件有php引擎,tomcat resin等,php配合apache nginx使用,解析php编程语言开发的程序,配合apache是以php模块的方式来进行对接,跟nginx是fastCGI守护进程来进行解析,还有一些tomcat resin这些是
    解析java语言开发的程序,这些状态程序会请求一些结构化的数据,结构化的数据我们会存放在后端的数据库中,目前互联网最主流的关系型数据库就是mysql,
    类似于二维表,但是性能会比较低,因此有些企业会使用memcached redis非关系型数据库进行做mysql的缓存数据库来提高访问速度,
    还有一些非结构化的数据,像图片、视频、音频等这些数据我们会存放在存储服务器上,常用的存储服务器有nfs、mfs、glusterfs等,
    这些非结构化的数据属于静态数据,很多公司会选择把这些静态数据推送到CDN节点上来提高用户的体验。
    5) http响应报文又分为四部分
    第一部分 响应起始行
    起始行分为三块
    第一块是http协议版本
    第二块是状态码
    第三块是状态码描述,一般我们常见的状态码像200正常,301永久跳转,302是临时跳转
    第二部分:响应头部信息
    一般是在内容服务器的一些参数,比如说处理请求的是哪个软件
    第三部分:响应空行
    表示响应头部与主体的分隔行。
    第四部分:响应主体
    响应主体信息就是客户端真正在浏览器中的数据会在响应主体中返回给客户端。
    此时客户端返回完之后:在常链接超时后

    四次挥手原理

    6) 客户端会进行tcp断开链接
    首先客户端会发送FIN请求给服务端,此时客户端从established状态进入到FINWAIT-1状态,服务端接收到请求后从established状态进入closewait状态
    服务端在进行ack确认,先返回给客户端,客户端进入finwait2状态,此时已经进入了一个半链接状态,所谓的半链接状态就是客户端向服务端发送数据完毕了,
    但是服务端向客户端发送的数据还没有发送过来,当服务端向客户端发送完数据之后,继续发送fin请求,此时客户端接到fin请求进行返回ack确认,
    此时客户端进入timewait状态,客户端接到ack,ack接着发送给服务端,此时服务端进入closed状态,断开链接。此时客户端会
    等待2倍的MSL值。(2倍的MSL值就是linux的生存周期,2MSL值就是一般默认是30秒)就是1分钟后客户端会进入closed状态,就是从timewait状态自动进入closed状态。
    "查看上面TCP11种状态中,包含三次握手和四次断开"

    网站访问流程故事版

    我们的主角小王,是个活雷锋,哪里需要哪里搬,今天他又来了。

    小王打开了自己的百度浏览器,输入www.baidu.com,按下回车,等了一会,就打开了网页,小王很困惑,在敲下回车的一瞬间,电脑到底做了什么?

    为了一探究竟,小王打开百宝箱,并念出了那句开启百宝箱的咒语(我是韩以安,关注我,有更多精彩内容哦)。百宝箱闪出一个耀眼光芒,小王眼前一黑,过了好一会儿小王醒才过来,醒过来后发现自己被困在了电脑里,一个美女正在电脑前跟闺蜜聊着天。突然美女像是想起了什么,她飞快的打开浏览器,输入了www.taobao.com

    小王的身体突然就不听使唤,直奔电脑的host文件飞去, 小王这才明白,百宝箱把自己变成了一个用户请求,根据请求的处理流程,小王飞快的看了一眼host,发现文件中已经有www.taobao.com对应的ip地址,于是获取到ip,直接扔给了美女,美女很开心的购起物来。

    小王正要好好欣赏一下眼前的美人,QQ上一个消息弹出,是一个不常见的网址,www.wsmv.com 美女想也没想,直接打开, 小王立即赶往host查看网址对应的ip,结果发现host里没有对应的ip。小王心想,这应该是美女第一次打开这个网站,所以电脑里没有缓存。

    既然在host里没有找到,小王赶紧询问了下周边忙碌的其他请求,接下来该怎么办,一个看上去很老成的nginx请求路过,指了指旁边的路由器(在你的城市的某个角落,但是不会太远)说,“诺,那个是本地域名服务器,你去向他寻求帮助吧”

    小王飞奔过去,向本地DNS服务器询问是否有刚刚美女输入的网址的ip, 本地DNS快速扫描了下,发现没有,但给出了提示,可以去根服务器去问问。

    小王来到根服务器,小王问,有没有www.wsmv.com对应的ip, 根域缓缓的答道,“我这边没有,但是我有.com.的服务器地址,你可以去问问他”,说着根域服务器甩出了 一条信息,上面写在.com服务器的ip地址。

    小王又马不停蹄的根据ip找到对应的.com服务器,询问是否有美女输入的网站ip的地址, .com服务器头也没抬的回了一句:“又是根域让你来的吧,我这边有wsnv.com对应的ip地址,你可以直接去,但是我们这有个不成文的规定,不是所有人都可以随便访问服务器的,IP给你,接下来能不能请求到资源还得靠你自己”

    小王拿到了 wsnv.com的ip地址正要进去获取数据,却被一个叫TCP协议挡住了去路。小王知道这是要进行TCP连接了, 需要与服务器进行三次对话,跟对暗号一样,通过后才能获取数据。

    但是要进行TCP连接,小王得先把消息成功的发送到服务器上,小王根据书中讲的准备了IP协议,ARP协议和OSPF协议, IP地址只指定了美女的PC的ip和刚从.com获得的要登陆网站的ip地址, 然后经过一个个路由器传送给服务器,然后进行了tcp的链接。

    连接成功了,小王兴奋的跳了起来,能给美女获取到数据是小王最开心的事情。 but,小王听到一个声音 “恭喜你,成功跟tcp进行了链接,现在你可以寻求HTTP协议的帮助来请求网页了,请先熟悉HTTP协议的请求规则”

    小王赶紧查看HTTP请求规则,规则里有条重要提示: 虽然你通过了tcp协议,但是还是有被服务器拒绝的可能,如果服务器拒绝了你的请求会返回"Forbiden",如果服务器没有拒绝,能够正常访问,就返回200OK,然后才会给你传输数据。

    小王连忙根据规则发送HTTP请求报文给服务器,经过了硬件防火墙,到了负载均衡,又通过负载均衡到了web,后面又有缓存,最后才到数据库。成功了,小王收到了服务器的回复,接收到一堆HTML形式的文本。然后快速返回到美女的电脑,当然也没忘了在本地缓存上存一份,毕竟下次再按这个流程走一遍,小王会累死的。

    在本地缓存好之后,小王把接收的文本给了浏览器,浏览器是个聪明的家伙,很快就翻译出来,并渲染到屏幕上,看到屏幕前美女开心的笑容,小王感觉好满足,顺便瞅了一眼浏览器,不看不要紧,一看吓一跳,浏览器上是美女男朋友发来的礼物,满屏的烟花和一句我爱你。

    小王的心突然疼了一下,原来有男朋友啊,那我这还忙活的这么起劲,算了,百宝箱带我回去吧。

    随着一阵耀眼的光芒,小王最后看了一眼美女,恋恋不舍的离开了。

    小王回来后,快速整理了今天的见闻,爱学习的小王在笔记本上写到:美女(此处划掉)

    小王又重新写到: 用户发起一个请求到最终落地数据,中间经历了:

    用户(电脑,网络,本地缓存)–域名服务器–tcp三次握手 --HTTP协议

    进入了HTTP协议之后,小王回忆了下,先是看到了硬件防火墙F5,然后是请求发给了负载均衡nginx, nginx转发给了其中的tomcat,tomcat有相应的配置文件,根据配置文件搜索相应的资源-好像在获取资源的时候还遇到了缓存redis,然后才是访问数据库,这一圈下来好麻烦。

    展开全文
  • webapi 访问权限

    千次阅读 2018-06-05 15:44:36
    webapi不需要登陆,只需要知道方法就能直接访问,这个就比较郁闷了。因为之前也没有做过权限控制的问题,百度搜到了不少,但是都不能用,只能自己解决了,后来终于找到了一种可以实现的方法,只是不知道好不好,希望...

           最近在做一个项目,前台使用的是angularjs,后台使用的是webapi。webapi不需要登陆,只需要知道方法就能直接访问,这个就比较郁闷了。因为之前也没有做过权限控制的问题,百度搜到了不少,但是都不能用,只能自己解决了,后来终于找到了一种可以实现的方法,只是不知道好不好,希望有人看到能给个答案。实现方法如下:

          1、根据登陆信息(用户名,密码之类的)去数据库查询到用户信息,以及用户所有的权限(权限由在增加用户的时候分配)。

          2、建立FormsAuthenticationTicket,并把用户信息保存到缓存中,并返回登陆结果及一个token(唯一标识),userRole是一个需要返回的信息实体类。

              FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                    2,
                    list[0].USERID,
                    DateTime.Now,
                    dateCookieExpires,
                     false,
                    new JavaScriptSerializer().Serialize(userRole)-------权限(后面用到)
                    );
                string encTicket = FormsAuthentication.Encrypt(ticket);
        HttpRuntime.Cache.Add(userRole.TOKEN, encTicket, null, DateTime.Now.AddDays(7), TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Default, null);------------保存到缓存中,也可以存到数据库

                return Json(userRole);

        

          3、把token保存到本地       localStorage.setItem("token",userRole.TOKEN);

          4、创建一个全局注入器,每次访问的时候,可以自动在header中带入token

               

    .factory("httpInjector",['$q','$injector',function($q,$injector){
        var httpInterceptor = {
            'responseError' : function(response) {
                // ......
                return $q.reject(response);
            },
            'response' : function(response) {
                if (response.status == 21000) {
                    // console.log('do something...');
                }
                return response || $q.when(response);
            },
            'request' : function(config) {
                config.headers = config.headers || {};
                if (localStorage.token) {
                    config.headers.token = localStorage.getItem("token");
                    // config.headers['X-Access-Token'] = $localStorage.token;
                };
    
                return config || $q.when(config);
    
                return config;
            },
            'requestError' : function(config){
                // ......
                return $q.reject(config);
            }
        };
        return httpInterceptor;
    

    }])

    5、把注入器配置到config中

    .config(["$ionicConfigProvider",'$httpProvider', function ($ionicConfigProvider,$httpProvider) {
        $httpProvider.interceptors.push('httpInjector');
    }])
    
    

     6、创建一个过滤器TestFilter,继承AuthorizationFilterAttribute,重写方法

             public override void OnAuthorization(HttpActionContext actionContext)-------重写授权方法        {    

            if (HttpContext.Current.Request.Headers["token"] != null)        

        {         

           string token = HttpContext.Current.Request.Headers["token"].ToString();---------获取前台传过来的token                      if (HttpRuntime.Cache.Get(token) != null)

                    {

                      ------------根据token到缓存中取出用户信息。

                  FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(HttpRuntime.Cache.Get(token).ToString());

                        if (ticket != null)                 

             {                   

         USER_ROLE userRole = new JavaScriptSerializer().Deserialize<USER_ROLE>(ticket.UserData);           

                 string[] roles = new string[] { };--------取出用户权限组成数据                

            IIdentity identity = new FormsIdentity(ticket);-------------标识用户的身份验证的类型              

              IPrincipal principal = new GenericPrincipal(identity, roles); ---------当前用户标识                        HttpContext.Current.User = principal;-----------  为当前 HTTP 请求设置安全信息。                    

                        }           

                    }       

                 }

            }

         7、把自定义的过滤器注册到webapiconfig中,注册后每次webapi请求会先经过过滤器

                 config.Filters.Add(new TestFilter());

    8、方法或控制器上添加权限限制   [Authorize(Roles = "TEST")]

    到此完成,没有此权限的用户就无法访问此方法。

    为什么要返回token到前台,然后把用户信息保存到缓存中呢?是因为对于webapi来说,每次的访问都是一个新的请求,

    之前的登陆信息在下次访问的时候就请求不到了,cookie和session也访问不到,所以信息保存到了缓存中(保存到数据库也可以

    但是请求太频繁)。根据token,找到对应的用户信息,取出用户信息后赋给当前请求用户,当前用户才有访问权限。

       

    展开全文
  • 使用纯Java实现一个WebSSH项目

    万次阅读 多人点赞 2020-03-10 13:18:21
    使用纯Java语言实现的WebSSH项目。 技术:SpringBoot+WebSockey+jsch+xterm.js

    前言

    最近由于项目需求,项目中需要实现一个WebSSH连接终端的功能,由于自己第一次做这类型功能,所以首先上了GitHub找了找有没有现成的轮子可以拿来直接用,当时看到了很多这方面的项目,例如:GateOne、webssh、shellinabox等,这些项目都可以很好地实现webssh的功能,但是最终并没有采用,原因是在于这些底层大都是python写的,需要依赖很多文件,自己用的时候可以使用这种方案,快捷省事,但是做到项目中供用户使用时,总不能要求用户做到服务器中必须包含这些底层依赖,这显然不太合理,所以我决定自己动手写一个WebSSH的功能,并且作为一个独立的项目开源出来。

    github项目开源地址:https://github.com/NoCortY/WebSSH

    技术选型

    由于webssh需要实时数据交互,所以会选用长连接的WebSocket,为了开发的方便,框架选用SpringBoot,另外还自己了解了Java用户连接ssh的jsch和实现前端shell页面的xterm.js.

    所以,最终的技术选型就是 SpringBoot+Websocket+jsch+xterm.js

    导入依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <!-- Web相关 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- jsch支持 -->
        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.54</version>
        </dependency>
        <!-- WebSocket 支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <!-- 文件上传解析器 -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
    </dependencies>
    

    一个简单的xterm案例

    由于xterm是一个冷门技术,所以很多同学并没有这方面的知识支撑,我也是为了实现这个功能所以临时学的,所以在这给大家介绍一下。

    xterm.js是一个基于WebSocket的容器,它可以帮助我们在前端实现命令行的样式。就像是我们平常再用SecureCRT或者XShell连接服务器时一样。

    下面是官网上的入门案例:

    <!doctype html>
     <html>
      <head>
        <link rel="stylesheet" href="node_modules/xterm/css/xterm.css" />
        <script src="node_modules/xterm/lib/xterm.js"></script>
      </head>
      <body>
        <div id="terminal"></div>
        <script>
          var term = new Terminal();
          term.open(document.getElementById('terminal'));
          term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')
        </script>
      </body>
     </html>
    

    最终测试,页面就是下面这个样子:

    xterm入门

    可以看到页面已经出现了类似与shell的样式,那就根据这个继续深入,实现一个webssh。

    后端实现

    由于xterm只要只是实现了前端的样式,并不能真正地实现与服务器交互,与服务器交互主要还是靠我们Java后端来进行控制的,所以我们从后端开始,使用jsch+websocket实现这部分内容。

    • WebSocket配置

      由于消息实时推送到前端需要用到WebSocket,不了解WebSocket的同学可以先去自行了解一下,这里就不过多介绍了,我们直接开始进行WebSocket的配置。

      /**
      * @Description: websocket配置
      * @Author: NoCortY
      * @Date: 2020/3/8
      */
      @Configuration
      @EnableWebSocket
      public class WebSSHWebSocketConfig implements WebSocketConfigurer{
          @Autowired
          WebSSHWebSocketHandler webSSHWebSocketHandler;
          @Override
          public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
              //socket通道
              //指定处理器和路径,并设置跨域
              webSocketHandlerRegistry.addHandler(webSSHWebSocketHandler, "/webssh")
                      .addInterceptors(new WebSocketInterceptor())
                      .setAllowedOrigins("*");
          }
      }
      
    • 处理器(Handler)和拦截器(Interceptor)的实现

      刚才我们完成了WebSocket的配置,并指定了一个处理器和拦截器。所以接下来就是处理器和拦截器的实现。

      拦截器

      public class WebSocketInterceptor implements HandshakeInterceptor {
          /**
           * @Description: Handler处理前调用
           * @Param: [serverHttpRequest, serverHttpResponse, webSocketHandler, map]
           * @return: boolean
           * @Author: NoCortY
           * @Date: 2020/3/1
           */
          @Override
          public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
              if (serverHttpRequest instanceof ServletServerHttpRequest) {
                  ServletServerHttpRequest request = (ServletServerHttpRequest) serverHttpRequest;
                  //生成一个UUID,这里由于是独立的项目,没有用户模块,所以可以用随机的UUID
                  //但是如果要集成到自己的项目中,需要将其改为自己识别用户的标识
                  String uuid = UUID.randomUUID().toString().replace("-","");
                  //将uuid放到websocketsession中
                  map.put(ConstantPool.USER_UUID_KEY, uuid);
                  return true;
              } else {
                  return false;
              }
          }
      
          @Override
          public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {
      
          }
      }
      

      处理器

      /**
      * @Description: WebSSH的WebSocket处理器
      * @Author: NoCortY
      * @Date: 2020/3/8
      */
      @Component
      public class WebSSHWebSocketHandler implements WebSocketHandler{
          @Autowired
          private WebSSHService webSSHService;
          private Logger logger = LoggerFactory.getLogger(WebSSHWebSocketHandler.class);
      
          /**
           * @Description: 用户连接上WebSocket的回调
           * @Param: [webSocketSession]
           * @return: void
           * @Author: Object
           * @Date: 2020/3/8
           */
          @Override
          public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
              logger.info("用户:{},连接WebSSH", webSocketSession.getAttributes().get(ConstantPool.USER_UUID_KEY));
              //调用初始化连接
              webSSHService.initConnection(webSocketSession);
          }
      
          /**
           * @Description: 收到消息的回调
           * @Param: [webSocketSession, webSocketMessage]
           * @return: void
           * @Author: NoCortY
           * @Date: 2020/3/8
           */
          @Override
          public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
              if (webSocketMessage instanceof TextMessage) {
                  logger.info("用户:{},发送命令:{}", webSocketSession.getAttributes().get(ConstantPool.USER_UUID_KEY), webSocketMessage.toString());
                  //调用service接收消息
                  webSSHService.recvHandle(((TextMessage) webSocketMessage).getPayload(), webSocketSession);
              } else if (webSocketMessage instanceof BinaryMessage) {
      
              } else if (webSocketMessage instanceof PongMessage) {
      
              } else {
                  System.out.println("Unexpected WebSocket message type: " + webSocketMessage);
              }
          }
      
          /**
           * @Description: 出现错误的回调
           * @Param: [webSocketSession, throwable]
           * @return: void
           * @Author: Object
           * @Date: 2020/3/8
           */
          @Override
          public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
              logger.error("数据传输错误");
          }
      
          /**
           * @Description: 连接关闭的回调
           * @Param: [webSocketSession, closeStatus]
           * @return: void
           * @Author: NoCortY
           * @Date: 2020/3/8
           */
          @Override
          public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
              logger.info("用户:{}断开webssh连接", String.valueOf(webSocketSession.getAttributes().get(ConstantPool.USER_UUID_KEY)));
              //调用service关闭连接
              webSSHService.close(webSocketSession);
          }
      
          @Override
          public boolean supportsPartialMessages() {
              return false;
          }
      }
      

      需要注意的是,我在拦截器中加入的用户标识是使用了随机的UUID,这是因为作为一个独立的websocket项目,没有用户模块,如果需要将这个项目集成到自己的项目中,需要修改这部分代码,将其改为自己项目中识别一个用户所用的用户标识。

    • WebSSH的业务逻辑实现(核心)

      刚才我们实现了websocket的配置,都是一些死代码,实现了接口再根据自身需求即可实现,现在我们将进行后端主要业务逻辑的实现,在实现这个逻辑之前,我们先来想想,WebSSH,我们主要想要呈现一个什么效果。

      我这里做了一个总结:

      1.首先我们得先连接上终端(初始化连接)

      2.其次我们的服务端需要处理来自前端的消息(接收并处理前端消息)

      3.我们需要将终端返回的消息回写到前端(数据回写前端)

      4.关闭连接

      根据这四个需求,我们先定义一个接口,这样可以让需求明了起来。

      /**
       * @Description: WebSSH的业务逻辑
       * @Author: NoCortY
       * @Date: 2020/3/7
       */
      public interface WebSSHService {
          /**
           * @Description: 初始化ssh连接
           * @Param:
           * @return:
           * @Author: NoCortY
           * @Date: 2020/3/7
           */
          public void initConnection(WebSocketSession session);
      
          /**
           * @Description: 处理客户段发的数据
           * @Param:
           * @return:
           * @Author: NoCortY
           * @Date: 2020/3/7
           */
          public void recvHandle(String buffer, WebSocketSession session);
      
          /**
           * @Description: 数据写回前端 for websocket
           * @Param:
           * @return:
           * @Author: NoCortY
           * @Date: 2020/3/7
           */
          public void sendMessage(WebSocketSession session, byte[] buffer) throws IOException;
      
          /**
           * @Description: 关闭连接
           * @Param:
           * @return:
           * @Author: NoCortY
           * @Date: 2020/3/7
           */
          public void close(WebSocketSession session);
      }
      

      现在我们可以根据这个接口去实现我们定义的功能了。

      1. 初始化连接

        由于我们的底层是依赖jsch实现的,所以这里是需要使用jsch去建立连接的。而所谓初始化连接,实际上就是将我们所需要的连接信息,保存在一个Map中,这里并不进行任何的真实连接操作。为什么这里不直接进行连接?因为这里前端只是连接上了WebSocket,但是我们还需要前端给我们发来linux终端的用户名和密码,没有这些信息,我们是无法进行连接的。

        public void initConnection(WebSocketSession session) {
                JSch jSch = new JSch();
                SSHConnectInfo sshConnectInfo = new SSHConnectInfo();
                sshConnectInfo.setjSch(jSch);
                sshConnectInfo.setWebSocketSession(session);
                String uuid = String.valueOf(session.getAttributes().get(ConstantPool.USER_UUID_KEY));
                //将这个ssh连接信息放入map中
                sshMap.put(uuid, sshConnectInfo);
        }
        
      2. 处理客户端发送的数据

        在这一步骤中,我们会分为两个分支。

        第一个分支:如果客户端发来的是终端的用户名和密码等信息,那么我们进行终端的连接。

        第二个分支:如果客户端发来的是操作终端的命令,那么我们就直接转发到终端并且获取终端的执行结果。

        具体代码实现:

        public void recvHandle(String buffer, WebSocketSession session) {
                ObjectMapper objectMapper = new ObjectMapper();
                WebSSHData webSSHData = null;
                try {
                    //转换前端发送的JSON
                    webSSHData = objectMapper.readValue(buffer, WebSSHData.class);
                } catch (IOException e) {
                    logger.error("Json转换异常");
                    logger.error("异常信息:{}", e.getMessage());
                    return;
                }
            //获取刚才设置的随机的uuid
                String userId = String.valueOf(session.getAttributes().get(ConstantPool.USER_UUID_KEY));
                if (ConstantPool.WEBSSH_OPERATE_CONNECT.equals(webSSHData.getOperate())) {
                    //如果是连接请求
                    //找到刚才存储的ssh连接对象
                    SSHConnectInfo sshConnectInfo = (SSHConnectInfo) sshMap.get(userId);
                    //启动线程异步处理
                    WebSSHData finalWebSSHData = webSSHData;
                    executorService.execute(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                //连接到终端
                                connectToSSH(sshConnectInfo, finalWebSSHData, session);
                            } catch (JSchException | IOException e) {
                                logger.error("webssh连接异常");
                                logger.error("异常信息:{}", e.getMessage());
                                close(session);
                            }
                        }
                    });
                } else if (ConstantPool.WEBSSH_OPERATE_COMMAND.equals(webSSHData.getOperate())) {
                    //如果是发送命令的请求
                    String command = webSSHData.getCommand();
                    SSHConnectInfo sshConnectInfo = (SSHConnectInfo) sshMap.get(userId);
                    if (sshConnectInfo != null) {
                        try {
                            //发送命令到终端
                            transToSSH(sshConnectInfo.getChannel(), command);
                        } catch (IOException e) {
                            logger.error("webssh连接异常");
                            logger.error("异常信息:{}", e.getMessage());
                            close(session);
                        }
                    }
                } else {
                    logger.error("不支持的操作");
                    close(session);
                }
        }
        
      3. 数据通过websocket发送到前端

        public void sendMessage(WebSocketSession session, byte[] buffer) throws IOException {
                session.sendMessage(new TextMessage(buffer));
        }
        
      4. 关闭连接

        public void close(WebSocketSession session) {
            //获取随机生成的uuid
                String userId = String.valueOf(session.getAttributes().get(ConstantPool.USER_UUID_KEY));
                SSHConnectInfo sshConnectInfo = (SSHConnectInfo) sshMap.get(userId);
                if (sshConnectInfo != null) {
                    //断开连接
                    if (sshConnectInfo.getChannel() != null) sshConnectInfo.getChannel().disconnect();
                    //map中移除该ssh连接信息
                    sshMap.remove(userId);
                }
        }
        

      至此,我们的整个后端实现就结束了,由于篇幅有限,这里将一些操作封装成了方法,就不做过多展示了,重点讲逻辑实现的思路吧。接下来我们将进行前端的实现。

    前端实现

    前端工作主要分为这么几个步骤:

    1. 页面的实现
    2. 连接WebSocket并完成数据的接收并回写
    3. 数据的发送

    所以我们一步一步来实现它。

    • 页面实现

      页面的实现很简单,我们只不过需要在一整个屏幕上都显示终端那种大黑屏幕,所以我们并不用写什么样式,只需要创建一个div,之后将terminal实例通过xterm放到这个div中,就可以实现了。

      <!doctype html>
      <html>
      <head>
          <title>WebSSH</title>
          <link rel="stylesheet" href="../css/xterm.css" />
      </head>
      <body>
      <div id="terminal" style="width: 100%;height: 100%"></div>
      
      <script src="../lib/jquery-3.4.1/jquery-3.4.1.min.js"></script>
      <script src="../js/xterm.js" charset="utf-8"></script>
      <script src="../js/webssh.js" charset="utf-8"></script>
      <script src="../js/base64.js" charset="utf-8"></script>
      </body>
      </html>
      
    • 连接WebSocket并完成数据的发送、接收、回写

      openTerminal( {
          //这里的内容可以写死,但是要整合到项目中时,需要通过参数的方式传入,可以动态连接某个终端。
              operate:'connect',
              host: 'ip地址',
              port: '端口号',
              username: '用户名',
              password: '密码'
          });
          function openTerminal(options){
              var client = new WSSHClient();
              var term = new Terminal({
                  cols: 97,
                  rows: 37,
                  cursorBlink: true, // 光标闪烁
                  cursorStyle: "block", // 光标样式  null | 'block' | 'underline' | 'bar'
                  scrollback: 800, //回滚
                  tabStopWidth: 8, //制表宽度
                  screenKeys: true
              });
      
              term.on('data', function (data) {
                  //键盘输入时的回调函数
                  client.sendClientData(data);
              });
              term.open(document.getElementById('terminal'));
              //在页面上显示连接中...
              term.write('Connecting...');
              //执行连接操作
              client.connect({
                  onError: function (error) {
                      //连接失败回调
                      term.write('Error: ' + error + '\r\n');
                  },
                  onConnect: function () {
                      //连接成功回调
                      client.sendInitData(options);
                  },
                  onClose: function () {
                      //连接关闭回调
                      term.write("\rconnection closed");
                  },
                  onData: function (data) {
                      //收到数据时回调
                      term.write(data);
                  }
              });
          }
      

    效果展示

    • 连接

      连接

    • 连接成功

      连接成功

    • 命令操作

      ls命令:

      ls命令

      vim编辑器:

      vim编辑器

      top命令:

      top命令

    结语

    这样我们就完成了一个webssh项目的实现,没有依赖其它任何的组件,后端完全使用Java实现,由于用了SpringBoot,非常容易部署。

    但是,我们还可以对这个项目进行扩展,比如新增上传或下载文件,就像Xftp一样,可以很方便地拖拽式上传下载文件。

    这个项目之后我会持续更新,上述功能也会慢慢实现,Github:https://github.com/NoCortY/WebSSH

    喜欢可以给个Star哦~

    欢迎大家访问我的个人博客:Object’s Blog

    展开全文
  • Web网页登录页面设计

    2020-03-09 23:40:56
    利用web网页设计技术(html+css)进行静态登录页面设计开发,包含源代码 ,以及网页所用的图片
  • webapi接口访问验证是否登陆的解决方案!每次访问接口都需要验证用户是否登陆
  • [经验之谈]web项目访问资源报错404

    千次阅读 2019-09-03 15:25:25
    2.其次考虑web.xml配置的前端控制器的dispatcher的拦截路径配置是否与资源路径一致,下面放上错误案例 前端控制器 <!-- 前端控制器(加载classpath:springmvc.xml 服务器启动创建servlet) --> <servlet>...

    1.首先考虑路径是否正确
    2.其次考虑web.xml配置的前端控制器的dispatcher的拦截路径配置是否与资源路径一致,下面放上错误案例

    前端控制器

    <!-- 前端控制器(加载classpath:springmvc.xml 服务器启动创建servlet) -->
        <servlet>
            <servlet-name>dispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 配置初始化参数,创建完DispatcherServlet对象,加载springmvc.xml配置文件 -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:spring-mvc.xml</param-value>
            </init-param>
            <!-- 服务器启动的时候,让DispatcherServlet对象创建 -->
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
    

    可以看到 web.xml 拦截路径配置为 *.do

        @RequestMapping("/findAll")
        public ModelAndView findAll(){
            ModelAndView modelAndView = new ModelAndView();
            List<Product> ps = service.findAll();
            modelAndView.addObject("productList",ps);
            modelAndView.setViewName("product-list");
            return modelAndView;
        }
    

    而controller层中没有 *.do 后缀, 所以这样去访问也会报错404.

    展开全文
  • 服务器在运行时为了安全,必须开启防火墙,但是在将防火墙全部开启之后,外部就不能访问应用了,在这种情况下,需要我们自己手动配置如站规则,主要是添加端口的入站规则,80,443,3306的 点击启动或关闭防火墙。...
  • H3C配置Web登陆

    千次阅读 2018-05-01 16:05:00
    2.创建web登陆的用户。 [H3C]local-user king //创建一个用户名为king [H3C-luser-manage-king]password simple 123456 //密码为123456 [H3C-luser-manage-king]authorization-attribute user-role level-15 //...
  • 主机访问虚拟机的web项目

    千次阅读 2020-04-17 23:00:50
    主机使用虚拟机的地址访问虚拟机的web项目。 第一:虚拟机关闭防火墙,主机也关闭防火墙。 第二:查看虚拟机的ip地址,使用ifconfig。 第三:打开虚拟机的,设置 ,在网络适配器中选择NAT模式 第四:点击...
  • 如何实现一个安全的Web登陆

    千次阅读 2017-10-14 20:20:06
    综述:待 Update:QUIC, SSO, HSTS等协议研究,SHA-1 可破解总结: 没有绝对的安全,能不自己做就不自己做, ... 单纯谈论偏向登陆会话过程思维养成key: 时间, 信任无解问题: CSRF, 中间人攻击(有应对方案,但
  • 通过手机访问本地web应用

    千次阅读 2017-10-19 18:19:34
    一直做android终端开发,对于服务器就是一小白,想尝试下服务器端的...用浏览器访问:http://localhost:8080/ 看到下面页面说明server启动了: 如果想上传文件到web应用,进入\webapps\ROOT,放一个文件到该目录下,比
  • HTML+CSS登陆界面实例

    万次阅读 多人点赞 2020-02-02 10:44:32
    项目访问地址 将登录界面项目部署在了github上面:点我 项目代码解析 项目的界面简析 主要部分是Login的模块,包括username文本框和password文本框以及Login的按钮 将Login模块进行居中,并且设置背景半透明 添加...
  • H3C5120;5130交换机开启web访问配置

    万次阅读 2019-04-17 09:36:42
    authorization-attribute level 15 ----设置权限级别15级(个别型号交换机设置为3级,如果打不开web可以换一下,或者咨询售后) service-type telnet–开启telnet service-type terminal–开启terminal (开启...
  • idea中Java Web项目的访问路径问题

    万次阅读 多人点赞 2018-05-08 18:38:00
    在 idea 中新建一个 Java Web 项目,项目的初始结构如下 ( 不同版本的 idea 可能略有区别 ) : 默认访问路径** - 当我们将项目的基本配置设置好后,启动 Tomcat,会发现直接出现的是 index.jsp 页面,此时浏览
  • kafka-eagle搭建 web无法访问

    万次阅读 2020-03-22 12:47:00
    一、kafka下载二进制压缩包和搭建 ...其中细节:使用单台机器搭建kafka时候是否安装mysql问题...问题一:./ke.sh start start能够启动,但是无法访问web ui页面的问题 1.需要注意添加配置项(system-config.properties ...
  • 使用 IP 地址访问 Web 服务器 首先打开 Wireshark,选择 ”HTTP TCP port(80)“ 过滤器,再鼠标双击 ”Npcap loopback A dapter“,开始抓取本机 127.0.0.1 地址上的网络数据。 接着在 Chrome 浏览器地址栏输入”...
  • websphere登陆页面访问出现错误,错误如下: A communication error occurred: "Operation timed out" The Web Server may be down, too busy, or experiencing other problems preventing it from responding to...
  • Elasticsearch无法登陆Web页面

    千次阅读 2019-03-07 10:36:32
    Elasticsearch无法登陆Web页面 问题: Elasticsearch 安装配置后,无法进入web页面,Log文件中没有报错信息,但是登陆 ip:9200 页面时,却显示是否要下载Json文件,并且无法正常登陆Web页面 解决方法: 其实就是360浏览器和...
  • Java Web 默认访问首页方式

    千次阅读 2018-07-30 17:02:13
    1.在工程的web.xml文件中配置 &lt;welcome-file-list&gt; &lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt; &lt;/welcome-file-list&gt; 2.使用Urlrewrit地址重写,首先是...
  • Cisco3850交换机设置web GUI访问

    千次阅读 2019-01-07 17:30:41
    启用Cisco3850交换机的web访问需进行以下设置: 启用ip http server服务(3850默认启用),以下CLI命令开启Controller(config)#ip http server2.CLI下创建用户名和密码,切必须创建的用户有15级访问权限。...
  • 华为云服务有个活动(访问网址:http://www.hwclouds.com/),通过认证后可以免费领取六个月 的云服务器使用权限,所以我也比较好奇地申请了一个,想部署自己的web项目。结果等部署完成后发现不能通过公网访问,而且...
  • 华为AC设备登陆web网管(ensp模拟)

    千次阅读 2021-05-15 23:08:27
    华为AC设备登陆web网管(ensp模拟) 实验环境: OS:windows10 模拟器:eNSP V100R003C00SPC100 虚拟软件:VirtualBox-5.2.44-139111-Win.exe 网络拓扑图 设备的接入端口已配置IP地址,该IP地址需要保证和您绑定的...
  • 1.由于我的rabbitmq是用apt-get安装,所以直接执行sudo rabbitmq-plugins enable...2.创建访问用户 rabbitmqctl add_vhost scanos rabbitmqctl add_user scanos 1qaz2wsx rabbitmqctl set_permissions -p "scanos" s...
  • 华为配置telnet和ssh访问
  • [Huawei-aaa]q [Huawei]user-interface vty 0 4 #进入VTY0~VTY4用户界面视图 [Huawei-ui-vty0-4]authentication-mode aaa #配置VTY类型用户界面的验证方式为AAA 配置用户通过web登录设备(真机演示) web登陆其实和...
  • 在上一篇文章中讲到了maven项目的springmvc和mybatis整合,下面我们讲两个小点:web项目访问的默认页面设置和登录拦截 1.web项目访问的默认页面 一、首先建一个在webapp下的页面login.jsp 二、...
  • Java Web简单登陆功能的实现

    千次阅读 2018-09-13 16:00:39
    数据库名叫db_jxgl,里面只有一张student表,具体请看下图: 使用过IDEA之后好像从农村来到了城市,太TM强大了!... 先创建数据库访问类: package com.jmdx.bingo.sql; import java.sql.*; import java....
  • 基于域名访问web服务器

    千次阅读 2019-03-19 02:00:47
    创建基于域名的虚拟主机,能够使用www.xiaopang.com和www.dapang.com访问各自网站,存放路径分别为/www/xiaopang和/www/dapang 第一步:创建目录 [root@catyuan ~]# mkdir /www/{dapang,xiaopang} -p 第二步:修改...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 154,804
精华内容 61,921
关键字:

web登陆访问