用Flask-Login库和阿里云短信推送服务实现网站注册登录功能

news2024/11/18 1:37:28

诸神缄默不语-个人CSDN博文目录

本文介绍如何用Flask-Login库和阿里云短信推送服务实现网站注册登录功能。

大致逻辑是在注册和找回密码时调用阿里云短信服务,登录时使用手机号+密码登录(别的安全功能还没有加)。

很多代码都是直接由ChatGPT生成的,所以前后可能不太统一。
能用就得了,要什么自行车。

文章目录

  • 1. 阿里云短信推送服务
  • 2. Flask-Login库
    • 2.1 初始化
    • 2.2 定义用户
    • 2.3 显示账号信息
    • 2.4 注册
    • 2.5 登录
    • 2.6 退出
    • 2.7 重置密码
    • 2.8 限制功能必须登录使用
  • 3. 本文撰写过程中的其他参考资料

1. 阿里云短信推送服务

可以薅100条的新人免费羊毛:https://www.aliyun.com/activity/daily/cloudcommunication-daily

OpenAPI调用访问的AccessKey信息,官方建议是创建一个RAM子用户,用它的AccessKey信息来调用。网站是这个:https://ram.console.aliyun.com/users/create
权限的话只用开启 OpenAPI 调用访问就够了。
如果在此时直接用这个AccessKey来请求短信推送服务的话,会返回:{'headers': {'date': 'omit', 'content-type': 'application/json;charset=utf-8', 'content-length': '171', 'connection': 'keep-alive', 'access-control-allow-origin': '*', 'access-control-expose-headers': '*', 'x-acs-request-id': 'omit', 'x-acs-trace-id': 'omit'}, 'statusCode': 200, 'body': {'Code': 'isp.RAM_PERMISSION_DENY', 'Message': 'RAM权限不足,请为当前使用的AccessKey对应RAM用户进行授权', 'RequestId': 'omit'}}
所以要先在https://ram.console.aliyun.com/users里面找到这个子用户,赋予这个系统权限(可以直接模糊查询“短信”):
在这里插入图片描述

设置签名:https://dysms.console.aliyun.com/domestic/text/sign(网站没备份的话就只能用测试账号,在“快速学习与测试”页面(https://dysms.console.aliyun.com/quickstart)绑定用以测试的手机号,除这些号以外的手机号都发不到)

设置模版:https://dysms.console.aliyun.com/domestic/text/template
参考模版:

  • (注册)您正在注册成为新用户,验证码为${code},验证码10分钟有效。如非本人操作,请忽略本短信。
  • (找回密码)您正在找回密码,验证码为${code},验证码10分钟有效。如非本人操作,请忽略本短信。

短信服务SDK的文档:短信服务_SDK中心-阿里云OpenAPI开发者门户

因为我用的是测试账号,所以如果下面填写测试手机号之外的账号,就会返回:{'headers': {'date': 'omit', 'content-type': 'application/json;charset=utf-8', 'content-length': '171', 'connection': 'keep-alive', 'access-control-allow-origin': '*', 'access-control-expose-headers': '*', 'x-acs-request-id': 'omit', 'x-acs-trace-id': 'omit'}, 'statusCode': 200, 'body': {'Code': 'isv.SMS_TEST_NUMBER_LIMIT', 'Message': '只能向已回复授权信息的手机号发送', 'RequestId': 'omit'}}

安装包:

pip install alibabacloud_ecs20140526==3.0.7
pip install alibabacloud_dysmsapi20170525==2.0.23

代码:(你可以发现在这里我事实上只处理了main(),没管异步代码……)

# -*- coding: utf-8 -*-
import sys

from typing import List

from alibabacloud_dysmsapi20170525.client import Client as Dysmsapi20170525Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_dysmsapi20170525 import models as dysmsapi_20170525_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_util.client import Client as UtilClient


