当前位置: 首页 > news >正文

网站开发 方案 报价/seo推广培训

网站开发 方案 报价,seo推广培训,动态图片在线制作,中国有几大电商平台简介 登录模块很简单,前端发送账号密码的表单,后端接收验证后即可~ 淦!可是我想多了,于是有了以下几个问题(里面还包含网络安全问题): 1.登录时的验证码 2.自动登录的实现 3.怎么维护前后端…

简介

登录模块很简单,前端发送账号密码的表单,后端接收验证后即可~

淦!可是我想多了,于是有了以下几个问题(里面还包含网络安全问题):

1.登录时的验证码

2.自动登录的实现

3.怎么维护前后端登录状态

在这和大家分享下我实现此功能的过程,包括一些技术和心得

1.登录时的验证码

为什么要验证码,原因很简单,防止脚本无限次重复登录,来暴力破解用户密码或者攻击服务器

验证码的出现,使得每次登录都有个动态变量需要输入,无法用脚本写死代码

2.自动登录的实现

所谓自动登录,指的是当用户登录网站时勾选了自动登录,那么下次再访问网站就不需要输入账号密码直接登录了

这说明,账号密码信息是必须保存在用户这边的,因此自动登录都是不安全的!(方便的代价呀)

尽管不安全,但是我们也必须要尽力让它安全一点,有以下常用方法:

1.账号密码加密保存

2.降低自动登录后用户的权限(如果用户自动登录想改密码,想给我转钱等操作的话,就必须输入账号密码再登录一次!)

3.进行ip检测(之前登录的ip小本本记着),如果发现和上次不一致,则不允许自动登录

数据存储在前端哪里呢

浏览器有3个经常保存数据的地方

1.Cookie (我用这个)

2.LocalStorage

3.SessionStorage

各位可以按F12直接观看

如果你在多个大型网站下都按按F12,会发现SessionStorage基本没数据

为啥,因为真的不好用,它并不是后台的session那样,生命周期是一个会话,这个SessionStorage存储的数据只限于该标签的页面

意思是标签1和标签2即使是同个URL的网址,里面的数据都是不互通的(这有个毛用)

那么LocalStorage存储的数据如何呢,答案是无限期本地存储

不过后台无法操作这里的数据,只能由js代码操作(至于操作结果,完全看js,后端无法感知,不太可靠),我认为这里不适合保存敏感点的信息,因为前端的功能是展示,状态性的数据应该由后端直接掌控(后端能直接操作Cookie,保证完成任务)

你看英雄所见略同,CSDN网站的用户密码也是存在Cookie的

 Token就是登录后的令牌(下一点会讲)

所以用Cookie就对啦,具体实现都很简单,前端多个自动登录的选择,选择后多个参数传给后端,后端根据参数往Cookie里设置加密后的账号密码

等下次访问时,用拦截器Interceptor进行拦截,检测是否要自动登录即可~

3.如何维护前后端登录状态

大家最先想到是用Session来维护,登录后在Session中存放用户信息,不过对分布式很不友好(什么,你说你用不到分布式,我也没用到,可是梦想还是要有的嘛),需要维护个分布式数据库来进行数据同步才行

于是我用Token实现的,Token就是一串字符串,最适合API鉴权(例如SSO单点登录这种),俗称令牌

好处就是账号密码用户输入一次就够了,特别是多个系统之间(一张身份的凭证都通用)

当用户登录后,服务器就会生成一个Token放在Cookie中,之后用户的所有操作都带这个Token访问(将Token放入http头部)

为什么要将Token放入头部

1.能抵挡下简单的CSRF攻击

2.浏览器跨域问题

什么是CSRF攻击

举个例子:我登录了A网站,A网站给我返回了一些Cookie信息,然后我再同一浏览器的另外标签访问了B网站,谁知这个B网站返回了一些攻击代码(向A网站发起一些请求,比如转钱给你,这时候由于是访问A网站,会附带A网站的Cookie,让一切都好像是我在访问一样),这个就是CSRF攻击

但B网站并不知道A网站这么鸡贼,会在头部放了Token,所以这次攻击请求是的头部是没Token的,因此检测后发现非法,所以没得逞

当然,这并不可靠,哪天B网站知道你头部放了Token,它研究A网站的js代码,清楚逻辑之后也加上,那就防不住了(所以说前端的东西一切都不可靠)

