Spring Boot + Vue3前后端分离实战wiki知识库系统十三--单点登录开发二

news2024/12/24 8:12:32

接着https://www.cnblogs.com/webor2006/p/17608839.html继续往下。

登录功能开发: 

接下来则来开发用户的登录功能,先准备后端的接口。

后端增加登录接口:

1、UserLoginReq:

先来准备用户登录的请求实体:

package com.cexo.wiki.req;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;

public class UserLoginReq {

    @NotEmpty(message = "【用户名】不能为空")
    private String loginName;

    @NotEmpty(message = "【密码】不能为空")
    // @Length(min = 6, max = 20, message = "【密码】6~20位")
    @Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,32}$", message = "【密码】规则不正确")
    private String password;

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", loginName=").append(loginName);
        sb.append(", password=").append(password);
        sb.append("]");
        return sb.toString();
    }
}

对于用户登录,只需要用户名和密码既可,其中有一个小细节需要说明一下,就是对于之前后台实现的用户管理保存的实体其密码是做了非常详细的规则提示的:

而这里对于用户登录的密码规则校验,则不能提示这么详情了,因为提示这么详情容易被人根据规则来进行密码破解,所以这里就提示了一个比较模糊的校验提示:

2、UserLoginResp:

再来准备登录的response实体:

package com.cexo.wiki.resp;

public class UserLoginResp {
    private Long id;

    private String loginName;

    private String name;

    private String token;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    @Override
    public String toString() {
        return "UserLoginResp{" +
                "id=" + id +
                ", loginName='" + loginName + '\'' +
                ", name='" + name + '\'' +
                ", token='" + token + '\'' +
                '}';
    }
}

3、Controller增加登录接口:

4、Service实现登录逻辑:

那接下来咱们是直接来校验用户名和密码的正确性么?其实应该先校验用户名是否存在,如果不存在,则密码都没密要校验了,所以先来查一下:

而处理异常可以采用在之前用户管理保存时的方式,抛出异常:

这里咱们先定义一个用户名不存在的异常码:

这里提示语貌似写错了吧。。其实这里是故意写一个模糊的提示的,因为给用户提示得越详细,越容易被攻击,所以这种风险意识在做项目时是很重要的。好,接下来就可以抛出这个异常了:

接下来再来判断密码的正确性:

最后,还有一个细节,就是目前这两块给用户提示了一个一模一样的提示:

很明显这对于后端排错不太好,所以有必要针对这俩加点日志:

前端增加登录模态框:

效果:

先来看一下登录的效果:

实现:

1、增加登录入口:

接下来则先在前端页面中增加一个用户登录的入口,这里很明显是应该在头部区域加,也就是:

此时的效果:

另外这里既然改了头部区域,左上角这块的logo也顺带改一下,目前这里是一个色块,没有什么实际意义,这里改一下:

控制它的css在这:

这里将这个logo的css先去掉,在头部组件里来定义就成:

然后修改为:

此时效果:

2、 点击弹出模态登录窗口:

先来给登录这个a标签增加点击事件:

而模态框的处理在之前的页面中已经多次用到了,所以这里就不过多解释了,直接准备一个登录的模态框:

其中提交的时候得请求接口,需要耗时,交互上肯定需要有loading等待效果,所以先提前把响应式的变量定义好:

此时运行看一下:

3、登录点击事件添加:

接下来给模拟框增加一个提交事件:

这里为了使用方便,给表单输一个默认值,如下:

此时运行:

4、发起登录请求:

最后发起登录请求,这块的网络请求代码也没啥好说的,直接copy原来的逻辑改下接口就可以了,如下:

其中需要导两个组件:

好,此时运行看一下效果:

成功登录。

登录成功处理并集成vuex:

 目前我们已经登录成功,但是登录成功之后,其实就给了一个提示,没有做登录成功之后的逻辑处理,接下来咱们则来完善它。

后端保存用户信息:

1、集成Redis:

由于需要将用户登录成功的信息以token形式存到Redis当中,所以先在工程中集成它:

而关于Redis的环境的配置这里就不说明了,当时在https://www.cnblogs.com/webor2006/p/14999543.html这篇已经详细学习过了,这块网上资料也比较多,我本机装好之后,先使用此命令启动一下它:

redis-server

然后再用可视化的图形工具RDM连接看一下:

目前里面没有存任何信息,所以数量都是0,然后再配置一下redis的数据源,类似于mysql一样:

2、登录时生成token并存入Redis中:

此时我们就需要修改一下登录的逻辑时,在登录成功之后,需要生成一个token,这里就用之前使用的雪花算法来生成,如下:

此时则需要将token存入到Redis当中,此时需要这么来做:

其中有个细节需要注意,我们目前存放到Redis中是将实体转换成了一个json串了:

如果想直接保存实体,注意需要让实体实现序列化的接口,不然保存的时候会报如下异常:

另外此token信息也需要返回给前端,因为之后前端也需要将此token信息在请求时携带上进行身份的识别,所以:

其中为了调试方便,将这块加个日志输出:

3、测试:

接下来咱们来登录测试一下是否写入成功了:

显示是成功了,到RDM可视化工具中刷新查看一下:

貌似是有了,不过看了是一串乱码,为了验证这个token写入到Redis是没有问题的,下面在TestController中增加测试方法,如下:

然后咱们就可以这样来测试了:

咱们运行一下:

那对于这里的登录时,生成这么一个token:

此时借助这个测试能查出存在redis中的用户信息么?

木问题。

前端显示登录用户:

接下来在用户登录成功之后,则需要显示出用户的昵称,修改页面:

其中user是一个响应式的变量,定义一下:

另外由于数据库中用户test的密码是test123,所以这里改一下:

然后在登录成功之后则给它进行赋值,如下:

接下来在登录入口处增加显示与隐藏的控制:

接下来运行看一下:

集成vuex:

说明:

接下来说明一个问题,就是目前我们登录后信息是在头部组件中来保存的:

那如果我想在底部组件里也能拿到用户的登录信息该怎么办呢?

很明显是拿不到的,因为定义的头部的响应式变量不能在其它页面使用,此时就得声明一个全局的变量来进行存储,这里就需要使用到vuex了,度娘先了了解一下它:

哦,就是来解决多组件数据通信的问题的,刚好符合我们目前的使用场景,而使用它的位置就在这块:

接下来咱们则来使用一下它。

实现:

1、定义一个全局的变量:

2、定义操作变量的函数:

光定义变量还不行,得定义操作它的行为,这里则会涉及到如下两处:

其中mutations是同步函数,而actions是支持异步的,这里我们在mutations中来进行定义:

3、返回store:

最后需要将这个store返回出去,以便可以在其它界面进行使用:

4、使用store保存用户信息:

接下来我们回到头部组件中,在登录成功之后使用store来保存一下用户信息,写法如下:

5、底部组件中获取用户信息:

接下来咱们就可以使用这个全局的数据了:

其中computed的含义是:如果一个响应式变量是要根据某个变量的变化而计算得来,就可以使用computed。

其中这里有个代码可以简化一下,就是它:

6、运行:

所以vuex其实就是全局响应式的变量,单纯的组件里面的响应式变量是做不到这种效果的。

最后更改一个文案:

而它应该受登录状态的控制,所以加一个显隐逻辑:

再来运行一下:

使用sessionStorage解决刷新数据丢失的问题:

说明:

接下来再来看一个问题:

刷新之后,登录态就没有了,这也反应出vuex有问题,浏览器一刷新就没有了,而要解决这个问题就需要使用sessionStorage了,度娘又来了解一下它: 

其中标红的是一些关于它值得关注的,它会随着浏览器页面的存在而存在,如果关闭页面了则数据就不存在了,在搜它的概念时,还搜到了一个在前端经常会提及的话题https://blog.csdn.net/weixin_45541388/article/details/125367823:

关于这块自己网上了解一下既可。

实现:

1、拷一个工具类:

为了使用sessionStorage,拷一个工具类进来:

SessionStorage = {
    get: function (key) {
        var v = sessionStorage.getItem(key);
        if (v && typeof (v) !== "undefined" && v !== "undefined") {
            return JSON.parse(v);
        }
    },
    set: function (key, data) {
        sessionStorage.setItem(key, JSON.stringify(data));
    },
    remove: function (key) {
        sessionStorage.removeItem(key);
    },
    clearAll: function () {
        sessionStorage.clear();
    }
};

为啥要封装一下呢,因为默认的sessionStorage只支持存string,这里扩展保存一个object类型,其实也就是最终会将object转换成Json字符串再保存:

2、引入工具类:

3、使用sessionStorage:

接下来我们在保存user信息时,除了使用vuex保存在全局响应式的变量当中之外,还需要保存到sessionStorage,所以好的做法就是在vuex这个文件中进行处理,先来引入工具类,引入的方法还记得不,其实在之前md5工具方法时已经使用过了,回忆一下:

所以定义一下:

其中let后面的名称取的是js中定义的它:

然后在获取用户信息时加上从sessionStorage来取的逻辑:

另外在设置user信息时,则需要将其存到SessionStorage当中:

其中有个代码可以优化一下:

都是常量,可以将其提取一下,提高维护性:

接下来运行看一下:

其中可以看到footer下的用户登录信息在浏览器刷新之后是能够被保留的,而关闭浏览器当前窗口就清空了,符合SessionStorage的定义场景,只是右上角的header用户信息在浏览器刷新时没有保留住,是因为header页面的user变量没有改成computed,如footer页面报写的这样:

所以咱们将header的代码改成这样:

将其改为:

这样就会去监听store中user的变化,不过这样改之后有个报错:

这里就没必要了,直接将user保存到store中就可以了:

接下来运行看一下效果:

成功修复浏览器刷新用户信息被清空的问题。

增加退出登录功能:

1、UserController.logout():

对于退出登录的接口其实只需要传一个token参数既可,所以定义接口如下:

其实也就是根据token将redis对应的信息给删除既可。

2、前端增加退出按钮:

而通常退出操作是需要给用户一个确认提示的,所以在它外层再包装一层:

3、调用退出登录接口:

接下来咱们就可以处理退出登录的点击事件,如下:

4、运行:

接下来运行看一下效果,发现后台报错了:

这是因为登出接口是一个get请求,而我们在后台声明的是:

修改一下:

再运行:

这里貌似界面上看着有点别扭,就是退出登录一般是在用户登录信息的右侧的,现在在左侧:

更改一下顺序:

因为login-menu的样式是:

最上面的元素就在最右侧边了,最后的样子:

增加登录校验:

有了用户登录之后, 对于页面中的功能则需要进行登录的校验了,对于管理类的入口都是需要登录之后才能预览,而对于文章查看是不需要的,所以,接下来进行登录校验的处理。

后端增加拦截器,校验token有效性:

1、 新建一个拦截器LoginInterceptor:

对于拦截器在之前已经有使用过了:

同样的,对于这个登录拦截器写法也差不多,关于这块的代码就不过多解释了,比较好理解:

package com.jiawa.wiki.interceptor;

import com.alibaba.fastjson.JSON;
import com.jiawa.wiki.resp.UserLoginResp;
import com.jiawa.wiki.util.LoginUserContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 拦截器:Spring框架特有的,常用于登录校验,权限校验,请求日志打印
 */
@Component
public class LoginInterceptor implements HandlerInterceptor {

    private static final Logger LOG = LoggerFactory.getLogger(LoginInterceptor.class);

    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 打印请求信息
        LOG.info("------------- LoginInterceptor 开始 -------------");
        long startTime = System.currentTimeMillis();
        request.setAttribute("requestStartTime", startTime);