class AliyunDuanxin:
    def __init__(self):
        pass

    @staticmethod
    def create_client(
        access_key_id: str,
        access_key_secret: str,
    ) -> Dysmsapi20170525Client:
        """
        使用AK&SK初始化账号Client
        @param access_key_id:
        @param access_key_secret:
        @return: Client
        @throws Exception
        """
        config = open_api_models.Config(
            # 必填,您的 AccessKey ID,
            access_key_id=access_key_id,
            # 必填,您的 AccessKey Secret,
            access_key_secret=access_key_secret
        )
        # 访问的域名
        config.endpoint = f'dysmsapi.aliyuncs.com'
        return Dysmsapi20170525Client(config)

    @staticmethod
    def main(
        accessKeyId:str,
        accessKeySecret:str,
        sign_name:str,
        template_code:str,
        phone_numbers:str,
        validation_code:str,
    ) -> None:
        client = AliyunDuanxin.create_client(accessKeyId,accessKeySecret)
        send_sms_request = dysmsapi_20170525_models.SendSmsRequest(
            sign_name=sign_name,
            template_code=template_code,
            phone_numbers=phone_numbers,
            template_param='{"code":"'+str(validation_code)+'"}'
        )
        runtime = util_models.RuntimeOptions()
        try:
             return client.send_sms_with_options(send_sms_request, runtime)
        except Exception as error:
            # 如有需要,请打印 error
            UtilClient.assert_as_string(error.message)
    
    @staticmethod
    async def main_async(
        accessKeyId:str,
        accessKeySecret:str,
        sign_name:str,
        template_code:str,
        phone_numbers:str,
        validation_code:str,
    ) -> None:
        client = AliyunDuanxin.create_client(accessKeyId,accessKeySecret)
        send_sms_request = dysmsapi_20170525_models.SendSmsRequest(
            sign_name=sign_name,
            template_code=template_code,
            phone_numbers=phone_numbers,
            template_param='{"code":"'+str(validation_code)+'"}'
        )
        runtime = util_models.RuntimeOptions()
        try:
            # 复制代码运行请自行打印 API 的返回值
            await client.send_sms_with_options_async(send_sms_request, runtime)
        except Exception as error:
            # 如有需要,请打印 error
            UtilClient.assert_as_string(error.message)


if __name__ == '__main__':
    AliyunDuanxin.main(omit)