正确做法应该是后端检测头部的Referer字段,每个网页里发起请求,请求的头部都会带有此字段,如

这说明这个请求是从 http://localhost:8099/swr 中发出的

B网站如果返回攻击代码,这里显示的事B网站的网址,判断出不是自家网站发出,就可以禁止访问

浏览器跨域访问会发生什么

说到跨域(自家网站去请求别人家的网站),得先了解什么是同源策略:

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说 Web 是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

它的核心就在于它认为自任何站点装载的信赖内容是不安全的。当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被允许访问来自同一站点的资源,而不是那些来自其它站点可能怀有恶意的资源。

所谓同源是指:域名、协议、端口相同。

另外,同源策略又分为以下两种:

  1. DOM 同源策略:禁止对不同源页面 DOM 进行操作。这里主要场景是 iframe 跨域的情况,不同域名的 iframe 是限制互相访问的。
  2. XMLHttpRequest 同源策略:禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求。(就是ajax)

咳咳,这里要说下第二种,其实设置一些参数之后,ajax访问时允许跨域请求的,甚至允许跨域时带上自身cookie

但是,带上自己的Cookie多不安全,明明里面只有1,2个信息要传给对方,现在被人全看见了(不好不好),所以要将Token放入头部

你说为啥不放到参数里,因为这会跟业务用的参数混淆,造成逻辑混乱(就好像你上学时要扔家里的垃圾,你不会放到书包里吧,都是手里提着的)

每个请求都放token,所以要封装起来,例如我是将ajax封装起一个新的对象,然后在这个对象使用时添加Token

当然啦,封装了ajax后还有其他好处(例如统一的成功,失败回调函数,统一的数据解析,统一的等待框等等),有兴趣的同学可以看下

 View Code

预防XSS攻击,Filter知识讲解

网上有些文章说,后端设置HttpOnly,让Cookie无法让js读写,可以防止XSS攻击。

(⊙o⊙)…简直就是乱写,首先要了解下什么是XSS攻击

Xss攻击是什么

举个简单的例子,假设你前端有个地方可以输入,然后保存的数据库的地方

用户A输入了以下东西

<script>alert(123)</script>

然后这东西就到了后台,当作一串字符串保存了起来

刚好你网站的html代码里,有个地方是显示用户输入过的东西的(例如评论区),然后上面的东西就被加载到html里面,如

<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title></title><p><script>alert(123)</script></p></head><body></body>
</html>

接下来每个人打开你的网站,都会弹出123的对话框,这就是XSS攻击

怎么预防呢,在后端设置过滤器,对输入进行过滤,先上代码

 1 /**2  * @auther: NiceBin3  * @description: 系统的拦截器,注册在FilterConfig类中进行4  *               不能使用@WebFilter,因为Filter要排序5  *               1.对ServletRequest进行封装6  *               2.防止CSRF,检查http头的Referer字段7  * @date: 2020/12/15 15:328  */9 @Component
10 public class SystemFilter implements Filter {
11     private final Logger logger = LoggerFactory.getLogger(SystemFilter.class);
12     @Autowired
13     private Environment environment;
14 
15     @Override
16     public void init(FilterConfig filterConfig) throws ServletException {
17         logger.info("系统拦截器SystemFilter开始加载");
18     }
19 
20     @Override
21     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
22         SystemHttpServletRequestWrapper requestWrapper = new SystemHttpServletRequestWrapper((HttpServletRequest) request);
23 
24         //检测http的Referer字段,不允许跨域访问
25         String hostPath = environment.getProperty("server.host-path");
26         String referer = requestWrapper.getHeader("Referer");
27         if(!Tool.isNull(referer)){
28             if(referer.lastIndexOf(hostPath)!=0){
29                 ((HttpServletResponse)response).setStatus(HttpStatus.FORBIDDEN.value()); //设置错误状态码
30                 return;
31             }
32         }
33         chain.doFilter(requestWrapper,response);
34     }
35 
36     @Override
37     public void destroy() {
38 
39     }
40 }

乍一看,是不是没发现哪里预防了XSS,其实正在的关键点在22行和33行代码,里面的SystemHttpServletRequestWrapper类才是关键,这个类是包装类,是替换参数里的ServletRequest类的,为的就是重写里面的方法,来达到预防XSS的目的,因为Spring也是根据ServletRequest类来进行前端参数读取的,所以它就是后端获得数据的源头