        // OPTIONS请求不做校验,
        // 前后端分离的架构, 前端会发一个OPTIONS请求先做预检, 对预检请求不做校验
        if (request.getMethod().toUpperCase().equals("OPTIONS")) {
            return true;
        }

        String path = request.getRequestURL().toString();
        LOG.info("接口登录拦截:,path:{}", path);

        //获取header的token参数
        String token = request.getHeader("token");
        LOG.info("登录校验开始,token:{}", token);
        if (token == null || token.isEmpty()) {
            LOG.info("token为空,请求被拦截");
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        }
        Object object = redisTemplate.opsForValue().get(token);
        if (object == null) {
            LOG.warn("token无效,请求被拦截");
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        } else {
            LOG.info("已登录:{}", object);return true;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        long startTime = (Long) request.getAttribute("requestStartTime");
        LOG.info("------------- LoginInterceptor 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//        LOG.info("LogInterceptor 结束");
    }
}

逻辑简单来说的话就是先来判断token是否为空,如果不为空,则再到redis中来获取一下。其中校验不通过时,返回一个401:

2、配置拦截器:

接下来要想拦截器生效,则需要到这来配置一下:

然后接下来得进行一下配置,因为有些接口是需要进行登录拦截的,如下:

package com.cexo.wiki.config;

import com.cexo.wiki.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;

@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {

    //    @Resource
//    LogInterceptor logInterceptor;//配置拦截器
    @Resource
    LoginInterceptor loginInterceptor;

    public void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(logInterceptor)
//                .addPathPatterns("/**");
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns(
                        "/test/**",
                        "/redis/**",
                        "/user/login",
                        "/category/all",
                        "/ebook/list",
                        "/doc/all/**",
                        "/doc/vote/**",
                        "/doc/find-content/**",
                        "/ebook-snapshot/**"
                );
    }
}

其中这里用到了“**”:

则表示是任意值,好,加了拦截器之后咱们再来访问一下页面:

首页查看电子书都正常,但是点击用户管理时,页面的数据加载不出来了,查看一下后台日志,其实就是这个登录拦截器给拦了:

前端请求增加token参数:

目前后端加了token校验之后,在前端则需要在请求头中增加token信息了,很显然也需要在统一接口拦截器中来进行处理,那vue中是如何处理的呢?其实使用的网络组件axios就有相应的处理办法,这块其实在之前https://www.cnblogs.com/webor2006/p/17182186.html已经使用过了:

所以在这里加上token信息的逻辑:

此时再运行你会发现用户管理模块在登录之后内容还是出不来,这里就有一个坑需要说明一下,就是这块:

但是在用户登录时往Redis写入时:

这样类型就不匹配了,所以需要这样改一下:

此时再运行看一下效果:

可以看到在登录之后再查询用户管理的列表就出来了,可见现在的token的校验已经是好使了。

前端页面增加登录校验:

未登录时,管理菜单要隐藏:

现在对于管理界面在用户没有登录时也能被看到,很显然是不合理的,所以接下来处理一下它:

根据之前的经验,对于元素的显隐可以用它:

挺简单,但是你运行发现不好使,反而是把这个v-show加到<router-link>中可以:

但是还是有瑕疵,就是隐藏时这个会占用宽度:

此时就需要自己来写css样式了,如下处理:

解释一下:

而如果没登录,则需要将元素给隐藏,注意这里的style里面是需要定义一个json的,好,再运行看一下:

对路由做判断,防止用户通过手敲url访问管理页面:

现在还有个问题,就是虽说已经在登录菜单上已经根据登录状态进行显隐控制了,但是用户还是可以直接通过管理的路由地址来访问到,比如:

所以接下来处理它。

1、路由中增加meta信息:

为了要处理需要登录的路由地址,这里需要在路由配置中增加一个meta信息,如下:

2、路由登录拦截:

接下来咱们则需要进行路由跳转的一个拦截处理,这块的写法也比较固定,写一次就明白了:

然后接下来就是要判断路由地址中有木有这个mate信息,如下:

而条件体里面的写法如下:

3、运行:

下面来运行看一下效果:

成功进行路由的登录拦截了。

总结:

好了,花了很长的篇幅就将用户登录相关的给学习完了,还是收获很多的,比如密码的双层加层,登录的拦截等等,下次继续。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1020948.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

07JVM_内存模型和CAS与原子类

一、内存模型 1.java内存模型 Java内存结构是JMM&#xff08;Java Memory Model&#xff09;的意思。JMM定义了一套在多线程读写共享数据&#xff08;成员变量&#xff0c;数组&#xff09;时&#xff0c;对数据的原子性&#xff0c;见性&#xff0c;有序性的规则和保障。 1…

浅谈电力电容器技术的发展及选型

安科瑞 华楠 摘要&#xff1a;介绍了我国电力电容器产品制造技术的发展现状。在与国外电力电容器产品先进水平对比的基础上,讨论了我国电力电容器产品的差距和某些对策,并对我国电力电容器技术发展趋势提出了一些看法。 关键词&#xff1a;电力电容器;制造技术;技术发展 0 引…

每日一题~最大二叉树

题目链接&#xff1a;654. 最大二叉树 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数…

Logstash介绍

Logstash介绍 Logstash是一个开源数据收集引擎&#xff0c;具有实时管道功能。Logstash可以动态地将来自不同数据源的数据统一起来&#xff0c;并将数据标准化到你所选择的目的地。 集中、转换和存储你的数据 Logstash是一个开源的服务器端数据处理管道&#xff0c;可以同时从多…

采集分析仪设计原理图:437-带触摸显示的10路5Msps@18bit采集分析仪

带触摸显示的10路5Msps18bit采集分析仪 一、产品概述 本产品提供了多种传感器接入接口&#xff0c;支持多种类型传感器实时采集、处理、显示等功能。主处理器采用XC7Z100-FFG900芯片&#xff0c;具有444K逻辑单元和双核ARM Cortex-A9 MPCore处理器。PL部分得可编程逻辑可…

docker系列-报错以及解决指南

1. windows运行docker报错Windows Hypervisor is not presentDocker Desktop is unable to detect a Hypervisor.Hardware assisted virtualization and data execution protection must be enabled in the BIOS. Docker Desktop - Windows Hypervisor is not presentDocker D…

async和await的用法

定义 async的定义 在mdn中,async的定义为: async function 关键字可用于定义表达式中的异步函数。 其实很简单,就是async关键字后面定义的函数会被转化为一个异步的函数 如下所示: function fn1(){return 同步}async function asyncFn(){return 异步}console.log(fn1())con…

Dubbo3应用开发——架构的演变过程

Dubbo3应用开发——架构的演变过程 什么是Dubbo 早期Dubbo的定位&#xff1b; 基于Java的高性能&#xff0c;轻量级的RPC框架&#xff1b;SOA【Service-Oriented Architecture ⾯向服务的架构】 RPC服务治理&#xff1b; 2018年阿⾥巴巴把这个框架捐献给了 Apache 基⾦会&am…

深入理解Java单例模式和优化多线程任务处理

目录 饿汉模式懒汉模式单线程版多线程版双重检查锁定 阻塞队列 单例模式能保证某个类在程序中只存在唯一一份实例, 而不会创建出多个实例&#xff0c;并提供一个全局访问点。 饿汉模式 类加载的同时&#xff0c;创建实例。 class Singleton {private static final Singlet…

2023:生成式AI与存储最新发展和趋势分析(上)

生成式AI的热潮在短时间内席卷全球&#xff0c;以一种势不可挡的趋势迅速出圈&#xff0c;在某一时间段&#xff0c;似乎出现了“除了IT行业&#xff0c;人人都是AI专家”的盛况。这一轮如火如荼的全民AI热潮迸发至今&#xff0c;业已过半载&#xff0c;待最初的烟花绚烂散去&a…