正常运行后的输出就是:{'headers': {'date': 'omit', 'content-type': 'application/json;charset=utf-8', 'content-length': '171', 'connection': 'keep-alive', 'access-control-allow-origin': '*', 'access-control-expose-headers': '*', 'x-acs-request-id': 'omit', 'x-acs-trace-id': 'omit'}, 'statusCode': 200, 'body': {'BizId': 'omit', 'Code': 'OK', 'Message': 'OK', 'RequestId': 'omit'}

另外还有一种情况是发送太频繁了:{'headers': {'date': 'omit', 'content-type': 'application/json;charset=utf-8', 'content-length': '131', 'connection': 'keep-alive', 'access-control-allow-origin': '*', 'access-control-expose-headers': '*', 'x-acs-request-id': 'omit', 'x-acs-trace-id': 'omit'}, 'statusCode': 200, 'body': {'Code': 'isv.BUSINESS_LIMIT_CONTROL', 'Message': '触发小时级流控Permits:5', 'RequestId': 'omit'}}

2. Flask-Login库

安装:pip install flask-login

官方文档:Flask-Login — Flask-Login 0.7.0 documentation
flask的session官方文档:https://flask.palletsprojects.com/en/latest/quickstart/#sessions

官方GitHub项目:https://github.com/maxcountryman/flask-login

在这个博文中写过的内容将不会重复描述:在云服务器上安装MySQL (MariaDB) 数据库并与Python连接和互动

其他需要安装的工具包:

  1. Flask-WTF
    官方文档:Flask-WTF — Flask-WTF Documentation (1.0.x)
    安装方式:pip install Flask-WTF
    (会同时安装WTForms)
  2. WTForms
    官方GitHub项目:wtforms/wtforms: A flexible forms validation and rendering library for Python.
    官方文档:WTForms — WTForms Documentation (3.0.x)

2.1 初始化

from flask import request,render_template,session,redirect,url_for,flash
from flask_login import login_user, LoginManager, logout_user, current_user,login_required
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, ValidationError, EqualTo
from tables import User

app.secret_key=app_secret_key

这里的secret_key要是一个随机初始化的字节对象,如b'_5#y2L"F4Q8z\n\xec]/'(但是不要用这个,意思是让你自己生成一个)。
可以用代码生成:

import secrets
print(secrets.token_hex())

2.2 定义用户

#定义用户
login_manager=LoginManager()
login_manager.init_app(app)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

2.3 显示账号信息

#我的账号
@app.route('/myaccount')
def myaccount():
    if 'user_id' in session:
        return f'Logged in as {session["nickname"]}'
    return 'You are not logged in'

2.4 注册

class RegistrationForm(FlaskForm):
    phone = StringField('请填入您的手机号:', validators=[DataRequired()])
    nickname=StringField('请填写用户昵称:(可选)')
    password = PasswordField('请填写密码:', validators=[DataRequired()])
    password2 = PasswordField(
        '请再次确认密码:', validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField('注册')

    def validate_phone(self, phone):
        user = User.query.filter_by(phone_number=phone.data).first()
        if user is not None:
            raise ValidationError('您的手机号已经被注册过,请重新注册')
            
@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        #发送验证码
        yanzhengma=''.join([str(random.randint(0,9)) for _ in range(6)])
        session['verification_code']=yanzhengma
        validation_code_json=AliyunDuanxin.main(accessKeyId,accessKeySecret,sign_name,template_codes['register'],form.phone.data,yanzhengma)

        if validation_code_json.body.code=='OK':
            #短信发送成功,跳转到验证界面
            session['phone'] = form.phone.data
            session['password'] = form.password.data
            session["nickname"]=form.nickname.data
            return redirect(url_for('verify'))
        elif validation_code_json.body.code=='isv.SMS_TEST_NUMBER_LIMIT':
            flash('网站开发者没有开通正规短信服务,如需使用,请联系开发者将您的手机号加入测试服务')
        elif validation_code_json.body.code=='isv.BUSINESS_LIMIT_CONTROL':
            flash('发送验证码次数过多,请稍后重试!')
        else:
            return str(validation_code_json)
    return render_template('register.html', form=form)

class VerificationForm(FlaskForm):
    code = StringField('请输入您收到的6位数验证码:', validators=[DataRequired()])
    submit = SubmitField('确定')
    
@app.route('/verify', methods=['GET', 'POST'])
def verify():
    form = VerificationForm()
    if form.validate_on_submit():
        # 验证码正确
        if form.code.data == session.get('verification_code'):
            user = User(phone_number=session.get('phone'))
            user.set_password(session.get('password'))
            db.session.add(user)
            db.session.commit()
            flash('您已成功注册,请享受ScholarEase之旅吧!')
            return redirect(url_for('login'))
        else:
            flash('验证码错误')
    return render_template('verify.html', form=form)

register.html
在这里插入图片描述

<!DOCTYPE html>
<html>
<head>
    <title>Register</title>
    <!-- Include Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        <h2>Register</h2>
        <form method="POST">
            {{ form.hidden_tag() }}
            <div class="form-group">
                {{ form.phone.label }} {{ form.phone(class="form-control") }}
                {% if form.phone.errors %}
                    <ul class="errors">
                        {% for error in form.phone.errors %}
                            <li>{{ error }}</li>
                        {% endfor %}
                    </ul>
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.nickname.label }} {{ form.nickname(class="form-control") }}
                {% if form.nickname.errors %}
                    <ul class="errors">
                        {% for error in form.nickname.errors %}
                            <li>{{ error }}</li>
                        {% endfor %}
                    </ul>
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.password.label }} {{ form.password(class="form-control") }}
                {% if form.password.errors %}
                    <ul class="errors">
                        {% for error in form.password.errors %}
                            <li>{{ error }}</li>
                        {% endfor %}
                    </ul>
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.password2.label }} {{ form.password2(class="form-control") }}
                {% if form.password2.errors %}
                    <ul class="errors">
                        {% for error in form.password2.errors %}
                            <li>{{ error }}</li>
                        {% endfor %}
                    </ul>
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.submit(class="btn btn-primary") }}
            </div>
        </form>
    </div>

    {% with messages = get_flashed_messages() %}
        {% if messages %}
            <ul class=flashes>
            {% for message in messages %}
                <li>{{ message }}</li>
            {% endfor %}
            </ul>
        {% endif %}
    {% endwith %}