1 /**2  * @auther: NiceBin3  * @description: 包装的httpServlet,进行以下增强4  *               1.将流数据取出保存,方便多次读出5  *               2.防止XSS攻击,修改读取数据的方法,过滤敏感字符6  * @date: 2020/4/23 19:507  */8 public class SystemHttpServletRequestWrapper extends HttpServletRequestWrapper {9     private final byte[] body;
10     private HttpServletRequest request;
11 
12     public SystemHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
13         super(request);
14         //打印属性
15         //printRequestAll(request);
16         body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));  //HttpHelper是我自己写的工具类
17         this.request = request;
18     }
19 
20     @Override
21     public BufferedReader getReader() throws IOException {
22         return new BufferedReader(new InputStreamReader(getInputStream()));
23     }
24 
25     @Override
26     public ServletInputStream getInputStream() throws IOException {
27         final ByteArrayInputStream bais = new ByteArrayInputStream(body);
28         return new ServletInputStream() {
29             @Override
30             public boolean isFinished() {
31                 return false;
32             }
33 
34             @Override
35             public boolean isReady() {
36                 return false;
37             }
38 
39             @Override
40             public void setReadListener(ReadListener readListener) {
41 
42             }
43 
44             @Override
45             public int read() throws IOException {
46                 return bais.read();
47             }
48         };
49     }
50 
51     /**
52      * 可以打印出HttpServletRequest里属性的值
53      * @param request
54      */
55     public void printRequestAll(HttpServletRequest request){
56         Enumeration e = request.getHeaderNames();
57         while (e.hasMoreElements()) {
58             String name = (String) e.nextElement();
59             String value = request.getHeader(name);
60             System.out.println(name + " = " + value);
61         }
62     }
63 
64     //以下为XSS预防
65     @Override
66     public String getParameter(String name) {
67         String value = request.getParameter(name);
68         if (!StringUtils.isEmpty(value)) {
69             value = StringEscapeUtils.escapeHtml4(value);
70         }
71         return value;
72     }
73 
74     @Override
75     public String[] getParameterValues(String name) {
76         String[] parameterValues = super.getParameterValues(name);
77         if (parameterValues == null) {
78             return null;
79         }
80         for (int i = 0; i < parameterValues.length; i++) {
81             String value = parameterValues[i];
82             parameterValues[i] = StringEscapeUtils.escapeHtml4(value);
83         }
84         return parameterValues;
85     }
86 }

HttpHelper工具类:

 View Code

可以看到SystemHttpServletRequestWrapper的64行开始,重写了两个获取参数的方法,在获取参数的时候进行过滤即可~

那64行往上是干啥的咧,这个是将ServletRequest里的数据读出来保存一份,因为ServletRequest里的数据流只能读取一次,很不方便

啥意思呢,就是你在这个Filter里

inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = reader.readLine()) != null) {sb.append(line);
}

把数据读完,下个Filter再执行这些代码,就没数据了(从而导致Spring也接收不到数据)

所以要保存起来,让后面的过滤器Filter和拦截器Interceptor快乐的读数据,没有后顾之忧(例如上面提到的验证码设计,如果你想用拦截器拦截,然后进行验证,则势必会读数据),既然封装ServletRequest这么重要,那必须得保证这个Filter第一个加载啊

在Springboot中,Filter的排序用@Order是没用的,必须要用FilterRegistrationBean进行注册才能排序,如:

 1 /**2  * @auther: NiceBin3  * @description: 为了排序Filter,如果Filter有顺序要求4  *               那么需要在此注册,设置order(值越低优先级越高)5  *               其他没顺序需要的,可以@WebFilter注册6  *               如@WebFilter(filterName = "SecurityFilter", urlPatterns = "/*", asyncSupported = true)7  * @date: 2020/12/15 15:488  */9 @Configuration
10 public class FilterConfig {
11 
12     @Autowired
13     SystemFilter systemFilter;
14     /**
15      * 注册SystemFilter,顺序为1,任何其他filter不能比他优先
16      * @return
17      */
18     @Bean
19     public FilterRegistrationBean filterRegist(){
20         FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
21         filterRegistrationBean.setFilter(systemFilter);
22         filterRegistrationBean.setName("SystemFilter");
23         filterRegistrationBean.addUrlPatterns("/*");
24         filterRegistrationBean.setAsyncSupported(true);
25         filterRegistrationBean.setOrder(1);
26         return filterRegistrationBean;
27     }
28 }