【基础篇】六、基于SpringBoot来整合SSM的案例(下)

文章目录 1、前后端调用&#xff1a;axios发送异步请求2、添加功能3、删除功能4、修改功能5、异常消息处理6、分页功能7、分页Bug处理8、条件查询 接下来加入前端页面&#xff0c;使用axios发送异步请求调用上篇的接口。调前端代码时&#xff0c;发现还挺有趣&#xff0c;刷新、…

Learn Prompt-ChatGPT 精选案例:广告文案

ChatGPT 可以帮助我们生成广告文案和宣传图片&#xff0c;这对营销品牌建设很有帮助。通常&#xff0c;一个产品会有一个主要的广告词&#xff0c;传达设计理念或宣传产品的好处。我们可以尝试直接生成文案&#xff0c;看看 ChatGPT 有没有好的创意。假设我们的产品是一款登山鞋…

【css | linear-gradient】linear-gradient()的用法

linear-gradient() CSS函数创建一个由两种或多种颜色沿一条直线进行线性过渡的图像,其结果是<gradient>数据类型的对象,此对象是一种特殊的<image> 数据类型。 先看一个线上的示例 https://code.juejin.cn/pen/7277486410842996771 语法 /* 渐变轴为 45 度&…

Docker容器详解

值得看的原文地址

一根USB线,全新单片机开发体验!推荐WeCanStudio工具套件

我的需求 回想当初大学时代,学习单片机的开发最繁琐的事情就是,通过串口升级STC的MCU来调试编写的固件。不知到有多少个深夜都在重复以下步骤&#xff1a; Keil编译代码打开STC软件,选择对生成的新固件程序手动断电、上电MCU板子(USB转串口的驱动还经常让电脑蓝屏&#x1f6…

极智开发 | 制作u盘启动盘的几种方式

欢迎关注我的公众号 [极智视界],获取我的更多经验分享 大家好,我是极智视界,本文分享一下 制作u盘启动盘的几种方式。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码和资源下载,链接:https://t.zsxq.com/0aiNxERDq 在平时的工作、生活中,经常会涉及…

Bigemap在市政工程设计给排水行业的应用场景?

去年单位采购的&#xff0c;今年11月份才分配给我使用。 使用场景&#xff1a; 现场定位&#xff1a; 通过我们电脑导入cad图纸数据&#xff0c;根据需求可以画一些简单的示意路线&#xff0c;发送到手机进行现场比对&#xff0c;最后会在cad里面加入管道设计方案。 去年单位采…

Windows Server 2012 R2系统远程桌面的数字证书算法SHA1升级到SHA256

问题描述&#xff1a; 最近项目进行密评的时候&#xff0c;Windows Server 2012 R2发现了以下证书问题&#xff1a; Windows Server 2012 R2系统远程桌面的TLS 1.2协议使用SHA1算法数字证书&#xff0c;且证书有效日期截止23年10月&#xff0c;建议注意证书到期时间&#xff…

极简解析!IP计费的s5爬虫IP

大家好&#xff01;今天我将为大家分享关于s5爬虫IP服务的知识。对于经常做爬虫的小伙伴来说&#xff0c;需要大量的爬虫IP支持爬虫业务&#xff0c;那么对于选择什么样的爬虫IP&#xff0c;我想我有很多发言权。 下面我们一起了解下IP计费的s5爬虫IP的知识&#xff0c;废话不…

Spring Boot + Vue3前后端分离实战wiki知识库系统<十三>--单点登录开发二

接着Spring Boot Vue3前后端分离实战wiki知识库系统<十二>--用户管理&单点登录开发一继续往下。 登录功能开发&#xff1a; 接下来则来开发用户的登录功能&#xff0c;先准备后端的接口。 后端增加登录接口&#xff1a; 1、UserLoginReq&#xff1a; 先来准备…