</body>
</html>

verify.html
在这里插入图片描述

<!DOCTYPE html>
<html>
<head>
    <title>Verify</title>
    <!-- Include Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        <h2>Verify</h2>
        <form method="POST">
            {{ form.hidden_tag() }}
            <div class="form-group">
                {{ form.code.label }} {{ form.code(class="form-control") }}
                {% if form.code.errors %}
                    <ul class="errors">
                        {% for error in form.code.errors %}
                            <li>{{ error }}</li>
                        {% endfor %}
                    </ul>
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.submit(class="btn btn-primary") }}
            </div>
        </form>
    </div>
</body>
</html>

注册成功之后跳转回登录界面:
在这里插入图片描述

2.5 登录

login_manager.login_view='login'
login_manager.login_message='您访问的页面需要登录使用'

class LoginForm(FlaskForm):
    phone = StringField('请填入您的手机号:', validators=[DataRequired()])
    password = PasswordField('请填写密码:', validators=[DataRequired()])
    remember_me = BooleanField('记住我')
    submit = SubmitField('登录')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        # 如果用户已经登录,显示一个消息并重定向到主页
        flash('您已成功登录,现在将您跳转到首页')
        return render_template('message.html')
    
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(phone_number=form.phone.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('手机号或密码错误')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        return redirect(url_for('get_home'))
    return render_template('login.html', form=form)

login_message是用于设置@login_required函数在未登录状态下被点击后的显示内容。

login.html
在这里插入图片描述

<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
    <!-- Include Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        <h2>Login</h2>
        <form method="POST">
            {{ form.hidden_tag() }}
            <div class="form-group">
                {{ form.phone.label }} {{ form.phone(class="form-control") }}
                {% if form.phone.errors %}
                    <ul class="errors">
                        {% for error in form.phone.errors %}
                            <li>{{ error }}</li>
                        {% endfor %}
                    </ul>
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.password.label }} {{ form.password(class="form-control") }}
                {% if form.password.errors %}
                    <ul class="errors">
                        {% for error in form.password.errors %}
                            <li>{{ error }}</li>
                        {% endfor %}
                    </ul>
                {% endif %}
            </div>
            <div class="form-group">
                {{ form.remember_me(class="form-check-input") }} {{ form.remember_me.label(class="form-check-label") }}
            </div>
            <div class="form-group">
                {{ form.submit(class="btn btn-primary") }}
            </div>
        </form>
    </div>

    {% with messages = get_flashed_messages() %}
        {% if messages %}
            <ul class=flashes>
            {% for message in messages %}
                <li>{{ message }}</li>
            {% endfor %}
            </ul>
        {% endif %}
    {% endwith %}
</body>
</html>

登录成功后跳转回主页:
在这里插入图片描述

2.6 退出

@app.route('/logout')
def logout():
    # 登出用户
    logout_user()
    # 显示一个消息
    flash('You have been logged out.')
    # 重定向到登录页面
    return redirect(url_for('login'))

在这里插入图片描述

2.7 重置密码