当然了,如果你没用Springboot,那web.xml中定义的顺序就是Filter加载的顺序

知识点提问:在我们之后的Filter或者Interceptor中,需要
1 SystemHttpServletRequestWrapper requestWrapper = (SystemHttpServletRequestWrapper) request

这样强制转换才能用吗?

答案是不用的,你可以想想Spring也用了这个东西的,它怎么知道你定义的类叫什么名字,怎么强制转换,那么这设计到Java什么知识呢

没错,就是Java的多态性,我们看以下代码

public class Father {public void sayName(){System.out.println("我是爸爸");}
}public class Son extends Father{public void sayName(){System.out.println("我是儿子");}
}public class Test {@org.junit.Testpublic void test() throws Exception {Father father = new Son();otherMethod(father);}public void otherMethod(Father father){father.sayName();}
}

输出:我是儿子

答错了的留言,看看有多少小伙子~~ 接下来言归正传

选择JWT生成Token

JWT全称JSON Web Tokens 是一种规范化的 token(别人想的挺多挺全面的了,比你自己想的token要好一点)

一个 JWT token 是一个字符串,它由三部分组成,头部、载荷与签名,中间用 . 分隔,例如:xxxxx.yyyyy.zzzzz

头部(header)

头部通常由两部分组成:令牌的类型(即 JWT)和正在使用的签名算法(如 HMAC SHA256 或 RSA.)。

例如:

{"alg": "HS256","typ": "JWT"
}

然后用 Base64Url 编码得到头部,即 xxxxx。Base64Url编码后,才能在URL中正常传输(因为有人会把Token放在URL里.....)

载荷(Payload)

载荷中放置了 token 的一些基本信息,以帮助接受它的服务器来理解这个 token。同时还可以包含一些自定义的信息,用户信息交换,如:

{"sub": "1","iss": "http://localhost:8000/auth/login","iat": 1451888119,"exp": 1454516119,"nbf": 1451888119,"jti": "37c107e4609ddbcc9c096ea5ee76c667","aud": "dev"}

可以将载荷用别的方式加密一遍,这样别人得到了token也看不懂

签名(Signature)

签名时需要用到前面编码过的两个字符串,如果以 HMACSHA256 加密,就如下:

HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)

加密后再进行 base64url 编码最后得到的字符串就是 token 的第三部分 zzzzz。

组合便可以得到 token:xxxxx.yyyyy.zzzzz。

签名的作用:保证 JWT 没有被篡改过,原理如下:

HMAC 算法是不可逆算法,类似 MD5 和 hash ,但多一个密钥,密钥(即上面的 secret)由服务端持有,客户端把 token 发给服务端后,服务端可以把其中的头部和载荷再加上事先共享的 secret 再进行一次 HMAC 加密,得到的结果和 token 的第三段进行对比,如果一样则表明数据没有被篡改。

具体Java使用:

<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.10.2</version></dependency><!--jwt一些工具类--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

