• 2020课程设计——小组报告


    2020课程设计——小组报告

    课程设计项目:基于Gmssl的CA系统构建及应用

    小组成员姓名学号:

    20181211沈芮吉

    20181212滕珠江

    20181312谢绎

    指导老师:娄嘉鹏

    提交日期:2020年11月8日

    一、设计方案及可行性分析

    (一)分析选题

    1.Gmssl

    了解gmssl中的命令,描述支持的选项、场景和参数,制作成文档;

    在Ubuntu虚拟机下安装gmssl,利用-help命令查看或者使用man命令等等方式,在提示下并理解使用gmssl分工完成文档。

    2.使用OpenSSL搭建CA

    颁发证书、签名验签、模拟用户和颁发机构,查看证书等

    (1)建立根CA——RootCA(自己给自己颁发证书)

    生成私钥文件

    生成自签名证书(CA要有证书)

    (2)用户服务器申请证书,CA服务器颁发证书

    生成私钥

    生成证书申请文件

    将申请文件发给CA

    (3)CA颁发证书--用自己的私钥签名
    (4)证书发送客户端
    (5)在应用软件中使用证书

    3.制作网站,通过https访问

    安装Tomcat,修改Tomcat中conf文件夹中的server.xml,注释掉有关端口8080的代码,加入或者修改一段端口为8443的代码,使得https开放,修改上次制作的用户证书里的common name为localhost。
    由于网站的证书是自建CA签名的,浏览器并不信任,所以需要手动导入CA证书。
    以chrome为例:设置->高级->隐私设置和安全性->管理证书
    可以查看证书详细信息和导入自建CA证书

    起初我们设计准备在虚拟机中进行,但是考虑到虚拟机内存大小,Tomcat,java代码运行等等方面,最终选择在主机实现。

    (二)模型

    1、创建CA

    生成一对用于制作自签证书的密钥

    生成自签证书

    2、客户端(相对于CA而言的客户端)

    生成一对用于申请CA证书密钥

    生成证书颁发请求;

    将请求发给CA

    3、CA端

    签署证书

    将签署完成的证书传送给客户端

    (三)设计方案

    (四)可行性分析

    我们的目标是实现通过https访问,其中制作根证书、颁发证书、签名等等十分重要,OpenSSL十分有效。

    OpenSSL 是一个安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用。密钥和证书管理是PKI的一个重要组成部分,OpenSSL为之提供了丰富的功能,支持多种标准。

    首先,OpenSSL实现了ASN.1的证书和密钥相关标准,提供了对证书、公钥、私钥、证书请求以及CRL等数据对象的DER、PEM和BASE64的编解码功能。OpenSSL提供了产生各种公开密钥对和对称密钥的方法、函数和应用程序,同时提供了对公钥和私钥的DER编解码功能。并实现了私钥的PKCS#12和PKCS#8的编解码功能。OpenSSL在标准中提供了对私钥的加密保护功能,使得密钥可以安全地进行存储和分发。

    OpenSSL实现了对证书的X.509标准编解码、PKCS#12格式的编解码以及PKCS#7的编解码功能。并提供了一种文本数据库,支持证书的管理功能,包括证书密钥产生、请求产生、证书签发、吊销和验证等功能。

    因而使用OpenSSL搭建CA十分有效。

    二、详细设计思路

    (一)系统体系结构、技术选择

    1.证书的申请签署步骤

    2.单向认证:不需要客户拥有CA证书,即不需要服务器端验证客户证书的过程

    使用openssl命令+tomcat配置的实现过程:

    3.双向认证:需要服务端与客户端提供身份认证

    使用openssl+keytools命令+tomcat配置的实现过程:

    4.最终技术选择

    基于openssl的CA系统构建

    基于tomcat和自建CA的https网站部署

    (二)生成CA根证书和浏览器证书流程图

    (三)证书生成命令行解析

    1.生成CA证书,在/root目录下新建一个ca文件夹,并在ca文件夹下创建四个子文件夹

    • newcerts目录将用于存放CA签署过的数字证书。
    • private目录用于存放CA的私钥。
    • conf目录用于存放一些简化参数用的配置文件。
    • server目录存放服务器证书文件。

    2.在conf目录下新建一个包含如下信息的openssl.conf文件

    su root
    mkdir ca
    cd ca
    mkdir newcerts private conf server
    cd conf/
    vim openssl.conf
    
    [ ca ]
    default_ca = foo
    [ foo ] 
    dir = /home/tzj/ca
    database = $dir/index.txt
    new_certs_dir = $dir/newcerts
    certificate = $dir/private/ca.crt
    serial = $dir/serial
    private_key = $dir/private/ca.key
    RANDFILE = $dir/private/.rand
    default_days = 365
    default_crl_days= 30
    default_md = md5
    unique_subject = no
    policy = policy_any
    [ policy_any ]
    countryName = match
    stateOrProvinceName = match
    organizationName = match
    organizationalUnitName = match
    localityName = optional
    commonName      = supplied
    emailAddress    = optional
    

    3.生成私钥key文件

    openssl genrsa -out private/ca.key
    

    4.执行如下命令,按照提示输入所需信息,然后按下回车键生成证书请求csr文件

    openssl req -new -key private/ca.key -out private/ca.csr
    

    5.执行如下命令,生成凭证crt文件

    openssl x509 -req -days 365 -in private/ca.csr -signkey private/ca.key -out private/ca.crt
    

    6.执行如下命令,为CA的key设置起始序列号,可以是任意四个字符,创建CA键库

    echo 1212 > serial
    touch index.txt
    

    7.执行如下命令,为移除客户端证书创建一个证书撤销列表

    openssl ca -gencrl -out /root/ca/private/ca.crl -crldays 7 -config "/home/tzj/ca/conf/openssl.conf"
    

    8.为客户端证书签名,执行如下命令,在ca目录内创建一个存放客户端key的目录users,为客户端创建一个key

    mkdir users
    openssl genrsa -des3 -out /home/tzj/ca/users/client.key 1024
    

    9.执行如下命令,为客户端key创建一个证书签名请求csr文件

    openssl req -new -key /home/tzj/ca/users/client.key -out /home/tzj/ca/users/client.csr
    

    10.执行如下命令,使用CA证书的key为客户端key签名

    openssl ca -in /home/tzj/ca/users/client.csr -cert /home/tzj/ca/private/ca.crt -keyfile /home/tzj/ca/private/ca.key -out /home/tzj/ca/users/client.crt -config "/home/tzj/ca/conf/openssl.conf"
    

    11.将证书转换为PKCS12文件

    openssl pkcs12 -export -clcerts -in /home/tzj/ca/users/client.crt -inkey /home/tzj/ca/users/client.key -out /home/tzj/ca/users/client.p12
    

    (四)列出测试目的、测试内容、测试结果,并对结果进行分析

    1.测试目的:测试生成的证书是否能部署到自己制作的网站上,使得网站能用https访问

    2.测试内容和测试结果:

    在tomcat/conf中加入client.p12并修改conf/server.xml,增加一段代码并注释原来的一行代码:

    在Firefox中(工具-选项-高级-加密-查看证书-您的证书),将private/ca.crt导入证书颁发机构

    运行tomcat/bin/startup.bat,启动tomcat

    用https访问,发现可以安全访问

    前面的步骤不变,在IE中导入根证书private/ca.crt

    但发现显示证书风险,此问题尚未解决

    三、设计特色

    (一)基于OpenSSL的CA系统构建

    1.OpenSSL

    OpenSSL是一个开放源代码的软件库包,应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。这个包广泛被应用在互联网的网页服务器上。

    OpenSSL包含一个命令行工具用来完成OpenSSL库中的所有功能。

    OpenSSL是一个强大的安全套接字层密码库,Apache使用它加密HTTPS,OpenSSH使用它加密SSH,但是,它还是一个多用途的、跨平台的密码工具。

    OpenSSL能保证安全信道的数据保密性、数据完整性和安全验证功能。

    OpenSSL整个软件包大概可以分成三个主要的功能部分:SSL协议库、应用程序以及密码算法库。OpenSSL的目录结构自然也是围绕这三个功能部分进行规划的。

    作为一个基于密码学的安全开发包,OpenSSL提供的功能相当强大和全面,囊括了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议,并提供了丰富的应用程序供测试或其它目的使用。

    2.CA系统

    CA是证书的签发机构,它是公钥基础设施(Public Key Infrastructure,PKI)的核心。CA是负责签发证书、认证证书、管理已颁发证书的机关。

    CA 拥有一个证书(内含公钥和私钥)。网上的公众用户通过验证 CA 的签字从而信任 CA ,任何人都可以得到 CA 的证书(含公钥),用以验证它所签发的证书。

    如果用户想得到一份属于自己的证书,他应先向 CA 提出申请。在 CA 判明申请者的身份后,便为他分配一个公钥,并且 CA 将该公钥与申请者的身份信息绑在一起,并为之签字后,便形成证书发给申请者。

    如果一个用户想鉴别另一个证书的真伪,他就用 CA 的公钥对那个证书上的签字进行验证,一旦验证通过,该证书就被认为是有效的。证书实际是由证书签证机关(CA)签发的对用户的公钥的认证。

    证书的内容包括:电子签证机关的信息、公钥用户信息、公钥、权威机构的签字和有效期等等。证书的格式和验证方法普遍遵循X.509 国际标准。

    3.OpenSSL对CA系统的支持

    密钥证书管理

    密钥和证书管理是PKI的一个重要组成部分,OpenSSL为之提供了丰富的功能,支持多种标准。

    首先,OpenSSL实现了ASN.1的证书和密钥相关标准,提供了对证书、公钥、私钥、证书请求以及CRL等数据对象的DER、PEM和BASE64的编解码功能。OpenSSL提供了产生各种公开密钥对和对称密钥的方法、函数和应用程序,同时提供了对公钥和私钥的DER编解码功能。并实现了私钥的PKCS#12和PKCS#8的编解码功能。OpenSSL在标准中提供了对私钥的加密保护功能,使得密钥可以安全地进行存储和分发。

    在此基础上,OpenSSL实现了对证书的X.509标准编解码、PKCS#12格式的编解码以及PKCS#7的编解码功能。并提供了一种文本数据库,支持证书的管理功能,包括证书密钥产生、请求产生、证书签发、吊销和验证等功能。

    事实上,OpenSSL提供的CA应用程序就是一个小型的证书管理中心(CA),实现了证书签发的整个流程和证书管理的大部分机制。

    SSL和TLS协议

    OpenSSL实现了SSL协议的SSLv2和SSLv3,支持了其中绝大部分算法协议。OpenSSL也实现了TLSv1.0,TLS是SSLv3的标准化版,虽然区别不大,但毕竟有很多细节不尽相同。

    虽然已经有众多的软件实现了OpenSSL的功能,但是OpenSSL里面实现的SSL协议能够让我们对SSL协议有一个更加清楚的认识,因为至少存在两点:一是OpenSSL实现的SSL协议是开放源代码的,我们可以追究SSL协议实现的每一个细节;二是OpenSSL实现的SSL协议是纯粹的SSL协议,没有跟其它协议(如HTTP)协议结合在一起,澄清了SSL协议的本来面目。

    对称加密
    非对称加密
    信息摘要

    (二)基于tomcat和自建CA的https网站部署

    1.Tomcat

    Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。

    Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。

    2.HTTPS

    HTTPS(全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS 在HTTP 的基础下加入SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。它被广泛用于万维网上安全敏感的通讯,例如交易支付等方面。

    HTTP 原理

    ① 客户端的浏览器首先要通过网络与服务器建立连接,该连接是通过TCP 来完成的,一般 TCP 连接的端口号是80。 建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是 MIME 信息包括请求修饰符、客户机信息和许可内容。

    ② 服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是 MIME 信息包括服务器信息、实体信息和可能的内容。

    HTTPS 原理

    ① 客户端将它所支持的算法列表和一个用作产生密钥的随机数发送给服务器;

    ② 服务器从算法列表中选择一种加密算法,并将它和一份包含服务器公用密钥的证书发送给客户端;该证书还包含了用于认证目的的服务器标识,服务器同时还提供了一个用作产生密钥的随机数;

    ③ 客户端对服务器的证书进行验证(有关验证证书,可以参考数字签名),并抽取服务器的公用密钥;然后,再产生一个称作 pre_master_secret 的随机密码串,并使用服务器的公用密钥对其进行加密(参考非对称加 / 解密),并将加密后的信息发送给服务器;

    ④ 客户端与服务器端根据 pre_master_secret 以及客户端与服务器的随机数值独立计算出加密和 MAC密钥(参考 DH密钥交换算法);

    ⑤ 客户端将所有握手消息的 MAC 值发送给服务器;

    ⑥ 服务器将所有握手消息的 MAC 值发送给客户端。

    HTTPS优点

    ① 使用 HTTPS 协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;

    ② HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 HTTP 协议安全,可防止数据在传输过程中被窃取、改变,确保数据的完整性。

    ③ HTTPS 是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。

    四、源代码及注释

    (一)注册界面核心代码

    1.通过div标签进行分块布局,并对每个块进行css修饰

    <div>
    	<h1>标题</h1>
    <div class="container">主体容器,使用display: flex布局嵌套左右两块
    		<div class="w3l_form">嵌套三个文字部分内容
    			<h3></h3>
    			<h4></h4>
    			<p></p>
    </div>
    		<div class="w3_info">嵌套文字说明内容和form表单
    			<h2></h2>
    			<p></p>
    			<form action="login.html" method="post" onsubmit="return finalCheck()">
    <!--提交时进行finalcheck,具体js代码见 2.JavaScript代码部分
    四个信息输入框分别用四个<div class="input-group"></div>来包含
    email、password、confirm需要使用js,具体代码见 2.JavaScript代码部分-->
    </form>
    </div>
    </div> 
    <div>页脚</div>
    </div>
    

    2.JavaScript代码部分

    (1)提交页面时触发
    function finalCheck() {
            var user = document.getElementById("user").value;
            var pw_1 = document.getElementById("pw_1").value;
            var pw_2 = document.getElementById("pw_2").value;
            var email = document.getElementById("email").value;
    //通过document.getElementById操作获取每一个表单域中的值,便于下面进行验证
            var passwordReg=/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6}$/;  //正则表达式,形式为/^完整表达式$/ ,(?![0-9]+$)表示整个字符串不能全是数字,(?![a-zA-Z]+$) 表示整个字符串不能全是字母,[0-9A-Za-z]{6}表示整个字符串由6位数字和字母组成。
            if(user != "") {//用户名不能为空
              if(pw_1 != "" && passwordReg.test(pw_1)){//密码不为空,且符合正则表达式规定的格式
                if(pw_1 == pw_2){//两次密码输入一致
                  alert("信息填写正确,可以正常提交!");
        					console.log("信息填写正确,可以正常提交!");
                  Store(email,pw_1);//调用Store函数进行本地存储
        					return true;
                  returnLogin();
                } else {
                  alert("密码不一致,提交失败,请重新填写!");
        					console.log("密码不一致,提交失败,请重新填写!");
        					return false;
                }
              } else {
                alert("密码格式错误,提交失败,请重新填写!");
      				  console.log("密码格式错误,提交失败,请重新填写!");
      				  return false;
              }
            } else {
              alert("注册的账号不符合要求,提交失败,请重新填写!");
      			  console.log("注册的账号不符合要求,提交失败,请重新填写!");
      			  return false;
           }
          } 
    function Store(email, pw_1,user) {
    // 使用 localStorage 创建本地存储的 Em/value和 Pw/value和user/value对
          var storage = window.localStorage;
          storage.setItem("Em", email);
          storage.setItem("Pw", pw_1);
          storage.setItem("user", user);
    } 
    //在静态界面中利用localStorage 是否创建本地存储来判断是否登录
    var storage = window.localStorage;//获取本地存储
    var who=storage.user;//获取本地存储中的user
    console.log(who);//便于在控制台查看是否存在本地存储
    function isEmpty(obj){//构造一个辅助函数来判断obj字段是否为空或未定义,用于下面的load()函数
        if(typeof obj == "undefined" || obj == null || obj == ""){
            return true;
        }else{
            return false;
        }
    }
    function load(){
    		if(!isEmpty(who)){//如果who不空,则说明是已注册登录用户
    			document.getElementById("login").innerHTML=who;
    //将登录选项卡中的html内容修改为用户名
    			var child=document.getElementById("register");
    			child.parentNode.removeChild(child); //通过获取Id来删除静态主页上的注册选项卡
    	}
    }
    
    (2)在对象失去焦点时触发事件:
    onblur ="checkEm(this.value) ",onblur="checkPw(this.value)",onblur="checkPwagain(this.value)" 
    function checkEm(Em) {
          var temp = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/;//正则表达式
          if (Em != "" && temp.test(Em)) {
            document.getElementById("remind_4").innerHTML = "邮箱格式正确";
            document.getElementById("remind_4").style.color = "green";//通过js修改css样式
          } else if (Em != "" && !temp.test(Em)) {
            document.getElementById("remind_4").innerHTML = "邮箱格式错误";
            document.getElementById("remind_4").style.color = "red";
          } else {
            document.getElementById("remind_4").innerHTML = "邮箱不能为空";
            document.getElementById("remind_4").style.color = "red";
          }
    }
    checkPw(pw_1)与checkEm(Em)类似,正则表达式修改为/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6}$/
    function checkPwagain(pw_2) {
          var pw_1 = document.getElementById("pw_1").value;
          if (pw_2 == "") {
            document.getElementById("remind_3").innerHTML = "密码不能为空";
            document.getElementById("remind_3").style.color = "red";
          } else if (pw_1 == pw_2) {
            document.getElementById("remind_3").innerHTML = "两次输入密码相同";
            document.getElementById("remind_3").style.color = "green";
          } else {
            document.getElementById("remind_3").innerHTML = "两次输入密码不一致";
            document.getElementById("remind_3").style.color = "red";
          }
    }
    

    (二)登录界面核心代码

    1.通过div标签进行分块布局,并对每个块进行css修饰

    <div>
    	<h1>标题</h1>
    <div class="container">主体容器,使用display: flex布局嵌套左右两块
    	<div class="w3l_form">嵌套一个<div>包裹的<img>、三个文字部分以及一组图片栏内容
    		<div id="stage">
    <img class="box x" src="../img/12.jpg" alt="" width="304" height="133">
    </div>
    <h3></h3>
    	    <h4></h4>
    	    <p></p>
    <div id="imglist">
    			    <div class="pol rotate-left float-left"><img src="../img/15.jpg" alt=""></div>
    			    <div class="pol float-left"><img src="../img/13.jpg" alt=""></div>
                    <div class="pol rotate-right float-right"><img src="../img/16.jpg" alt=""></div>
    		 </div>
    </div>
    	<div class="w3_info">嵌套文字说明内容和form表单
    		  <h2></h2>
    		  <p></p>
    		  <form action=" test.html" method="post" onsubmit="return finalCheck()">
    <!--两个信息输入框分别用四个<div class="input-group"></div>来包含-->
    </form>
    </div>
    <div>页脚</div>
    </div>
    

    2.CSS代码部分

    <style>
    #stage{
    		perspective:100px;
    		margin-bottom:10px;
    		}/*透视效果在舞台这层表现*/
    .box{
    		margin-top:3px;
    	    padding:4px;/*图片距离边框*/
    		background-color:#eee;
    		transition:linear 1s;/*使其具有渐进效果*/
    		transform-style:preserve-3d;/*3D变换的代码*/
    }
    .x:hover{//鼠标悬浮式实现3D旋转效果
    		transform:rotateX(360deg);
    		}
    .pol{
    	96px;/*每个图片所在的宽度*/
    	padding:2px;/*图片距离边框*/
    	background-color:#eee;
    	border:1px solid #bfbfbf;
    	box-shadow:1px 1px 2px #3F9;
    	border-radius:5px;/*圆角边框*/
    }
    .rotate-left{
    	transform:rotate(7deg);
    }
    .rotate-right{
    	transform:rotate(-7deg);
    }
    </style>
    

    (三)静态页面核心代码

    1.此部分为轮播图单独测试

    #wrapper {//主体
           550px;
           height: 300px;
           position: relative;//位置相对
           margin: 300px auto;
           cursor:pointer;//设定鼠标的形状为一只伸出食指的手
    }
    #wrapper:hover .btn{//选择鼠标指针浮动在其上的元素
           opacity: 1;//当鼠标在上面时元素的不透明级别:完全不透明即出现
           transition: all 0.6s;//指定过渡时间,产生过渡效果
    }
    .pic {
           position: absolute;
            550px;
           height: 300px;
           opacity:0;//鼠标不在按钮上时完全透明即隐身
           transition: all 0.8s;/指定过渡时间,产生过渡效果,时间比按钮长,效果更佳
    }
    .btn {
           position: absolute;
           top: 135px;
           background: none;
           border: none;
    }
    .btn img{
           position: absolute;
            50px;
           height: 50px;
         opacity:0.7;//鼠标在图片上按钮的效果,微微隐身
         z-index: 100;//z-index 属性设置元素的堆叠顺序越高越上面
    }
    #btnLeft {//向左按钮
         left: 10px;
    }
    #btnRight {//向右按钮
          right:60px;
    }
    .pic.active{
           z-index: 100;z-index 属性设置元素的堆叠顺序越高越上面
           opacity: 1;
    }
    .point {
           list-style: none;//把图像设置为列表中的列表项目标记
           position: absolute;
           right: 20px;
           bottom: 15px;
           z-index: 300;//z-index 属性设置元素的堆叠顺序越高越上面
           margin-bottom: 0;
    }
    .pot {
           margin-left: 12px;
            8px;
           height: 8px;
           border: 2px solid rgba(255,255,255,0.8); //线宽,实线,颜色
           float: left;
           border-radius: 100%;//圆形,后面应用时方形看上去更好看就放弃了
           background-color: rgba(0,0,0,0.4);
    }
    .pot.active {
       background-color: rgba(243,149,176,1);//在该图片展示时即激活时的颜色
    }
    

    2.轮播图的js文件

    let pics = document.getElementsByClassName('pic');
    let btnL = document.getElementById('btnLeft');
    let btnR = document.getElementById('btnRight');
    let points = document.getElementsByClassName('pot');
    let swiper = document.getElementById('wrapper');
    //index表示第几张图片在展示——>第index张图片有active这个类名
    let index = 0;
    //存储时间
    let time = null;
    let clearPics = ()=> {
        //全部去掉active类名
        for (let i =0; i<pics.length; i++){
            pics[i].className = "pic"
        }
        for (let i =0; i<points.length; i++){
            points[i].className = "pot"
        }
    };
    let update = ()=> {
        clearPics();
        //,第index张图片有active类名
        pics[index].className = "pic active";
        points[index].className = "pot active";
    };
    //声明一个变量,每当执行一次btnNext函数变切换下一张图片并且添加active类名,当图片是最后一张时,下次切换回到初始图片
    let btnNext = ()=> {
      index ++;
      if(index === 5){
          index = 0;
      }
      //执行update()方法给图片添加active类名
      update();
    };
    //声明一个变量,每当执行一次btnText函数变切换上一张图片并且添加active类名,当图片是最后一张时,下次切换回到初始图片
    let btnText = ()=> {
        if (index === 0){
            index = 4;
        }else {
            index --;
        }
        //执行update()方法给图片添加active类名
        update();
    };
    //默认开启定时器每一秒钟切换下一张图片
    time=setInterval( ()=> {
        btnNext();
    },1000);
    //鼠标移入图片关闭定时器
    swiper.onmouseover =  ()=> {
        clearInterval(time);
    };
    //鼠标移出图片开启定时器,继续执行默认操作
    swiper.onmouseout = ()=> {
        time=setInterval( ()=> {
            btnNext();
        },1000);
    };
    //给右键按钮添加点击事件,每点击调用一次btnNext()函数
    btnR.addEventListener('click', ()=> {
        btnNext();
    });
    //给左键按钮添加点击事件,每点击调用一次btnText()函数
    btnL.addEventListener('click',()=> {
        btnText();
    });
    //先遍历所有的点给一个点添加点击事件
    for (let i=0; i<points.length; i++){
        points[i].addEventListener('click', function() {
            //声明一个变量用来存储当前的点是哪一位(在html里面给标签存入了数据)
            let opt = this.getAttribute('arr');
            //让把当前点击的点值跟index相等,这样就是保证当点击点的时候跳转到对应的图片
            index = opt;
            update();
        })
    }
    

    3.此部分为index页中APP推荐部分鼠标产生效果

    .card-img{//APP图片外框设置
    	overflow: hidden;//超出部分隐藏
    	position: relative;//位置相对
    }
    .overlay{//浅绿色浮上来的框设置
    	background: rgba(78,174,58,0.5);//背景颜色不知名土棕色
    	position: absolute;
    	bottom: -100%;//使得框可以从下面浮置上方
    	 100%;//在大的块里足宽
    	height: 100%;//在大的块里足高
    	left: 50%;//左边50%,中间位置
    	transform: translateX(-50%);//元素往左位移自身宽度50%的距离,整体居中
    	transition: all 0.3s;//产生过渡效果
    }
    .overlay i{//在浅绿色块里的十字箭头设置
    	font-size: 35px;
    	position: absolute;
    	top: 50%;//上面50%,中间位置
    	left: 50%;//左边50%,中间位置
    //垂直居中
    	transform: translateX(-50%);//元素往左位移自身宽度50%的距离,整体居中
    	color: #4e3914;
    }
    .fas {
      font-family: 'Font Awesome 5 Free';//Font Awesome 字体提供可缩放矢量图标
      font-weight: 900; //font-weight 属性设置文本的粗细
    }
    //:before 选择器在被选元素的内容前面插入内容
    .fa-arrows-alt:before {//网页使用Font Awesome图标字体时,css定义 content 属性
      content: "f0b2"; }
    .fa-arrows-alt-h:before {//网页使用Font Awesome图标字体时,css定义 content 属性
      content: "f337"; }
    .fa-arrows-alt-v:before {//网页使用Font Awesome图标字体时,css定义 content 属性
      content: "f338"; }
    <div class="card-img">//图片分块
         <a href="https://www.iqiyi.com">
             <img class="card-img-top vdpic" src="images/爱奇艺.jpg" alt="" />
              <div class="overlay"><i class="fas fa-arrows-alt"></i></div>
          </a>
     </div>
    
    

    4.此部分为movie界面里的页码部分

    .pagination_bar .pagination .page-item .page-link{//页码在大小块里的设置
    	font-size: 20px;//字宽
    	background: #4e3914;//背景不知名的土棕色
    	border: 1px solid #4e3914;//边框不知名的土棕色
    	color: #ffffff;//字黑
    	 35px;
    	text-align: center;//文字居中
    }
    .pagination_bar .pagination .page-item .page-link:hover{
    	background: #4eae3a;//鼠标放在页码的块上时变成绿色
    }
    //当页面被激活,即在该页码的页面时页码块变绿,字体仍为黑色
    .pagination_bar .pagination .page-item .page-link.active{	background: #4eae3a;
    	color: #ffffff;
    }
    .pagination_bar_arrow .pagination .page-item .page-link{
    	font-size: 20px;//字宽
    	background: #4e3914;//背景不知名的土棕色
    	border: 1px solid #4e3914;//边框不知名的土棕色
    	color: #ffffff;//字黑
    	 120px;
    	text-align: center;//文字居中
    }
    .pagination_bar_arrow .pagination .page-item .page-link:hover{
    	background: #4eae3a;
    }
    .sr-only {
      border: 0;
      clip: rect(0, 0, 0, 0);//clip 属性剪裁绝对定位元素,方形无修剪
      height: 1px;
      margin: -1px;
      overflow: hidden;//超出部分隐藏
      padding: 0;
      position: absolute;
       1px; }
    <div class="pagination_bar">
    		<!-- Pagination -->
    		<ul class="pagination justify-content-center">
    			<li class="page-item">//前一页
    				<a class="page-link" href="romance-page-1.html" aria-label="Previous">
    //aria-label属性用来给当前元素加上的标签描述,接受字符串作为参数
    				<span aria-hidden="true">&laquo;</span>//让这个元素对浏览器隐藏
    //&laquo特殊符号出现在html页面里的一种代码
    				<span class="sr-only">Previous</span>
    				</a>
    			</li>
    			<li class="page-item">//第一页
    				<a class="page-link active" href="romance-page-1.html">1</a>
    			</li>
    			<li class="page-item">//第二页
    				<a class="page-link" href="romance-page-2.html">2</a>
    			</li>
    			<li class="page-item">//第三页
    				<a class="page-link" href="romance-page-3.html">3</a>
    			</li>
    //调试过程中修改类说明和active
    			<li class="page-item">//后一页
    				<a class="page-link" href="romance-page-2.html" aria-label="Next">
    				<span aria-hidden="true">&raquo;</span>
    				<span class="sr-only">Next</span>
    				</a>
    			</li>
    	 </ul>
    </div>
    

    五、个人报告

    (一)小组贡献排序及依据(每个人的工作量):

    谢 绎(34%):学习openssl,调试代码命令,查阅资料,搭建CA,完成https访问,撰写课程报告。
    沈芮吉(33%):学习openssl,调试代码命令,查阅资料,搭建CA,完成https访问,撰写课程报告。
    滕珠江(33%):学习openssl,调试代码命令,查阅资料,搭建CA,完成https访问,撰写课程报告。

    (二)个人报告链接

    20181211沈芮吉

    20181212滕珠江

    20181312谢绎

  • 相关阅读:
    Django【进阶篇-缓存类型】
    深度剖析Kubernetes API Server三部曲
    深度剖析Kubernetes API Server三部曲
    深度剖析Kubernetes API Server三部曲
    Istio技术与实践03:最佳实践之sidecar自动注入
    原来你是这样的PaaS!
    5分钟APIG实战: 使用Rust语言快速构建API能力开放
    Log4J日志配置详解
    cookie是如何保存到客户端,又是如何发送到服务端
    session cookie
  • 原文地址:https://www.cnblogs.com/blingblingXY/p/13946139.html
Copyright © 2020-2023  润新知