@app.route('/reset_password', methods=['GET', 'POST'])
def reset_password():
    form = ResetPasswordForm()
    if form.validate_on_submit():
        #发送验证码
        yanzhengma=''.join([str(random.randint(0,9)) for _ in range(6)])
        session['verification_code']=yanzhengma
        validation_code_json=AliyunDuanxin.main(accessKeyId,accessKeySecret,sign_name,template_codes['register'],form.phone.data,yanzhengma)

        if validation_code_json.body.code=='OK':
            # 保存用户信息到 session
            session['phone'] = form.phone.data
            session['new_password'] = form.new_password.data
            return redirect(url_for('verify_reset_password'))
        elif validation_code_json.body.code=='isv.SMS_TEST_NUMBER_LIMIT':
            flash('网站开发者没有开通正规短信服务,如需使用,请联系开发者将您的手机号加入测试服务')
        elif validation_code_json.body.code=='isv.BUSINESS_LIMIT_CONTROL':
            flash('发送验证码次数过多,请稍后重试!')
        else:
            return validation_code_json
    return render_template('reset_password.html',form=form)
    
@app.route('/verify_reset_password', methods=['GET', 'POST'])
def verify_reset_password():
    #限制发起请求的url
    referrer = request.referrer
    reset_password_url = url_for('reset_password')
    verify_reset_password_url = url_for('verify_reset_password')
    if referrer not in [reset_password_url, verify_reset_password_url]:
        flash("您的requests URL错误!")
        return redirect(url_for('reset_password'))

    form = VerificationForm()
    if form.validate_on_submit():
        # 验证码正确
        if form.code.data == session.get('verification_code'):
            user = User.query.filter_by(phone_number=session.get('phone')).first()
            if user is None:
                flash('Invalid phone number.')
                return redirect(url_for('reset_password'))
            user.set_password(session.get('new_password'))
            db.session.commit()
            flash('Your password has been reset.')
            return redirect(url_for('login'))
        else:
            flash('Invalid verification code.')
    return render_template('verify_reset_password.html', form=form)

reset_password.html
在这里插入图片描述

<!DOCTYPE html>
<html>
<head>
    <title>Reset Password</title>
</head>
<body>
    <h1>Reset Password</h1>
    <form action="{{ url_for('reset_password') }}" method="post">
        {{ form.hidden_tag() }}
        <p>
            {{ form.phone.label }}<br>
            {{ form.phone(size=20) }}
        </p>
        <p>
            {{ form.new_password.label }}<br>
            {{ form.new_password(size=20) }}
            {% for error in form.new_password.errors %}
                <span style="color: red;">{{ error }}</span>
            {% endfor %}
        </p>
        <p>
            {{ form.new_password2.label }}<br>
            {{ form.new_password2(size=20) }}
            {% for error in form.new_password2.errors %}
                <span style="color: red;">{{ error }}</span>
            {% endfor %}
        </p>
        <p>{{ form.submit() }}</p>
    </form>

    {% with messages = get_flashed_messages() %}
        {% if messages %}
            <ul class=flashes>
            {% for message in messages %}
                <li>{{ message }}</li>
            {% endfor %}
            </ul>
        {% endif %}
    {% endwith %}
</body>
</html>

verify_reset_password.html
在这里插入图片描述

<!DOCTYPE html>
<html>
<head>
    <title>Verify Reset Password</title>
</head>
<body>
    <h1>Verify Reset Password</h1>
    <form action="{{ url_for('verify_reset_password') }}" method="post">
        {{ form.hidden_tag() }}
        <p>
            {{ form.code.label }}<br>
            {{ form.code(size=20) }}
        </p>
        <p>{{ form.submit() }}</p>
    </form>
</body>
</html>

2.8 限制功能必须登录使用

@app.route()后面加一行@login_required

3. 本文撰写过程中的其他参考资料

  1. Flask+python3+阿里云平台发送短信 最简单最笨的那种_mingkoukou的博客-CSDN博客
  2. 注册登录功能设计:3种常见注册登录方案逻辑解析 | 人人都是产品经理

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

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

相关文章

Zinx框架学习 - 连接管理

Zinx - V0.9 连接管理 每个服务器的能够处理的最大IO数量是有限的&#xff0c;根据当前服务器能开辟的IO数量决定&#xff0c;最终决定权是内存大小现在我们要为Zinx框架增加链接个数的限定&#xff0c;如果超过⼀定量的客户端个数&#xff0c;Zinx为了保证后端的及时响应&…