1 **2  * @auther: NiceBin3  * @description: Jwt构造器,创建Token来进行身份记录4  * jwt由3个部分构成:jwt头,有效载荷(主体,payLoad),签名5  * @date: 2020/5/7 22:406  */7 public class JwtTool {8 9     //以下为JwtTool生成时的主题10     //登录是否还有效11     public static final String SUBJECT_ONLINE_STATE = "online_state";12 13     //以下为载荷固定的Key值14     //主题15     public static final String SUBJECT = "subject";16     //发布时间17     public static final String TIME_ISSUED = "timeIssued";18     //过期时间19     public static final String EXPIRATION = "expiration";20 21     /**22      * 生成token,参数都是载荷(自定义内容)23      * 其中Map里为非必要数据,而其他参数为必要参数24      *25      * @param subject  主题,token生成干啥用的,用上面的常量作为参数26      * @param liveTime 存活时间(秒单位),建议使用TimeUnit方便转换27      *                 如TimeUnit.HOURS.toSeconds(1);将1小时转为秒 = 360028      * @param claimMap 自定义荷载,可以为空29      * @return30      */31     public static String createToken(String subject, long liveTime, HashMap<String, String> claimMap) throws Exception {32 33         SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;34 35         //毫秒要转为秒36         long now = System.currentTimeMillis() / 1000;37 38 //        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(EncrypRSA.keyString);39 //40 //        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());41 42         JwtBuilder jwtBuilder = Jwts.builder()43                 //加密算法44                 .setHeaderParam("alg", "HS256")45                 //jwt签名46                 .signWith(signatureAlgorithm, EncrypRSA.convertSecretKey);  //这个Key是我自个的密码,你们自己设个字符串也成,这个得保密47 48         HashMap<String,String> payLoadMap = new HashMap<>();49         payLoadMap.put(SUBJECT,subject);50         payLoadMap.put(TIME_ISSUED,String.valueOf(now));51         //设置Token的过期时间52         if (liveTime >= 0) {53             long expiration = now + liveTime;54             payLoadMap.put(EXPIRATION,String.valueOf(expiration));55         } else {56             throw new SystemException(SystemStaticValue.TOOL_PARAMETER_EXCEPTION_CODE, "liveTime参数异常");57         }58 59         StringBuilder payLoad = new StringBuilder();60 61 62 63         if (!Collections.isEmpty(claimMap)) {64             payLoadMap.putAll(claimMap);65         }66 67         //拼接主题payLoad,采用 key1,value1,key2,value2的格式68         for (Map.Entry<String, String> entry : payLoadMap.entrySet()) {69             payLoad.append(entry.getKey()).append(',').append(entry.getValue()).append(',');70         }71 72         //对payLoad进行加密,这样别人Base64URL解密后也不是明文73         String encrypPayLoad = EncrypRSA.encrypt(payLoad.toString());74 75         jwtBuilder.setPayload(encrypPayLoad);76 77         //会自己生成签名,组装78         return jwtBuilder.compact();79     }80 81     /**82      * 私钥解密token信息83      *84      * @param token85      * @return 存有之前定义的Key, value的Map,解析失败则返回null86      */87     public static HashMap getMap(String token) {88         if (!Tool.isNull(token)) {89             try {90                 String encrypPayLoad = Jwts.parser()91                         .setSigningKey(EncrypRSA.convertSecretKey)92                         .parsePlaintextJws(token).getBody();93 94                 String payLoad = EncrypRSA.decrypt(encrypPayLoad);95 96                 String[] payLoads = payLoad.split(",");97                 HashMap<String, String> map = new HashMap<>();98                 for (int i = 0; i < payLoads.length - 1; i=i+2) {99                     map.put(payLoads[i], payLoads[i + 1]);
100                 }
101                 return map;
102             } catch (Exception e) {
103                 System.out.println("Token解析失败");
104                 return null;
105             }
106         } else {
107             return null;
108         }
109     }
110 
111     /**
112      * 判断token是否有效
113      *
114      * @param map 已经解析过token的map
115      * @return true 为有效
116      */
117     public static boolean isAlive(HashMap<String, String> map) {
118 
119         if (!Collections.isEmpty(map)) {
120             String tokenString = map.get(EXPIRATION);
121 
122             if (!Tool.isNull(tokenString)) {
123                 long expiration = Long.valueOf(tokenString) / 1000;
124                 long now = System.currentTimeMillis();
125                 if (expiration > now) {
126                     return true;
127                 } else {
128                     return false;
129                 }
130             }
131         }
132         return false;
133     }
134 
135     /**
136      * 判断token是否有效
137      * @param token 还未被解析的token
138      * @return
139      */
140     public static boolean isAlive(String token) {
141         return JwtTool.isAlive(JwtTool.getMap(token));
142     }
143 }

至此,Token的生成和使用就介绍完了,大家有没兴趣了解下重放攻击(淦,我也是在某个博文看到的,又得花时间研究)

Https防止半路被截和重放攻击

前面提到了Token就是身份令牌,可以相当于已登录一样进入系统,那么半路被人截了那就不好了

所以要用Https协议,具体怎么设置大家自行百度吧(直接在tomcat操作的,不需要更改代码,证书也有免费的~)

这里说下Https建立连接的过程,来看看为什么就不会被人截获了