浏览器断点调试技巧

一、前言 日常开发中&#xff0c;当业务测试数据展示有问题时&#xff0c;我们需要快速去排查问题出现原因&#xff1b;但看了自己写的逻辑&#xff0c;很自信的觉得没问题但最终展示和逻辑对不上。这个需要我们便可以利用浏览器断点调试功能&#xff0c;来逐步调试对比逻辑来…

IDEA 终端命令行设置

一、说明 在使用 IDEA 进行程序开发时&#xff0c;需要使用到终端 Terminal 的功能&#xff0c;便于能够快速使用 shell 命令&#xff0c;进行各种相关的操作。 这些操作可以包括代码的版本控制、程序的打包部署等等 比如&#xff0c;前后端的集成开发环境&#xff08;IDEA、We…

探究Cache缓存功能---【pytest】

前言 pytest运行完用例之后会生成一个 .pytest_cache的缓存文件夹&#xff0c;用于记录用例的ids和上一次失败的用例。 1、跑自动化时经常会出现这样一个情况&#xff0c;一轮自动化跑完后零星出现了几个失败测试用例&#xff0c;无法断定失败的原因&#xff0c;所以可能需要重…

2023新版Spring6全新讲解-核心内容之事务管理

Spring核心之事务 一、JdbcTemplate JdbcTemplate是Spring框架对JDBC操作进行的封装&#xff0c;可以简化方便对数据库的操作。 1.数据库表结构 准备一张普通的表 CREATE TABLE t_student (id int NOT NULL AUTO_INCREMENT,name varchar(32) DEFAULT NULL,age int DEFAULT N…

网络安全面试题大全(整理版)+附答案

随着国家政策的扶持&#xff0c;网络安全行业也越来越为大众所熟知&#xff0c;想要进入到网络安全行业的人也越来越多。 为了拿到心仪的 Offer 之外&#xff0c;除了学好网络安全知识以外&#xff0c;还要应对好企业的面试。 作为一个安全老鸟&#xff0c;工作这么多年&…

Vue.js 中的过渡动画是什么?如何使用过渡动画?

Vue.js 中的过渡动画是什么&#xff1f;如何使用过渡动画&#xff1f; 在 Vue.js 中&#xff0c;过渡动画是一种在元素插入、更新或删除时自动应用的动画效果&#xff0c;可以为应用程序增加一些动态和生动的效果。本文将介绍 Vue.js 中过渡动画的概念、优势以及如何使用过渡动…

谈“污”色变!如何应对测序中常见污染

微生物群落研究正在彻底改变人类对微生物学的理解&#xff0c;但是微生物污染的DNA存在于各种操作中包含从取样到测序结束。其中常用的DNA提取试剂盒和其他实验室试剂中也存在污染&#xff0c;其严重影响从微生物量较低的样品中获得的结果。 DNA污染的可能来源包括分子生物学级…

【嵌入式环境下linux内核及驱动学习笔记-(14)linux总线、设备、驱动模型之platform】

目录 1、新驱动架构的导入1.1 传统驱动方式的痛点1.2 总线设备驱动架构 2、platform 设备驱动2.1 platform总线式驱动的架构思想2.2 platform _device相关的数据类型2.2.1 struct platform_device2.2.2 struct platform_device_id2.2.3 struct resource2.2.4 struct device 2.3…

VSCode离线安装插件

一、前言 工作环境屏蔽外网&#xff0c;无法在VSCode客户端在线VSCode插件商店下载插件。因此&#xff0c;只能下载插件文件&#xff0c;并离线安装。 二、下载VSCode插件 1. 在VSCode插件商店中搜索需要的插件 2. 下载vsix格式插件 三、离线安装 VSCode 插件 1. 打开菜单Vi…

docker-compose部署hive数仓服务 —— 筑梦之路

1. docker创建网络 # 创建&#xff0c;注意不能使用hadoop-network docker network create hadoop_network# 查看 docker network ls 2. mysql部署 # 拉取镜像docker pull mysql:5.7# 生成配置mkdir -p conf/ data/db/cat > conf/my.cnf <<EOF [mysqld] character…

今天面了个字节跳动拿30k出来的测试大佬,让我见识到了什么是天花板

2022年堪称大学生就业最难的一年&#xff0c;应届毕业生人数是1076万。失业率超50%&#xff01; 但是我观察到一个数据&#xff0c;那就是已经就业的毕业生中&#xff0c;计算机通信等行业最受毕业生欢迎&#xff01; 计算机IT行业薪资高&#xff0c;平均薪资是文科其他岗位的…

Apache 日志解析和分析工具

ApacheWeb服务器在企业中广泛用于托管其网站和Web应用程序。Apache 服务器生成的原始日志提供了有关 Apache 服务器托管的网站如何处理用户请求以及访问您的网站时经常遇到的错误的宝贵信息。 什么是 Apache 日志 Apache 日志包含 Apache Web 服务器处理的所有事件的记录 - 从…

【Linux】LNMP框架的架构与环境配置

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 LNMP框架的架构与环境配置 一、安装 Nginx 服务1.关闭防火墙及安装依赖包2、创建运行用户3、编译安装4、优化路径5、添加 Nginx 系统服务 二、安装 MySQL 服务1、安装Mysql环…

图论与算法(4)图的深度优先遍历应用

1. 无向图的联通分量个数 1.1 联通分量个数 无向图的联通分量个数是指图中无法通过边连接到其他分量的顶点集合的个数。可以通过深度优先搜索或广度优先搜索来计算无向图的联通分量个数。 1.2 记录联通分量 &#xff08;1&#xff09;多个联通量的数&#xff1a; 7 6 0 1 0…

【MCS-51单片机汇编语言】期末复习总结⑥——串口通信(题型六)

文章目录 知识准备发送/接收缓冲器 SBUF串口通信控制寄存器SCON电源控制寄存器 PCON各个工作方式波特率的设定 常考题型例题1题目描述题目解析题解 例题2题目描述题解 知识准备 发送/接收缓冲器 SBUF 单片机在发送或接收数据的前先将数据存储在SBUF中&#xff1b;接收&#x…

STM32单片机蓝牙APP语音识别取暖器GSM短信超温报警

实践制作DIY- GC0141-蓝牙APP语音识别取暖器 基于STM32单片机设计---蓝牙APP语音识别取暖器 二、功能介绍&#xff1a; 电路&#xff1a;STM32F103C最小系统DS18B20温度传感器 多个按键 LCD1602显示器 1个串口语音识别模块1个5V 加热片 模拟加热蜂鸣器SIM800 GSM短信模块 HC0…

Type-C口统一在即,多节锂电池充放电管理难题何解?

在USB PD3.0时代&#xff0c;100W的充电功率已经能够满足绝大多数便携设备的充电需求&#xff0c;如智能手机、平板电脑、笔记本电脑等。最新的USB PD3.1快充标准&#xff0c;充电功率从原有的100W提升至240W&#xff0c;并支持最大48V的电压输出&#xff0c;将快充场景进一步延…

第四章 部署远程访问服务

♥️作者介绍&#xff1a;奇妙的大歪 ♥️个人名言&#xff1a;但行前路&#xff0c;不负韶华&#xff01; ♥️个人简介&#xff1a;云计算网络运维专业人员 目录 一.什么是远程访问&#xff1f; 二.远程访问的组成 三.远程访问的方式有哪些&#xff1f; 一、远程访问软件…

2017 年一月联考逻辑真题

2017 年一月联考逻辑真题 真题&#xff08;2017-26&#xff09; 26. 倪教授认为&#xff0c;我国工程技术领域可以考虑与国外先进技术合作&#xff0c;但任何涉及核心技术的项目就不能受制于人&#xff0c;我国许多网络安全建设项目涉及信息核心技术。如果全盘引进国外先进技术…