1.服务器先向CA(证书颁布机构)申请一个证书(证书里有自己的ip等等消息),然后在自己服务器设置好

2.浏览器向服务器发送HTTPS请求,服务器将自己的证书发给浏览器

3.浏览器拿到证书后,查看证书是否过期啊,ip是不是跟服务器的一样啊,跟检查身份证跟你长得像不像一样,检查没问题后,跟自己系统里的CA列表比对,看看是谁发的(找不到就报错,说证书不可信),比对成功后从列表里拿出对应的CA公钥解密证书(具体方法跟JWT的很像,浏览器用相同的算法和公钥对证书部分进行加密,看得到的值和证书的签名是否一致),得到服务器的公钥

4.然后生成一个传输私钥,用服务器的公钥加密,发给服务器

5.服务器用服务器的私钥解密,得到了传输秘钥,然后用传输秘钥进行加密要传送的信息发给浏览器

6.浏览器用秘钥解密,然后用传输秘钥进行加密要传送的信息发给服务器(对称加密)

7.重复5,6步骤直到结束

以上哪个步骤黑客得到数据都看不懂

至于为什么能防重放攻击,是因为Https通信自带序列号,如果黑客截取了浏览器的请求,重复发送一遍,那么序列号会一样,会被直接丢弃

相关文章:

Springboot之登录模块探索(含Token,验证码,网络安全等知识)

简介 登录模块很简单&#xff0c;前端发送账号密码的表单&#xff0c;后端接收验证后即可~ 淦&#xff01;可是我想多了&#xff0c;于是有了以下几个问题&#xff08;里面还包含网络安全问题&#xff09;&#xff1a; 1.登录时的验证码 2.自动登录的实现 3.怎么维护前后端…...

golang调用模组程序实现交互输入自动化,获取imei及iccid

应用场景&#xff1a;在openwrt下调用移远的测试程序&#xff0c;并实现输入自动话&#xff0c;获取imei rootOpenWrt:~# ql-api-test Test groups:0: ql_dsi1: ql_nw2: ql_sim3: ql_dev4: ql_voice5: ql_sms6: ql_adc7: ql_i2c8: …...

ACE之单例

单例簇 使用双重锁检查优化 #mermaid-svg-RMOXQ0KMo0VnJe7V {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-RMOXQ0KMo0VnJe7V .error-icon{fill:#552222;}#mermaid-svg-RMOXQ0KMo0VnJe7V .error-text{fill:#552222…...

泷羽sec学习打卡-云技术基础1-docker

声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 关于云技术基础的那些事儿-Base1 一、云技术基础什么是云架构&#xff1f;什么是云服务&#xff1f;什么…...

7天掌握SQL - 第一天:数据库基础与SQL入门

目标 在本章节中&#xff0c;我们将学习数据库的基本概念和SQL语言的基础操作&#xff0c;为后续的深入学习打下坚实的基础。 一级目录 数据库基本概念SQL语言基础SQL操作实践推荐资源总结 1. 数据库基本概念 1.1 表&#xff08;Table&#xff09; 表是数据库中存储数据的…...

A037-基于Spring Boot的二手物品交易的设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…...

【异常记录】Junitmock之InvalidUseOfMatchersException异常

mock之InvalidUseOfMatchersException异常 新手小白对mock一知半解&#xff0c;就开始自测了&#xff0c;被这个InvalidUseOfMatchersException困扰了一晚上。排查了好久&#xff0c;大多数文章都把英文翻译了一遍&#xff0c;但自检无问题。最后发现是&#xff0c;注入的时候…...

Spring Boot3自定义starter

1、加入必要依赖 plugins {id javaid org.springframework.boot version 3.2.6id io.spring.dependency-management version 1.1.5 } group org.example.test.starter version 1.1.0jar{enabledtrue// resolveMainClassName }java {toolchain {languageVersion JavaLanguage…...

掌控 Solidity:事件日志、继承和接口的深度解析

Solidity 是以太坊智能合约的主要编程语言&#xff0c;它的强大之处在于能够帮助开发者构建安全、高效的去中心化应用。在我参与的多个项目中&#xff0c;事件日志、继承和接口这三个概念始终贯穿其中&#xff0c;成为构建复杂智能合约的关键技术。今天就来聊聊Solidity中的错误…...

新手教学系列——善用 VSCode 工作区,让开发更高效

引言 作为一名开发者,你是否曾经在项目中频繁地切换不同文件夹,打开无数个 VSCode 窗口?特别是当你同时参与多个项目或者处理多个模块时,这种情况更是家常便饭。很快,你的任务栏上挤满了 VSCode 的小图标,切换起来手忙脚乱,工作效率直线下降。这时候,你可能会问:“有…...

Vue3 虚拟列表组件库 virtual-list-vue3 的使用

Vue3 虚拟列表组件库 virtual-list-vue3 的基本使用 分享个人写的一个基于 Vue3 的虚拟列表组件库&#xff0c;欢迎各位来进行使用与给予一些更好的建议&#x1f60a; 概述&#xff1a;该组件组件库用于提供虚拟化列表能力的组件&#xff0c;用于解决展示大量数据渲染时首屏渲…...

WebRTC实现双端音视频聊天(Vue3 + SpringBoot)

目录 概述 相关概念 双端连接整体实现步骤概述 文章代码实现注意点 STUN和TURN服务器的搭建 开发过程描述 后端开发流程 前端开发流程 效果演示 Gitee源码地址 概述 文章描述使用WebRTC技术实现一对一音视频通话。 由于设备摄像头限制&#xff08;一台电脑作测试无法…...

第6章详细设计-6.9 PCB审查

6.9 PCB审查 6.9.1 布局阶段注意事项1.结构设计要求在PCB布局之前弄清楚产品的结构2.布局要求 6.9.2 布线注意事项6.9.3 接地处理&#xff08;1&#xff09;射频链路接地。&#xff08;2&#xff09;腔壳接地孔。&#xff08;3&#xff09;螺钉放置&#xff08;需要了解结构知识…...

docker与大模型(口语化原理和实操讲解)

文章目录 一、镜像images1&#xff09;下载安装2&#xff09;docker images相关命令(保存、删除、上传、别名、搜索镜像) 二、容器container1&#xff09;展现所有在跑的容器服务ps2&#xff09;start /restart / kill / stop /rm3&#xff09;exec /cp4&#xff09;run/create…...

Linux之vim模式下全选命令

在Linux系统中&#xff0c;使用Vim编辑器进行全选操作可以通过以下几种方式实现&#xff1a; 1.使用键盘快捷键 按下 ”ggVG”&#xff08;先按下”g”&#xff0c;再按下”g”&#xff0c;再按下”V”&#xff0c;最后按下”G”&#xff09;可以全选当前文件内容。其中 ”g…...

云原生周刊:Kubernetes v1.32 要来了

开源项目推荐 Woodpecker Woodpecker 是一款轻量级且功能强大的 CI/CD 引擎&#xff0c;以其高度可扩展性和易用性著称。它支持多种版本控制系统与编程语言&#xff0c;能够灵活适配不同开发流程&#xff0c;帮助团队实现高效的持续集成与交付。无论是个人项目还是大型团队&a…...

# JVM学习

JVM JVM是什么&#xff1f; Java虚拟机&#xff08;JVM&#xff09; 是一个抽象的计算机&#xff0c;它是一个运行时环境&#xff0c;用于执行Java字节码或编译后的Java程序。JVM屏蔽了底层操作系统的差异&#xff0c;使得Java程序可以在任何支持JVM的操作系统上运行。 JVM能…...

【代码随想录day33】【C++复健】62.不同路径;63. 不同路径 II;343. 整数拆分;96.不同的二叉搜索树

感觉dp的题真的很适合背&#xff0c;当然不是死记硬背&#xff0c;而是当做一种模板题&#xff0c;出来一道新的题就往模板题上面去靠&#xff0c;如果套对模板的话剩下的事情其实就简单了。所以只要看一遍解法知道大致思路其实就够了&#xff0c;毕竟大部分dp的代码也不算难写…...

《勇者斗恶龙3:HD-2D重制版》找幽灵船攻略分享

《勇者斗恶龙3&#xff1a;HD-2D重制版》中的幽灵船是游戏里非常独特的一个区域&#xff0c;而想要找到幽灵船的话还是比较麻烦的&#xff0c;首先是听到关于幽灵船在世界海域上航行的传闻&#xff0c;包括在海盗巢穴中&#xff0c;但幽灵船的出现有一些具体条件。 勇者斗恶龙3…...

基于 MATLAB 的模拟退火算法详解及实现

以下是一篇更详细的关于 模拟退火算法 (Simulated Annealing) 的 MATLAB 实现的教程和代码示例&#xff0c;涵盖基本概念、核心思想和代码实现。 一、模拟退火算法简介 模拟退火算法&#xff08;Simulated Annealing&#xff0c;简称 SA&#xff09;是一种随机优化算法&#x…...

MQTT 服务器常用的有哪些?

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的消息传输协议&#xff0c;常用于物联网&#xff08;IoT&#xff09;设备之间的通信。以下是一些常用的 MQTT 服务器&#xff08;也称为 MQTT Broker&#xff09;&#xff1a; 1.Eclipse Mosqui…...

【android USB 串口通信助手】stm32 源码demo 单片机与手机通信 Android studio 20241118

android 【OTG线】 接 下位机STM32【USB】 通过百度网盘分享的文件&#xff1a;USBToSerialPort.apk 链接&#xff1a;https://pan.baidu.com/s/122McdmBDUxEtYiEKFunFUg?pwd8888 提取码&#xff1a;8888 android 【OTG线】 接 【USB转TTL】 接 【串口(下位机 SMT32等)】 需…...

汽车资讯新探索:Spring Boot技术引领

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了汽车资讯网站的开发全过程。通过分析汽车资讯网站管理的不足&#xff0c;创建了一个计算机管理汽车资讯网站的方案。文章介绍了汽车资讯网站的系统分析部分&…...

简单的MCU与FPGA通过APB总线实现通讯(fpga mcu APB):乘法器为例

测试平台: GW1N4器件内置 M1内核;并且可以设置 APB总线与fpga 逻辑进行交互; 框图: +---------------------+ | | | M1 Microprocessor | <-----------------+ | | | | +-----------------…...

css uniapp背景图宽度固定高度自适应可以重复

page {height: 100%;background-image: url(https://onlinekc.a.hlidc.cn/uploads/20241115/350f94aaf493d05625a7ddbc86c7804e.png);background-repeat: repeat;background-size: contain;} 如果不要重复 把background-repeat: repeat;替换background-repeat: no-repeat;...

深度学习--优化器

笔记内容侵权联系删 优化器 在梯度下降算法中&#xff0c;有各种不同的改进版本。在面向对象的语言实现中&#xff0c;往往把不同的梯度下降算法封装成一个对象&#xff0c;称为优化器。 算法改进的目的&#xff0c;包括但不限于: 加快算法收敛速度; 尽量避过或冲过局部极值; …...

【嵌入式】关于push老仓库到新仓库的方法

1. 背景 公司项目经常会有需要从开源项目中镜像代码过来的活,所以常常会在自己的服务器上创建一个对应的仓库,然后使用命令将期push过去。为方便日后抄命令,这里记录一下使用的命令。 2. 操作步骤 2.1. 已下载的代码push 特别提醒: 使用此脚本前请确保你修改的代码已保存…...

从线下到线上,上门洗衣服务如何实现智能化升级?

在现代快节奏生活的推动下&#xff0c;上门洗衣服务作为一种新兴的服务模式正逐渐崭露头角。它以其便捷性和创新性&#xff0c;改变了传统洗衣行业的格局&#xff0c;为消费者提供了全新的选择&#xff0c;同时也为洗衣品牌带来了新的机遇与挑战。 一、上门洗衣服务的市场现状1…...

SQL字段来源表的解析

测试例子&#xff1a; SELECT e.NAME, d.DEPT_NAME,d.DEPT_ID,EMP_ID,100EMP_ID100 FROM EMP e JOIN DEPT d ON e.DEPT_ID d.DEPT_ID WHERE e.EMP_ID IN (SELECT EMP_ID FROM EMP WHERE DEPT_ID 10) 代码示例&#xff1a; package com.test; import org.apache.calcite.jd…...

理解 Python 解释器:CPython 与 IPython 的比较及选择指南

理解 Python 解释器&#xff1a;CPython 与 IPython 的比较及选择指南 在选择适合自己需求的 Python 解释器时&#xff0c;理解 CPython 和 IPython 之间的主要差异至关重要。本文将详细解释 CPython 和 IPython 的特性、优势和适用场景&#xff0c;以帮助用户做出明智的选择。…...