精华内容
下载资源
问答
  • 1、前台用户模型 前台用户模型定义 创建前台模型文件 apps/front/models.py # -*- encoding: utf-8 -*- """ @File : models.py @Time : 2020/5/11 10:00 @Author : chen 前台模型文件 apps/front/models.py """ # ...

    1、前台用户模型

    前台用户模型定义

    创建前台模型文件 apps/front/models.py

    # -*- encoding: utf-8 -*-
    """
    @File    : models.py
    @Time    : 2020/5/11 10:00
    @Author  : chen
    前台模型文件 apps/front/models.py
    """
    # 前台管理的模型
    from exts import db                   # 数据库连接
    import shortuuid                      # 前台用户id加密
    from datetime import datetime
    from werkzeug.security import generate_password_hash, check_password_hash         # 导入密码加密,解密方法的库
    import enum                           # 导入枚举
    
    
    # 性别选择的类
    class GenderEnum(enum.Enum):
        MALE = 1
        FEMALE = 2
        SECRET = 3
        UNKNOW = 4
    
    
    #   前台用户模型类
    class Front_User(db.Model):
        __tablename__ = "front_user"
        # id 类型不用db.Integer类型,使用String是为了防止爆破,同时使用shortuuid进行加密
        id = db.Column(db.String(100), primary_key=True, default=shortuuid.uuid)
        telephone = db.Column(db.String(11), nullable=False, unique=True)             # 非空唯一
        username = db.Column(db.String(150), nullable=False)
        _password = db.Column(db.String(150), nullable=False)                         # 密码加密操作修改字段
        email = db.Column(db.String(50), unique=True)
        
        realname = db.Column(db.String(50))
        avatar = db.Column(db.String(150))                                            # 头像,二进制数据
        signatrue = db.Column(db.String(500))                                         # 签名
        gender = db.Column(db.Enum(GenderEnum), default=GenderEnum.UNKNOW)            # 性别枚举类,默认未知
        join_time = db.Column(db.DateTime, default=datetime.now)  # 默认当前时间
        
        # 修改密码加密操作,manage.py映射数据库时候,使用字段保持相同,由于字段太多,使用传参形式
        def __init__(self, *args, **kwargs):
            if 'password' in kwargs:                       # 如果传参中包含有
                self.password = kwargs.get('password')     # 获取该参数值赋值给password
                kwargs.pop('password')                     # 模型参数中是_password,不是password,弹出
            
            # super(FrontUser, self).__init__(*args, **kwargs)   # python2的写法
            super().__init__(*args, **kwargs)
    
        # 密码加密操作
        @property
        def password(self):             # 密码取值
            return self._password
    
        @password.setter  # 密码加密
        def password(self, raw_password):
            self._password = generate_password_hash(raw_password)
    
        # 用于验证前台登录密码是否和数据库一致,raw_password是前台登录输入的密码
        def check_password(self, raw_password):
            result = check_password_hash(self.password, raw_password)  # 相当于用相同的hash加密算法加密raw_password,检测与数据库中是否一致
            return result
    

    前台用户模型映射到数据库

    映射数据库信息文件manage.py

    # -*- encoding: utf-8 -*-
    """
    @File    : manage.py
    @Time    : 2020/5/10 17:36
    @Author  : chen
    
    """
    from flask_script import Manager
    from bbs import app     # 需要将当前文件夹设置为当前根目录,才不会报错
    from flask_migrate import Migrate, MigrateCommand
    from exts import db
    
    # 导入后台模型 才能映射到数据库     导入后端的模型
    from apps.cms.models import CMS_User
    
    # 导入后台角色模型,映射到数据库         CMSPersmission角色权限定义类
    from apps.cms.models import CMSRole, CMSPersmission
    
    # 导入前台模型 才能映射到数据库
    from apps.front.models import Front_User
    
    manage = Manager(app)
    
    Migrate(app, db)
    manage.add_command('db', MigrateCommand)
    
    
    # 命令行添加后台用户
    @manage.option('-u', '--username', dest='username')
    @manage.option('-p', '--password', dest='password')
    @manage.option('-e', '--email', dest='email')
    def create_cms_user(username, password, email):
        user = CMS_User(username=username, password=password, email=email)
        # 添加映射到数据库,提交至数据库
        db.session.add(user)
        db.session.commit()
        print("cms后台用户添加成功")
    
    
    # 命令行添加前台用户
    @manage.option('-t', '--telephone', dest='telephone')
    @manage.option('-u', '--username', dest='username')
    @manage.option('-p', '--password', dest='password')
    def create_front_user(telephone, username, password):
        user = Front_User(telephone=telephone, username=username, password=password)
        # 添加映射到数据库,提交至数据库
        db.session.add(user)
        db.session.commit()
        print("front前台用户添加成功")
    
    
    # 添加角色  不传参用command
    @manage.command
    def create_role():
        # 访问者
        visitor = CMSRole(name="访问者", desc="只能查看数据,不能修改数据")
        visitor.permission = CMSPersmission.VISITOR                         # 权限
        
        # 运营人员
        operator = CMSRole(name="运营人员", desc="管理评论、帖子、管理前台用户")
        # 权限或运算,代表包含有运算中的所有权限     二进制的运算 001|010=011
        operator.permission = CMSPersmission.VISITOR | CMSPersmission.POSTER | CMSPersmission.CMSUSER | \
                              CMSPersmission.COMMENTER | CMSPersmission.FRONTUSER
        
        # 管理员
        admin = CMSRole(name="管理员", desc="拥有本系统大部分权限")
        admin.permission = CMSPersmission.VISITOR | CMSPersmission.POSTER | CMSPersmission.CMSUSER | \
                              CMSPersmission.COMMENTER | CMSPersmission.FRONTUSER | CMSPersmission.BOARDER
    
        # 开发人员
        developer = CMSRole(name="开发人员", desc="拥有本系统所有权限")
        developer.permission = CMSPersmission.ALL_PERMISSION
        
        # 提交数据库   添加身份字段到数据库中的表,
        db.session.add_all([visitor, operator, admin, developer])
        db.session.commit()
        return "创建角色成功"
    
    
    # 测试用户权限
    @manage.command
    def test_permission():
        # user = CMS_User.query.first()                          # 查询第一个用户,当时创建的用户还没有关联权限,所以应该是没有权限
        user = CMS_User.query.get(3)
        print(user)                                              # 显示用户信息
        if user.has_permissions(CMSPersmission.VISITOR):         # has_permissions方法判定是否具有该权限
            print("这个用户有访问者的权限!")
        else:
            print("这个用户有访问者的权限!")
    
    
    # 添加用户到角色里面
    @manage.option("-e", "--email", dest="email")
    @manage.option("-n", "--name", dest="name")
    def add_user_to_role(email, name):
        user = CMS_User.query.filter_by(email=email).first()                   # 通过邮箱查询用户
        if user:
            role = CMSRole.query.filter_by(name=name).first()                  # 邮箱存在的前提下,通过name查询角色
            if role:
                role.users.append(user)                                        # 将用户添加到角色中,list类型数据,role.users是CMSRole中的外键
                db.session.commit()                                            # 映射到数据库
                print("用户添加到角色成功")
            else:
                print("该角色不存在")
        else:
            print("邮箱不存在")
    
    
    if __name__ == '__main__':
        manage.run()
    
    

    命令行执行映射数据库

    python manage.py db migrate
    python manage.py db upgrade
    

    在这里插入图片描述
    命令行添加前台用户

    python manage.py create_front_user -t 15210438734 -u ch -p 1234
    

    在这里插入图片描述

    2、前台登录注册

    注册界面搭建

    前台用户注册界面:templates/front/front_signup.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>论坛注册</title>
        <script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
        <link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    
        <!--  导入css,js等静态文件  -->
        <link href="{{ url_for('static', filename='front/css/front_signbase.css') }}" rel="stylesheet">
    <!--    <script src="{{ url_for('static', filename='front/js/front_signup.js') }}"></script>-->
    
    
        <script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    </head>
    <body>
        <div class="outer-box">
            <div class="logo-box">
                <a href="/">
                    <img src="{{ url_for('static',filename='common/images/logo.png') }}"/>
                </a>
            </div>
            <h2 class="page-title">BBS论坛注册</h2>
    
            <div class="sign-box">
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" name="telephone" class="form-control" placeholder="手机号码">
                        <span class="input-group-btn">
                            <button class="btn btn-default">
                                发送验证码
                            </button>
                        </span>
                    </div>
                </div>
                <div class="form-group">
                    <input type="text" name="sms_captcha" class="form-control" placeholder="短信验证码">
                </div>
                <div class="form-group">
                    <input type="text" name="username" class="form-control" placeholder="用户名">
                </div>
                <div class="form-group">
                    <input type="password" name="password" class="form-control" placeholder="密码">
                </div>
                <div class="form-group">
                    <input type="password" name="password2" class="form-control" placeholder="确认密码">
                </div>
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" name="graph_captcha" class="form-control" placeholder="图形验证码">
    
                        <span class="input-group-addon captcha-addon">
                            图形验证码
    
                        </span>
                    </div>
                </div>
                <div class="form-group">
                    <button class="btn btn-warning btn-block">
                        立即注册
                    </button>
                </div>
            </div>
    
        </div>
    </body>
    </html>
    
    

    前台注册界面静态资源文件:static/front/css/front_base.css

    body{
        background: #f3f3f3;
    }
    .outer-box{
        width: 854px;
        background: #fff;
        margin: 0 auto;
        overflow: hidden;
    }
    .logo-box{
        text-align: center;
        padding-top: 40px;
    }
    .logo-box img{
        width: 60px;
        height:60px;
    }
    .page-title{
        text-align: center;
    }
    .sign-box{
        width: 300px;
        margin: 0 auto;
        padding-top: 50px;
    }
    .captcha-addon{
        padding: 0;
        overflow: hidden;
    }
    .captcha-img{
        width: 94px;
        height: 32px;
        cursor: pointer;
    }
    
    .captcha-addon{
        padding:0;
        /*溢出隐藏*/
        overflow: hidden;
    }
    
    .captcha-img{
        width:94px;
        height:32px;
        cursor:pointer;
    }
    

    前台的蓝图文件:apps/front/views.py

    # -*- encoding: utf-8 -*-
    """
    @File    : views.py
    @Time    : 2020/5/11 9:59
    @Author  : chen
    前台蓝图文件:apps/front/views.py
    """
    # 前台的蓝图文件  类视图函数写在这里
    from flask import Blueprint, render_template, views
    
    front_bp = Blueprint("front_bp", __name__)          # 前端不用前缀,直接在首页显示
    
    
    @front_bp.route("/")
    def index():
        return "front index:前端的首页"
    
    
    # 用户注册类视图
    class SingupView(views.MethodView):
        def get(self):
            return render_template("front/front_signup.html")
      
        def post(self):
            pass
    
    
    # 绑定类视图的路由
    front_bp.add_url_rule("/signup/", view_func=SingupView.as_view("/signup/"))
    
    

    需要注意的是:在static/common/images/文件夹中添加一个logo.png的图片文件,用于显示在注册界面上方:

    在这里插入图片描述

    3、图形验证码

    先导入pillow库

    pip install pillow -i https://pypi.tuna.tsinghua.edu.cn/simple/
    

    虚拟环境中此项目需要用的库:
    在这里插入图片描述
    创建图像验证码生成文件:utils/captcha/ _ _ init_ _.py

    import random
    import string
    # Image:一个画布
    # ImageDraw:一个画笔
    # ImageFont:画笔的字体
    from PIL import Image, ImageDraw, ImageFont
    
    
    # pip install pillow
    
    # Captcha验证码
    class Captcha(object):
        # 生成几位数的验证码
        number = 4
        # 验证码图片的宽度和高度
        size = (100, 30)
        # 验证码字体大小
        fontsize = 30
        # 加入干扰线的条数
        line_number = 2
    
        # 构建一个验证码源文本
        SOURCE = list(string.ascii_letters)
        for index in range(0, 10):
            SOURCE.append(str(index))
    
        # 用来绘制干扰线
        @classmethod
        def __gene_line(cls, draw, width, height):
            begin = (random.randint(0, width), random.randint(0, height))
            end = (random.randint(0, width), random.randint(0, height))
            draw.line([begin, end], fill=cls.__gene_random_color(), width=2)
    
        # 用来绘制干扰点
        @classmethod
        def __gene_points(cls, draw, point_chance, width, height):
            chance = min(100, max(0, int(point_chance)))  # 大小限制在[0, 100]
            for w in range(width):
                for h in range(height):
                    tmp = random.randint(0, 100)
                    if tmp > 100 - chance:
                        draw.point((w, h), fill=cls.__gene_random_color())
    
        # 生成随机的颜色
        @classmethod
        def __gene_random_color(cls, start=0, end=255):
            random.seed()
            return (random.randint(start, end), random.randint(start, end), random.randint(start, end))
    
        # 随机选择一个字体
        @classmethod
        def __gene_random_font(cls):
            fonts = [
                'Lobster-Regular.ttf',
                'verdana.ttf'
            ]
            font = random.choice(fonts)          # 随机选择一个列表中的字体
            
            return 'utils/captcha/' + font
    
        # 用来随机生成一个字符串(包括英文和数字)
        @classmethod
        def gene_text(cls, number):
            # number是生成验证码的位数
            return ''.join(random.sample(cls.SOURCE, number))
    
        # 生成验证码
        @classmethod
        def gene_graph_captcha(cls):
            # 验证码图片的宽和高
            width, height = cls.size
            # 创建图片
            # R:Red(红色)0-255
            # G:G(绿色)0-255
            # B:B(蓝色)0-255
            # A:Alpha(透明度)
            image = Image.new('RGBA', (width, height), cls.__gene_random_color(0, 100))
            # 验证码的字体
            font = ImageFont.truetype(cls.__gene_random_font(), cls.fontsize)
            # 创建画笔
            draw = ImageDraw.Draw(image)
            # 生成字符串
            text = cls.gene_text(cls.number)
            # 获取字体的尺寸
            font_width, font_height = font.getsize(text)
            # 填充字符串
            draw.text(((width - font_width) / 2, (height - font_height) / 2), text, font=font,
                      fill=cls.__gene_random_color(150, 255))
            # 绘制干扰线
            for x in range(0, cls.line_number):
                cls.__gene_line(draw, width, height)
            # 绘制噪点
            cls.__gene_points(draw, 10, width, height)
            return (text, image)
    
    # 测试文件
    # if __name__ == '__main__':
    #     c = Captcha()
    #     print(c.gene_graph_captcha())
    
    

    在这里插入图片描述
    视图文件apps/front/views.py文件测试图形验证码

    # -*- encoding: utf-8 -*-
    """
    @File    : views.py
    @Time    : 2020/5/11 9:59
    @Author  : chen
    前台蓝图文件:apps/front/views.py
    """
    # 前台的蓝图文件  类视图函数写在这里
    from flask import Blueprint, render_template, views, make_response    # make_response生成response对象,用于返回前端模板
    
    # 导入图像验证码生成文件
    from utils.captcha import Captcha
    
    # 图形验证码image是二进制数据,需要转换成字节流才能使用
    from io import BytesIO
    
    front_bp = Blueprint("front", __name__)          # 前端不用前缀,直接在首页显示,,front是蓝图,在front_signup.html调用生成图形验证码时候需要用
    
    
    @front_bp.route("/")
    def index():
        return "front index:前端的首页"
    
    
    # 图形验证码路由
    @front_bp.route("/captcha/")
    def graph_captcha():
        try:                                                 # 异常处理
            # 图像验证码生成文件中返回两个参数   text, image
            text, image = Captcha.gene_graph_captcha()      # 生成图形验证码,image是二进制数据,需要转换成字节流才能使用
            
            # BytesIO是生成的字节流
            out = BytesIO()
            image.save(out, 'png')                          # 把图片image保存在字节流中,并指定为png格式
            # 文件流指针
            out.seek(0)                                     # 从字节流最初开始读取
            # 生成response对象,用于返回前端模板中
            resp = make_response(out.read())
            resp.content_type = 'image/png'                 # 指定数据类型
        except:
            return graph_captcha()                          # 没有生成验证码就再调用一次
            
        return resp                                         # 返回对象
    
    
    # 用户注册类视图
    class SingupView(views.MethodView):
        def get(self):
            # 图像验证码生成文件中返回两个参数   text, image
            text, image = Captcha.gene_graph_captcha()
            # print(text)                                         # 验证码
            # print(image)                     # 图形文件,图形类<PIL.Image.Image image mode=RGBA size=100x30 at 0x1EFC9000C88>
            return render_template("front/front_signup.html")
      
        def post(self):
            pass
    
    
    # 绑定类视图的路由
    front_bp.add_url_rule("/signup/", view_func=SingupView.as_view("/signup/"))
    

    测试效果如下:
    在这里插入图片描述

    图形验证码渲染到注册页面

    修改前台用户注册界面:templates/front/front_signup.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>论坛注册</title>
        <script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
        <link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    
        <!--  导入css,js等静态文件  -->
        <link href="{{ url_for('static', filename='front/css/front_signbase.css') }}" rel="stylesheet">
    <!--    <script src="{{ url_for('static', filename='front/js/front_signup.js') }}"></script>-->
    
    
    <!--    <script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>-->
    <!--  引入js模板  -->
        <script src="{{ url_for('static', filename='front/js/front_signup.js' ) }}"></script>
    
    </head>
    <body>
        <div class="outer-box">
            <div class="logo-box">
                <a href="/">
                    <img src="{{ url_for('static',filename='common/images/logo.png') }}"/>
                </a>
            </div>
            <h2 class="page-title">BBS论坛注册</h2>
    
            <div class="sign-box">
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" name="telephone" class="form-control" placeholder="手机号码">
                        <span class="input-group-btn">
                            <button class="btn btn-default">
                                发送验证码
                            </button>
                        </span>
                    </div>
                </div>
                <div class="form-group">
                    <input type="text" name="sms_captcha" class="form-control" placeholder="短信验证码">
                </div>
                <div class="form-group">
                    <input type="text" name="username" class="form-control" placeholder="用户名">
                </div>
                <div class="form-group">
                    <input type="password" name="password" class="form-control" placeholder="密码">
                </div>
                <div class="form-group">
                    <input type="password" name="password2" class="form-control" placeholder="确认密码">
                </div>
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" name="graph_captcha" class="form-control" placeholder="图形验证码">
    
                        <span class="input-group-addon captcha-addon">
    
    <!--图形验证码调用 ,id="captcha-img"为了在front_signup.js绑定刷新验证码,('front.graph_captcha')是front蓝图调用views.py生成验证码方法,返回的是验证码的路由     蓝图名称.函数名-->
                        <img id="captcha-img" class="captcha-img" src="{{ url_for('front.graph_captcha') }}" alt="">
                        
                        </span>
                    </div>
                </div>
                <div class="form-group">
                    <button class="btn btn-warning btn-block">
                        立即注册
                    </button>
                </div>
            </div>
    
        </div>
    </body>
    </html>
    

    引入静态资源文件:static/front/js/front_signup.js

    var param = {
        setParam: function (href,key,value) {
            // 重新加载整个页面
            var isReplaced = false;
            var urlArray = href.split('?');               // 通过?分割url
    
            // 判定图形验证码的url长度,需要控制长度
            if(urlArray.length > 1){
                var queryArray = urlArray[1].split('&');
                for(var i=0; i < queryArray.length; i++){
                    var paramsArray = queryArray[i].split('=');
                    if(paramsArray[0] == key){
                        paramsArray[1] = value;
                        queryArray[i] = paramsArray.join('=');
                        isReplaced = true;
                        break;
                    }
                }
    
                if(!isReplaced){
                    var params = {};
                    params[key] = value;
                    if(urlArray.length > 1){
                        href = href + '&' + $.param(params);
                    }else{
                        href = href + '?' + $.param(params);
                    }
                }else{
                    var params = queryArray.join('&');
                    urlArray[1] = params;
                    href = urlArray.join('?');
                }
            }else{
                var param = {};
                param[key] = value;
                if(urlArray.length > 1){
                    href = href + '&' + $.param(param);
                }else{
                    href = href + '?' + $.param(param);
                }
            }
            return href;
        }
    };
    
    
    var lgajax = {
        'get':function(args) {
            args['method'] = 'get';
            this.ajax(args);
        },
        'post':function(args) {
            args['method'] = 'post';
            this.ajax(args);
        },
        'ajax':function(args) {
            // 设置csrftoken
            this._ajaxSetup();
            $.ajax(args);
        },
        '_ajaxSetup': function() {
            $.ajaxSetup({
                'beforeSend':function(xhr,settings) {
                    if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
                        var csrftoken = $('meta[name=csrf-token]').attr('content');
                        xhr.setRequestHeader("X-CSRFToken", csrftoken)
                    }
                }
            });
        }
    };
    
    $(function(){
        // #captcha-img绑定这个id,在front_signup.html文件中绑定图形验证码的id
        $('#captcha-img').click(function (event) {
            var self = $(this);
            var src = self.attr('src');
            // 每次 click之后,srcd地址改变,图形验证码就会刷新
            var newsrc = param.setParam(src,'xx',Math.random());
            self.attr('src',newsrc);
        });
    });
    
    
    // $(function () {
    // var __encode ='sojson.com',_a={}, _0xb483=["\x5F\x64\x65\x63\x6F\x64\x65","\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x73\x6F\x6A\x73\x6F\x6E\x2E\x63\x6F\x6D\x2F\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x6F\x62\x66\x75\x73\x63\x61\x74\x6F\x72\x2E\x68\x74\x6D\x6C"];(function(_0xd642x1){_0xd642x1[_0xb483[0]]= _0xb483[1]})(_a);var __Ox82dc8=["\x70\x72\x65\x76\x65\x6E\x74\x44\x65\x66\x61\x75\x6C\x74","\x76\x61\x6C","\x69\x6E\x70\x75\x74\x5B\x6E\x61\x6D\x65\x3D\x27\x74\x65\x6C\x65\x70\x68\x6F\x6E\x65\x27\x5D","\x74\x65\x73\x74","\u8BF7\u8F93\u5165\u6B63\u786E\u7684\u624B\u673A\u53F7\u7801\uFF01","\x61\x6C\x65\x72\x74\x49\x6E\x66\x6F","\x67\x65\x74\x54\x69\x6D\x65","\x71\x33\x34\x32\x33\x38\x30\x35\x67\x64\x66\x6C\x76\x62\x64\x66\x76\x68\x73\x64\x6F\x61\x60\x23\x24\x25","\x2F\x63\x2F\x73\x6D\x73\x5F\x63\x61\x70\x74\x63\x68\x61\x2F","\x63\x6F\x64\x65","\u77ED\u4FE1\u9A8C\u8BC1\u7801\u53D1\u9001\u6210\u529F\uFF01","\x61\x6C\x65\x72\x74\x53\x75\x63\x63\x65\x73\x73\x54\x6F\x61\x73\x74","\x64\x69\x73\x61\x62\x6C\x65\x64","\x61\x74\x74\x72","\x74\x65\x78\x74","\x72\x65\x6D\x6F\x76\x65\x41\x74\x74\x72","\u53D1\u9001\u9A8C\u8BC1\u7801","\x6D\x65\x73\x73\x61\x67\x65","\x61\x6C\x65\x72\x74\x49\x6E\x66\x6F\x54\x6F\x61\x73\x74","\x70\x6F\x73\x74","\x63\x6C\x69\x63\x6B","\x23\x73\x6D\x73\x2D\x63\x61\x70\x74\x63\x68\x61\x2D\x62\x74\x6E","\x75\x6E\x64\x65\x66\x69\x6E\x65\x64","\x6C\x6F\x67","\u5220\u9664","\u7248\u672C\u53F7\uFF0C\x6A\x73\u4F1A\u5B9A\u671F\u5F39\u7A97\uFF0C","\u8FD8\u8BF7\u652F\u6301\u6211\u4EEC\u7684\u5DE5\u4F5C","\x73\x6F\x6A\x73","\x6F\x6E\x2E\x63\x6F\x6D"];$(function(){$(__Ox82dc8[0x15])[__Ox82dc8[0x14]](function(_0x6781x1){_0x6781x1[__Ox82dc8[0x0]]();var _0x6781x2=$(this);var _0x6781x3=$(__Ox82dc8[0x2])[__Ox82dc8[0x1]]();if(!(/^1[345879]\d{9}$/[__Ox82dc8[0x3]](_0x6781x3))){lgalert[__Ox82dc8[0x5]](__Ox82dc8[0x4]);return};var _0x6781x4=( new Date)[__Ox82dc8[0x6]]();var _0x6781x5=md5(_0x6781x4+ _0x6781x3+ __Ox82dc8[0x7]);lgajax[__Ox82dc8[0x13]]({'\x75\x72\x6C':__Ox82dc8[0x8],'\x64\x61\x74\x61':{'\x74\x65\x6C\x65\x70\x68\x6F\x6E\x65':_0x6781x3,'\x74\x69\x6D\x65\x73\x74\x61\x6D\x70':_0x6781x4,'\x73\x69\x67\x6E':_0x6781x5},'\x73\x75\x63\x63\x65\x73\x73':function(_0x6781x6){if(_0x6781x6[__Ox82dc8[0x9]]== 200){lgalert[__Ox82dc8[0xb]](__Ox82dc8[0xa]);_0x6781x2[__Ox82dc8[0xd]](__Ox82dc8[0xc],__Ox82dc8[0xc]);var _0x6781x7=60;var _0x6781x8=setInterval(function(){_0x6781x7--;_0x6781x2[__Ox82dc8[0xe]](_0x6781x7);if(_0x6781x7<= 0){_0x6781x2[__Ox82dc8[0xf]](__Ox82dc8[0xc]);clearInterval(_0x6781x8);_0x6781x2[__Ox82dc8[0xe]](__Ox82dc8[0x10])}},1000)}else {lgalert[__Ox82dc8[0x12]](_0x6781x6[__Ox82dc8[0x11]])}}})})});;;(function(_0x6781x9,_0x6781xa,_0x6781xb,_0x6781xc,_0x6781xd,_0x6781xe){_0x6781xe= __Ox82dc8[0x16];_0x6781xc= function(_0x6781xf){if( typeof alert!== _0x6781xe){alert(_0x6781xf)};if( typeof console!== _0x6781xe){console[__Ox82dc8[0x17]](_0x6781xf)}};_0x6781xb= function(_0x6781x10,_0x6781x9){return _0x6781x10+ _0x6781x9};_0x6781xd= _0x6781xb(__Ox82dc8[0x18],_0x6781xb(__Ox82dc8[0x19],__Ox82dc8[0x1a]));try{_0x6781x9= __encode;if(!( typeof _0x6781x9!== _0x6781xe&& _0x6781x9=== _0x6781xb(__Ox82dc8[0x1b],__Ox82dc8[0x1c]))){_0x6781xc(_0x6781xd)}}catch(e){_0x6781xc(_0x6781xd)}})({})
    // })
    
    $(function () {
        // 绑定手机发送验证码按钮
        $("#sms-captcha-btn").click(function (event) {
            event.preventDefault();
            var self = $(this);
            var telephone = $("input[name='telephone']").val();
            if(!(/^1[345879]\d{9}$/.test(telephone))){
    
                lgalert.alertInfo('请输入正确的手机号码!');                 // 定义lgalert,需要导入static/comment/sweetalert/lgalert.js
                return;
            }
            var timestamp = (new Date).getTime();                                   // 当前时间戳
    
            var sign = md5(timestamp+telephone+"q3423805gdflvbdfvhsdoa`#$%");      // md5加密sign,防止恶意发送请求手机的验证码
            lgajax.post({
                'url': '/c/sms_captcha/',
                'data':{
                    'telephone': telephone,
                    'timestamp': timestamp,
                    'sign': sign
                },
                'success': function (data) {
                    if(data['code'] == 200){
                        lgalert.alertSuccessToast('短信验证码发送成功!');
                        self.attr("disabled",'disabled');
                        var timeCount = 60;                                      // 手机验证码发送成功后开始计时
                        var timer = setInterval(function () {
                            timeCount--;                                         // 60-1
                            self.text(timeCount);
                            if(timeCount <= 0){
                                self.removeAttr('disabled');
                                clearInterval(timer);
                                self.text('发送验证码');
                            }
                        },1000);
                    }else{
                        lgalert.alertInfoToast(data['message']);
                    }
                }
            });
        });
    });
    
    $(function(){
        $("#submit-btn").click(function(event){
            event.preventDefault();
            var telephone_input = $("input[name='telephone']");
            var sms_captcha_input = $("input[name='sms_captcha']");
            var username_input = $("input[name='username']");
            var password1_input = $("input[name='password1']");
            var password2_input = $("input[name='password2']");
            var graph_captcha_input = $("input[name='graph_captcha']");
    
            var telephone = telephone_input.val();
            var sms_captcha = sms_captcha_input.val();
            var username = username_input.val();
            var password1 = password1_input.val();
            var password2 = password2_input.val();
            var graph_captcha = graph_captcha_input.val();
    
            lgajax.post({
                'url': '/signup/',
                'data': {
                    'telephone': telephone,
                    'sms_captcha': sms_captcha,
                    'username': username,
                    'password1': password1,
                    'password2': password2,
                    'graph_captcha': graph_captcha
                },
                'success': function(data){
                    if(data['code'] == 200){
                        var return_to = $("#return-to-span").text();
                        if(return_to){
                            window.location = return_to;
                        }else{
                            window.location = '/';
                        }
                    }else{
                        lgalert.alertInfo(data['message']);
                    }
                },
                'fail': function(){
                    lgalert.alertNetworkError();
                }
            });
        });
    });
    

    渲染效果如下:
    在这里插入图片描述

    4、手机短信验证码

    手机短信发送平台:
    云片
    阿里大于
    (都需要充钱)

    这个项目使用的是云片,查看云片SDK的github网页:

    https://github.com/yunpian/yunpian-python-sdk
    在这里插入图片描述

    导入
    pip install yunpian-python-sdk
    

    在这里插入图片描述
    创建生成手机短信验证码发送文件:utils/send_telephone_msg.py

    # -*- encoding: utf-8 -*-
    """
    @File    : send_telephone_msg.py
    @Time    : 2020/5/22 16:18
    @Author  : chen
    发送验证码到手机的功能:utils/send_telephone_msg.py
    """
    # 发送验证码到手机的功能
    from yunpian_python_sdk.model import constant as YC
    from yunpian_python_sdk.ypclient import YunpianClient
    
    
    # 封装成方法
    def send_telephone_msg(telephone, code):
        # 初始化client,apikey作为所有请求的默认值
        # clnt = YunpianClient('70b0eb56669841bbecff6c000c99d7e7')                                 # API key是云片账号中绑定的私有的
        clnt = YunpianClient('xxx')  # API key是云片账号中绑定的私有的
        
        param = {YC.MOBILE: telephone, YC.TEXT: '【xxx】您的验证码是{}'.format(code)}
        r = clnt.sms().single_send(param)
        return r.code()                                                                            # 返回发送状态码
        
    
    # print(r.code())    # 0    代表发送成功
    # print(r.msg())     # 发送成功
    # print(r.data())    # {'code': 0, 'msg': '发送成功', 'count': 1, 'fee': 0.05, 'unit': 'RMB', 'mobile': '13316551764', 'sid': 54051316288}
    # 获取返回结果, 返回码:r.code(),返回码描述:r.msg(),API结果:r.data(),其他说明:r.detail(),调用异常:r.exception()
    # 短信:clnt.sms() 账户:clnt.user() 签名:clnt.sign() 模版:clnt.tpl() 语音:clnt.voice() 流量:clnt.flow()
    

    在共有文件夹中添加生成手机验证码功能文件视图文件:apps/common/views.py

    # -*- encoding: utf-8 -*-
    # -*- encoding: utf-8 -*-
    """
    @File    : views.py
    @Time    : 2020/5/11 9:59
    @Author  : chen
    视图文件:apps/common/views.py
    """
    # 导入手机验证码生成文件
    from utils.send_telephone_msg import send_phone_msg
    
    from utils import restful
    from utils.captcha import Captcha
    from flask import Blueprint, request
    
    
    common_bp = Blueprint("common", __name__, url_prefix='/c')      # 视图common,url前缀c,在
    
    
    # 手机验证码生成文件
    @common_bp.route("/sms_captcha/", methods=['POST'])
    def sms_captcha():
        telephone = request.form.get('telephone')        # 表单信息收集
        
        if not telephone:
            return restful.params_error(message="请填写手机号")              # 手机信息不存在,输出错误
        
        captcha = Captcha.gene_text(number=4)                               # 生成4位验证码,这里生成的是验证码,要发送到手机端的,不能是图形验证码
        # captcha = get_random_captcha(num=4):                              # 或者使用utils/random_captcha.py文件中的随机生成验证码
        
        # 调用send_telephone_msg.py中send_phone_msg方法发送4位验证码到手机中
        if send_phone_msg(telephone, captcha) == 0:                         # 返回成功的状态码为 0
            return restful.success()
        else:
            return restful.params_error("手机验证码发送失败")                 # 手机验证码发送失败
    
    

    注册公有蓝图文件到主程序文件:bbs.py

    # -*- encoding: utf-8 -*-
    """
    @File    : bbs.py
    @Time    : 2020/5/11 9:46
    @Author  : chen
    
    """
    # 项目主文件,启动入口
    
    # 前台  front    管理前端界面的逻辑
    # 后台  cms      管理后端的操作
    # 公有的文件 common
    
    from flask import Flask
    import config                              # 配置文件库
    from exts import db, mail                  # 第三方库导入db,mail
    from apps.cms.views import cms_bp          # 导入后端蓝图文件
    from apps.front.views import front_bp      # 导入前端蓝图文件
    from apps.common.views import common_bp    # 导入公有蓝图文件
    from flask_wtf import CSRFProtect          # CSRF表单保护验证
    
    app = Flask(__name__)
    
    CSRFProtect(app)                           # CSRF保护app
    
    app.config.from_object(config)             # 添加配置
    
    db.init_app(app)                           # 绑定app
    mail.init_app(app)                         # mail绑定app
    
    app.register_blueprint(cms_bp)             # 后端蓝图文件注册
    app.register_blueprint(front_bp)           # 前端蓝图文件注册
    app.register_blueprint(common_bp)         # 公有蓝图文件注册
    
    
    if __name__ == '__main__':
        app.run(debug=True, port=9999)
    

    但是还需要考虑到前端界面SCRF的验证问题,需要修改front_signup.html文件
    在这里插入图片描述
    关联前端界面的发送验证码按钮:front_signup.html,并添加CSRF验证

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
    
        <!--  在头文件中接收csrf信息  -->
        <meta name="csrf-token" content="{{ csrf_token() }}">
    
        <title>论坛注册</title>
        <script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
        <link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    
        <!--  导入css,js等静态文件  -->
        <link href="{{ url_for('static', filename='front/css/front_signbase.css') }}" rel="stylesheet">
    <!--    <script src="{{ url_for('static', filename='front/js/front_signup.js') }}"></script>-->
    
    
    <!--    <script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>-->
    <!--  引入js  -->
        <script src="{{ url_for('static', filename='front/js/front_signup.js' ) }}"></script>
    
        <!--  导入static/comment/sweetalert/lgalert.js,提示框的静态资源文件  -->
        <link rel="stylesheet" href="{{ url_for('static', filename='common/sweetalert/sweetalert.css') }}">
    <!-- 关联提示框的js样式  -->
        <script src="{{ url_for('static', filename='common/sweetalert/lgalert.js') }}"></script>
        <script src="{{ url_for('static', filename='common/sweetalert/sweetalert.min.js') }}"></script>
    <!--MD5加密-->
        <script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.js"></script>
    
    </head>
    <body>
        <div class="outer-box">
            <div class="logo-box">
                <a href="/">
                    <img src="{{ url_for('static',filename='common/images/logo.png') }}"/>
                </a>
            </div>
            <h2 class="page-title">BBS论坛注册</h2>
    
            <div class="sign-box">
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" name="telephone" class="form-control" placeholder="手机号码">
                        <span class="input-group-btn">
    
                            <!--  绑定sms-captcha-btn的按钮id,id显示在front_signup.html   -->
                            <button class="btn btn-default" id="sms-captcha-btn">
                                发送验证码
                            </button>
                            
                        </span>
                    </div>
                </div>
                <div class="form-group">
                    <input type="text" name="sms_captcha" class="form-control" placeholder="短信验证码">
                </div>
                <div class="form-group">
                    <input type="text" name="username" class="form-control" placeholder="用户名">
                </div>
                <div class="form-group">
                    <input type="password" name="password" class="form-control" placeholder="密码">
                </div>
                <div class="form-group">
                    <input type="password" name="password2" class="form-control" placeholder="确认密码">
                </div>
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" name="graph_captcha" class="form-control" placeholder="图形验证码">
    
                        <span class="input-group-addon captcha-addon">
    
                            <!--图形验证码调用 ,id="captcha-img"为了在front_signup.js绑定刷新验证码,('front.graph_captcha')是front蓝图调用views.py生成验证码方法,返回的是验证码的路由 -->
                           <img id="captcha-img" class="captcha-img" src="{{ url_for('front.graph_captcha') }}" alt="">
    
                        </span>
                    </div>
                </div>
                <div class="form-group">
                    <button class="btn btn-warning btn-block">
                        立即注册
                    </button>
                </div>
            </div>
    
        </div>
    </body>
    </html>
    

    5、添加表单验证短信验证码请求

    当前的短信请求只需要调用路由,就会被执行,不够安全,需要进行Form表单验证:利用下面的三个表单信息进行验证:

    telephone: 13316551764
    timestamp: 1590218267779
    sign: 3a94b6c107973b94e557d909fcea54cc
    

    在这里插入图片描述
    表单验证文件:apps/common/forms.py:验证当前页面的请求是否正常

    # -*- encoding: utf-8 -*-
    # -*- encoding: utf-8 -*-
    """
    @File    : forms.py
    @Time    : 2020/5/11 10:00
    @Author  : chen
    表单验证文件:apps/common/forms.py
    """
    # 表单验证手机短信验证码
    from wtforms import Form
    from wtforms import StringField
    from wtforms.validators import InputRequired, Regexp
    import hashlib          # 哈希md5加密
    
    ''' 页面请求Form会有下面三个表单信息,利用他们进行验证当前页面的请求是否正常
    telephone: 13316551764
    timestamp: 1590218267779
    sign: 3a94b6c107973b94e557d909fcea54cc
    '''
    
    
    # 调用front_signup.js中生成的sign进行Form验证当前页面的请求是否正常
    class SMSCaptchaForm(Form):
        telephone = StringField(validators=[Regexp(r'1[2345789]\d{9}')])        # 正则表达式验证手机号码
        timestamp = StringField(validators=[Regexp(r'\d{13}')])                 # 正则表达式验证时间戳长度
        sign = StringField(validators=[InputRequired])                          # 请求中需要有sign
    
        # 验证前端发送过来的sign和后端md5加密之后的sign是否一致
        def validate_sign(self, field):
            telephone = self.telephone.data
            timestamp = self.timestamp.data
            sign = self.sign.data
            
            # 服务端自己加密之后生成的sign,都是md5加密,加密的内容是通过front_signup.js中的加密内容相同
            # md5加密前需要转码才行.encode('utf-8');             .hexdigest()将加密后内容转换成字符串
            sign2 = hashlib.md5((timestamp+telephone+"q3423805gdflvbdfvhsdoa`#$%").encode('utf-8')).hexdigest()
            print("客户端sign %s" % sign)
            print("服务端sign2 %s" % sign2)
            
            # 验证客户端sign和服务端sign2是否相同
            if sign == sign2:
                return True
            else:
                return False
    
    

    修改视图文件:apps/common/views.py

    # -*- encoding: utf-8 -*-
    """
    @File    : views.py
    @Time    : 2020/5/11 9:59
    @Author  : chen
    视图文件:apps/common/views.py
    """
    # 导入手机验证码生成文件
    from utils.send_telephone_msg import send_phone_msg
    
    from utils import restful
    from utils.captcha import Captcha
    from flask import Blueprint, request
    
    # 导入form表单信息验证客户端sign2和服务端sign
    from apps.common.forms import SMSCaptchaForm
    
    common_bp = Blueprint("common", __name__, url_prefix='/c')      # 视图common,url前缀c,在
    
    
    # 手机验证码生成文件,这部分是只要调用当前路由请求,就会发送短信验证码,
    # 需要利用sign = md5(timestamp+telephone+"q3423805gdflvbdfvhsdoa`#$%"),在front_signup.js文件中调用
    # @common_bp.route("/sms_captcha/", methods=['POST'])
    # def sms_captcha():
    #     telephone = request.form.get('telephone')        # 表单信息收集
    #
    #     if not telephone:
    #         return restful.params_error(message="请填写手机号")              # 手机信息不存在,输出错误
    #
    #     captcha = Captcha.gene_text(number=4)                               # 生成4位验证码,这里生成的是验证码,要发送到手机端的,不能是图形验证码
    #     # captcha = get_random_captcha(num=4):                              # 或者使用utils/random_captcha.py文件中的随机生成验证码
    #
    #     # 调用send_telephone_msg.py中send_phone_msg方法发送4位验证码到手机中
    #     if send_phone_msg(telephone, captcha) == 0:                         # 返回成功的状态码为 0
    #         return restful.success()
    #     else:
    #         return restful.params_error("手机验证码发送失败")                 # 手机验证码发送失败
    
    
    # 在front_signup.js文件中调用sign = md5()验证表单信息.
    @common_bp.route("/sms_captcha/", methods=['POST'])
    def sms_captcha():
        form = SMSCaptchaForm(request.form)               # 收集form表单信息
        
        if form.validate():                               # 表单信息存在
            return restful.success()
        else:
            return restful.params_error(message="参数错误")   
    

    还需要使用工具对js代码中的md5加密方式进行加密:

    js在线加密网址

    将加密后的包含md5加密方法function在front_signup.js文件中进行替换:
    修改静态资源文件:static/front/js/front_signup.js

    var param = {
        setParam: function (href,key,value) {
            // 重新加载整个页面
            var isReplaced = false;
            var urlArray = href.split('?');               // 通过?分割url
    
            // 判定图形验证码的url长度,需要控制长度
            if(urlArray.length > 1){
                var queryArray = urlArray[1].split('&');
                for(var i=0; i < queryArray.length; i++){
                    var paramsArray = queryArray[i].split('=');
                    if(paramsArray[0] == key){
                        paramsArray[1] = value;
                        queryArray[i] = paramsArray.join('=');
                        isReplaced = true;
                        break;
                    }
                }
    
                if(!isReplaced){
                    var params = {};
                    params[key] = value;
                    if(urlArray.length > 1){
                        href = href + '&' + $.param(params);
                    }else{
                        href = href + '?' + $.param(params);
                    }
                }else{
                    var params = queryArray.join('&');
                    urlArray[1] = params;
                    href = urlArray.join('?');
                }
            }else{
                var param = {};
                param[key] = value;
                if(urlArray.length > 1){
                    href = href + '&' + $.param(param);
                }else{
                    href = href + '?' + $.param(param);
                }
            }
            return href;
        }
    };
    
    
    var lgajax = {
        'get':function(args) {
            args['method'] = 'get';
            this.ajax(args);
        },
        'post':function(args) {
            args['method'] = 'post';
            this.ajax(args);
        },
        'ajax':function(args) {
            // 设置csrftoken
            this._ajaxSetup();
            $.ajax(args);
        },
        '_ajaxSetup': function() {
            $.ajaxSetup({
                'beforeSend':function(xhr,settings) {
                    if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
                        var csrftoken = $('meta[name=csrf-token]').attr('content');
                        xhr.setRequestHeader("X-CSRFToken", csrftoken)
                    }
                }
            });
        }
    };
    
    $(function(){
        // #captcha-img绑定这个id,在front_signup.html文件中绑定图形验证码的id
        $('#captcha-img').click(function (event) {
            var self = $(this);
            var src = self.attr('src');
            // 每次 click之后,srcd地址改变,图形验证码就会刷新
            var newsrc = param.setParam(src,'xx',Math.random());
            self.attr('src',newsrc);
        });
    });
    
    
    // $(function () {
    // var __encode ='sojson.com',_a={}, _0xb483=["\x5F\x64\x65\x63\x6F\x64\x65","\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x73\x6F\x6A\x73\x6F\x6E\x2E\x63\x6F\x6D\x2F\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x6F\x62\x66\x75\x73\x63\x61\x74\x6F\x72\x2E\x68\x74\x6D\x6C"];(function(_0xd642x1){_0xd642x1[_0xb483[0]]= _0xb483[1]})(_a);var __Ox82dc8=["\x70\x72\x65\x76\x65\x6E\x74\x44\x65\x66\x61\x75\x6C\x74","\x76\x61\x6C","\x69\x6E\x70\x75\x74\x5B\x6E\x61\x6D\x65\x3D\x27\x74\x65\x6C\x65\x70\x68\x6F\x6E\x65\x27\x5D","\x74\x65\x73\x74","\u8BF7\u8F93\u5165\u6B63\u786E\u7684\u624B\u673A\u53F7\u7801\uFF01","\x61\x6C\x65\x72\x74\x49\x6E\x66\x6F","\x67\x65\x74\x54\x69\x6D\x65","\x71\x33\x34\x32\x33\x38\x30\x35\x67\x64\x66\x6C\x76\x62\x64\x66\x76\x68\x73\x64\x6F\x61\x60\x23\x24\x25","\x2F\x63\x2F\x73\x6D\x73\x5F\x63\x61\x70\x74\x63\x68\x61\x2F","\x63\x6F\x64\x65","\u77ED\u4FE1\u9A8C\u8BC1\u7801\u53D1\u9001\u6210\u529F\uFF01","\x61\x6C\x65\x72\x74\x53\x75\x63\x63\x65\x73\x73\x54\x6F\x61\x73\x74","\x64\x69\x73\x61\x62\x6C\x65\x64","\x61\x74\x74\x72","\x74\x65\x78\x74","\x72\x65\x6D\x6F\x76\x65\x41\x74\x74\x72","\u53D1\u9001\u9A8C\u8BC1\u7801","\x6D\x65\x73\x73\x61\x67\x65","\x61\x6C\x65\x72\x74\x49\x6E\x66\x6F\x54\x6F\x61\x73\x74","\x70\x6F\x73\x74","\x63\x6C\x69\x63\x6B","\x23\x73\x6D\x73\x2D\x63\x61\x70\x74\x63\x68\x61\x2D\x62\x74\x6E","\x75\x6E\x64\x65\x66\x69\x6E\x65\x64","\x6C\x6F\x67","\u5220\u9664","\u7248\u672C\u53F7\uFF0C\x6A\x73\u4F1A\u5B9A\u671F\u5F39\u7A97\uFF0C","\u8FD8\u8BF7\u652F\u6301\u6211\u4EEC\u7684\u5DE5\u4F5C","\x73\x6F\x6A\x73","\x6F\x6E\x2E\x63\x6F\x6D"];$(function(){$(__Ox82dc8[0x15])[__Ox82dc8[0x14]](function(_0x6781x1){_0x6781x1[__Ox82dc8[0x0]]();var _0x6781x2=$(this);var _0x6781x3=$(__Ox82dc8[0x2])[__Ox82dc8[0x1]]();if(!(/^1[345879]\d{9}$/[__Ox82dc8[0x3]](_0x6781x3))){lgalert[__Ox82dc8[0x5]](__Ox82dc8[0x4]);return};var _0x6781x4=( new Date)[__Ox82dc8[0x6]]();var _0x6781x5=md5(_0x6781x4+ _0x6781x3+ __Ox82dc8[0x7]);lgajax[__Ox82dc8[0x13]]({'\x75\x72\x6C':__Ox82dc8[0x8],'\x64\x61\x74\x61':{'\x74\x65\x6C\x65\x70\x68\x6F\x6E\x65':_0x6781x3,'\x74\x69\x6D\x65\x73\x74\x61\x6D\x70':_0x6781x4,'\x73\x69\x67\x6E':_0x6781x5},'\x73\x75\x63\x63\x65\x73\x73':function(_0x6781x6){if(_0x6781x6[__Ox82dc8[0x9]]== 200){lgalert[__Ox82dc8[0xb]](__Ox82dc8[0xa]);_0x6781x2[__Ox82dc8[0xd]](__Ox82dc8[0xc],__Ox82dc8[0xc]);var _0x6781x7=60;var _0x6781x8=setInterval(function(){_0x6781x7--;_0x6781x2[__Ox82dc8[0xe]](_0x6781x7);if(_0x6781x7<= 0){_0x6781x2[__Ox82dc8[0xf]](__Ox82dc8[0xc]);clearInterval(_0x6781x8);_0x6781x2[__Ox82dc8[0xe]](__Ox82dc8[0x10])}},1000)}else {lgalert[__Ox82dc8[0x12]](_0x6781x6[__Ox82dc8[0x11]])}}})})});;;(function(_0x6781x9,_0x6781xa,_0x6781xb,_0x6781xc,_0x6781xd,_0x6781xe){_0x6781xe= __Ox82dc8[0x16];_0x6781xc= function(_0x6781xf){if( typeof alert!== _0x6781xe){alert(_0x6781xf)};if( typeof console!== _0x6781xe){console[__Ox82dc8[0x17]](_0x6781xf)}};_0x6781xb= function(_0x6781x10,_0x6781x9){return _0x6781x10+ _0x6781x9};_0x6781xd= _0x6781xb(__Ox82dc8[0x18],_0x6781xb(__Ox82dc8[0x19],__Ox82dc8[0x1a]));try{_0x6781x9= __encode;if(!( typeof _0x6781x9!== _0x6781xe&& _0x6781x9=== _0x6781xb(__Ox82dc8[0x1b],__Ox82dc8[0x1c]))){_0x6781xc(_0x6781xd)}}catch(e){_0x6781xc(_0x6781xd)}})({})
    // })
    
    // js加密方法,使得md5加密方式不被破解
    $(function () {
        /*
     * 加密工具已经升级了一个版本,目前为 sojson.v5 ,主要加强了算法,以及防破解【绝对不可逆】配置,耶稣也无法100%还原,我说的。;
     * 已经打算把这个工具基础功能一直免费下去。还希望支持我。
     * 另外 sojson.v5 已经强制加入校验,注释可以去掉,但是 sojson.v5 不能去掉(如果你开通了VIP,可以手动去掉),其他都没有任何绑定。
     * 誓死不会加入任何后门,sojson JS 加密的使命就是为了保护你们的Javascript 。
     * 警告:如果您恶意去掉 sojson.v5 那么我们将不会保护您的JavaScript代码。请遵守规则
     * 新版本: https://www.jsjiami.com/ 支持批量加密,支持大文件加密,拥有更多加密。 */
    ;var encode_version = 'sojson.v5', cvwjl = '__0x83a8c',  __0x83a8c=['w4HDvGjDgcKf','w4rDvE7CjMOJ','c8OeTGo1','KMKEwr48V8OyBmXChBRnNHB9AcOpw4k7w51fQcOYw6c3RyE=','VsKsw5lM','w5hVTSDDknYDw4Jyw6HDjFvDoiDCjA==','D8OZw5s=','556z5L6i6aiv6KyE56Ct5Yy/6YGJ5oqC5Ymu77yX','wrEQwrk=','MybDkMK2TcKJLQ==','wr9Hw50=','5Y+j6YCt6aqz6K6G56Co','wqXCp8Kcw7HCsg==','w7AUwrQ6wpk=','BXwkw6QU','wqpuw5xlSMOpc38JwrvDjMO/wrEyw7LChB8=','R8K8wp1ZwqM=','FXsBXw==','L8Ouw7xsKQ==','w4J+w4fDuDI=','HwvDq8KDSw==','w79WwozCt8K7I8KXVA==','5Y2/6YKK6aqr6K2Z56Op','wqAqHMK8w5HDlsKNdSEe','dxQjGMK6','S8OyZ2QP','ccKgw5JMfQ==','w6HDpmPCvg==','wqjDvsKyw5nDiA==','TsK5wr51IQ==','e8KAwoZEwo4=','E8OuwoYvc8KAQ8KvLcKvw5HDkcKWwpfCgxjDpw==','55+45L6i6aul6K6M56Oy5Y+V6YOR5oqW5Yq277yS','w6Yfw5zCuQ==','NsK8w7TCv3Q=','woNYw7Q=','w53DpE3Dq8KHQgLDrcOu','54iI5p+J5Y2177+RUyjkvZnlr73mnZ7lvIjnq4/vvYPovYDorqbml4Lmjr/mirHkuqfnmq/lt4LkvYo=','5YuX6ZmS54iq5p2/5Y2I77yJNsOS5LyJ5ayL5p6n5byB56id','OsOYwq4=','w7ggwo4=','cMKTw49Wdg==','wqXDhsKhw6bDtlnDomUs','wrfCpRAcwpg=','FWrCsR/DsQ==','w5tRMxsW','w6rDiE3CkcOH','w4PDpGLClcKO','wqLDjcKow6zDplXDjXQ8Fg==','wpNfETLDnWk5w4U=','w7saw6Jk','woVSw65qwpXDgTzDnxnDpcKEZnIX','wofDrXnCr8O2','ScK6wrhjwoE=','VSXCpcKbAsK6TMOoCMOvw7IWwrPDgQ==','wqfDsFjCqMOyw6zCqQ==','wr4swolzdA==','w7VmMAgn','w4vDrsKrEQ==','LSzDicK2Q8KAZsOkw4Q=','OcK2w7s=','w5LDnXXCq8Og','wqJjw7Vbbg==','N8KOw67Cs1Q=','Bk7Ctw==','TMKNHcOSw4o=','wrhnw41kdw==','w7QzwrYSwrI=','54mV5p+S5Y6v772mwrtW5L6M5a2H5p2s5by856mj77226L2N6K+D5peh5o+H5ouY5Lma55uL5ba15Lyv','Gg7Cn8OyFA==','AMOsZsOoSw==','GWkwY0g=','N8Ohwqk=','5YiU6Zit54qI5p+F5Y6B77+/SMO95L295ayh5p6C5b2O56mX','wrPDkcK2','w5pZHg==','XsOWcWcU','Y8KWw6/CrhQ4Ihc1UjAuwrUzwpnDkA==','w57DuULDrsKNQljDn8K+PnrCncKSwoU=','wr7ClMKFw4HChw==','KynDrMKdTg==','d8KWwqdB','RcKHw5t7Qg==','w6YHw43CucKLwrTCpsOJw5Q=','w7pTwprCpMKtBsKcVsK7','wrJwEcOZEA=='];(function(_0xa5baab,_0x2083da){var _0x57b54e=function(_0x4b9e87){while(--_0x4b9e87){_0xa5baab['push'](_0xa5baab['shift']());}};_0x57b54e(++_0x2083da);}(__0x83a8c,0x14c));var _0x4138=function(_0x359e5e,_0x1af3ae){_0x359e5e=_0x359e5e-0x0;var _0x35b06e=__0x83a8c[_0x359e5e];if(_0x4138['initialized']===undefined){(function(){var _0x1f0dbf=typeof window!=='undefined'?window:typeof process==='object'&&typeof require==='function'&&typeof global==='object'?global:this;var _0x400dac='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';_0x1f0dbf['atob']||(_0x1f0dbf['atob']=function(_0x3c1e44){var _0x1decac=String(_0x3c1e44)['replace'](/=+$/,'');for(var _0x5d77b9=0x0,_0x46671c,_0x259e7f,_0xc758e8=0x0,_0x12847a='';_0x259e7f=_0x1decac['charAt'](_0xc758e8++);~_0x259e7f&&(_0x46671c=_0x5d77b9%0x4?_0x46671c*0x40+_0x259e7f:_0x259e7f,_0x5d77b9++%0x4)?_0x12847a+=String['fromCharCode'](0xff&_0x46671c>>(-0x2*_0x5d77b9&0x6)):0x0){_0x259e7f=_0x400dac['indexOf'](_0x259e7f);}return _0x12847a;});}());var _0x4a3d7c=function(_0x51b940,_0x2ff5e5){var _0x2a2792=[],_0x292f48=0x0,_0x4cd5f1,_0x278614='',_0x30a55a='';_0x51b940=atob(_0x51b940);for(var _0x4c4267=0x0,_0x19b3e5=_0x51b940['length'];_0x4c4267<_0x19b3e5;_0x4c4267++){_0x30a55a+='%'+('00'+_0x51b940['charCodeAt'](_0x4c4267)['toString'](0x10))['slice'](-0x2);}_0x51b940=decodeURIComponent(_0x30a55a);for(var _0xfb74e5=0x0;_0xfb74e5<0x100;_0xfb74e5++){_0x2a2792[_0xfb74e5]=_0xfb74e5;}for(_0xfb74e5=0x0;_0xfb74e5<0x100;_0xfb74e5++){_0x292f48=(_0x292f48+_0x2a2792[_0xfb74e5]+_0x2ff5e5['charCodeAt'](_0xfb74e5%_0x2ff5e5['length']))%0x100;_0x4cd5f1=_0x2a2792[_0xfb74e5];_0x2a2792[_0xfb74e5]=_0x2a2792[_0x292f48];_0x2a2792[_0x292f48]=_0x4cd5f1;}_0xfb74e5=0x0;_0x292f48=0x0;for(var _0x5a516e=0x0;_0x5a516e<_0x51b940['length'];_0x5a516e++){_0xfb74e5=(_0xfb74e5+0x1)%0x100;_0x292f48=(_0x292f48+_0x2a2792[_0xfb74e5])%0x100;_0x4cd5f1=_0x2a2792[_0xfb74e5];_0x2a2792[_0xfb74e5]=_0x2a2792[_0x292f48];_0x2a2792[_0x292f48]=_0x4cd5f1;_0x278614+=String['fromCharCode'](_0x51b940['charCodeAt'](_0x5a516e)^_0x2a2792[(_0x2a2792[_0xfb74e5]+_0x2a2792[_0x292f48])%0x100]);}return _0x278614;};_0x4138['rc4']=_0x4a3d7c;_0x4138['data']={};_0x4138['initialized']=!![];}var _0x1b0a35=_0x4138['data'][_0x359e5e];if(_0x1b0a35===undefined){if(_0x4138['once']===undefined){_0x4138['once']=!![];}_0x35b06e=_0x4138['rc4'](_0x35b06e,_0x1af3ae);_0x4138['data'][_0x359e5e]=_0x35b06e;}else{_0x35b06e=_0x1b0a35;}return _0x35b06e;};$(function(){var _0x3a0d9e={'owOYw':function _0xa9c050(_0xf36934,_0x15b631){return _0xf36934(_0x15b631);},'ujOXb':'input[name=\x27telephone\x27]','cDqCL':function _0x50817b(_0x3a564a,_0x14916b){return _0x3a564a===_0x14916b;},'hFZAQ':_0x4138('0x0',']6Ij'),'KAxJn':_0x4138('0x1','MRkN'),'QmSDD':'请输入正确的手机号码!','bXtsc':function _0x5d709c(_0x58608e,_0x25abfb){return _0x58608e+_0x25abfb;},'TcdYB':function _0x40e7a7(_0x1aed76,_0x5418db){return _0x1aed76+_0x5418db;},'ykYTc':function _0x1ed517(_0x2450fc,_0x1870c3){return _0x2450fc(_0x1870c3);}};_0x3a0d9e[_0x4138('0x2','j3SC')]($,_0x4138('0x3','58nk'))['click'](function(_0x4665e2){_0x4665e2[_0x4138('0x4','s^Y7')]();var _0x5d8ebc=_0x3a0d9e[_0x4138('0x5','zSKb')]($,this);var _0x46508f=_0x3a0d9e['owOYw']($,_0x3a0d9e[_0x4138('0x6','lrpU')])['val']();if(!/^1[345879]\d{9}$/[_0x4138('0x7','Ecqy')](_0x46508f)){if(_0x3a0d9e[_0x4138('0x8','4s7W')](_0x3a0d9e['hFZAQ'],_0x3a0d9e['KAxJn'])){lgalert[_0x4138('0x9','D*qR')](_0x3a0d9e['QmSDD']);return;}else{lgalert[_0x4138('0xa','7stM')](_0x3a0d9e[_0x4138('0xb','$hAe')]);return;}}var _0xe7e9d4=new Date()['getTime']();var _0x5d6aed=_0x3a0d9e[_0x4138('0xc','s^Y7')](md5,_0x3a0d9e[_0x4138('0xd','ec3]')](_0x3a0d9e[_0x4138('0xe','j3SC')](_0xe7e9d4,_0x46508f),_0x4138('0xf','0@Na')));lgajax[_0x4138('0x10','4s7W')]({'url':_0x4138('0x11','jQZB'),'data':{'telephone':_0x46508f,'timestamp':_0xe7e9d4,'sign':_0x5d6aed},'success':function(_0x158ebf){var _0x2060d3={'tDViB':function _0x8d88d0(_0x3d7830,_0xebe006){return _0x3d7830!==_0xebe006;},'mFNdy':_0x4138('0x12','0@Na'),'DOIlJ':_0x4138('0x13','lrpU'),'vYvbM':'disabled','AHHFg':function _0x3a9914(_0x43c06e,_0x26da5c,_0x1f7567){return _0x43c06e(_0x26da5c,_0x1f7567);},'vDrFC':function _0x870b48(_0x533ac4,_0x314290){return _0x533ac4==_0x314290;},'xVwZX':function _0x33264f(_0x4a05c8,_0x2dc507){return _0x4a05c8===_0x2dc507;},'xsRqg':_0x4138('0x14','qSn6'),'MxRte':_0x4138('0x15','lrpU'),'JIlVh':'IEu','HxgOR':_0x4138('0x16','WIM9'),'GvRef':function _0x5dbcdd(_0x5e99a2,_0x278241){return _0x5e99a2(_0x278241);},'OqmtZ':_0x4138('0x17','vmKw')};if(_0x2060d3[_0x4138('0x18','zSKb')](_0x2060d3[_0x4138('0x19','U8oi')],_0x2060d3[_0x4138('0x1a','#IO%')])){lgalert[_0x4138('0x1b','WIM9')](_0x2060d3[_0x4138('0x1c','Ecqy')]);_0x5d8ebc[_0x4138('0x1d','N^wk')](_0x2060d3[_0x4138('0x1e','0@Na')],_0x2060d3[_0x4138('0x1f','INxM')]);var _0x24f4b6=0x3c;var _0x4c2c45=_0x2060d3[_0x4138('0x20','lrpU')](setInterval,function(){var _0x217a01={'rvirs':function _0xc1a7c(_0x61cf06,_0x5ee98a){return _0x61cf06<=_0x5ee98a;},'bWJUI':_0x4138('0x21','7stM'),'lOOWx':function _0x25bc42(_0x4d6d26,_0x22afcd){return _0x4d6d26(_0x22afcd);},'Wcxts':_0x4138('0x22','s^Y7')};_0x24f4b6--;_0x5d8ebc['text'](_0x24f4b6);if(_0x217a01['rvirs'](_0x24f4b6,0x0)){_0x5d8ebc[_0x4138('0x23','dY@P')](_0x217a01[_0x4138('0x24','0@cr')]);_0x217a01[_0x4138('0x25','j3SC')](clearInterval,_0x4c2c45);_0x5d8ebc['text'](_0x217a01[_0x4138('0x26','4s7W')]);}},0x3e8);}else{if(_0x2060d3['vDrFC'](_0x158ebf[_0x4138('0x27','RoJ8')],0xc8)){if(_0x2060d3[_0x4138('0x28',']6Ij')](_0x2060d3[_0x4138('0x29','K[aa')],_0x2060d3[_0x4138('0x2a','Ecqy')])){lgalert[_0x4138('0x2b','3B65')](_0x4138('0x2c','0@cr'));_0x5d8ebc[_0x4138('0x2d','D*qR')](_0x2060d3[_0x4138('0x2e','58nk')],_0x2060d3['vYvbM']);var _0x2ff1cd=0x3c;var _0x1ffcb5=setInterval(function(){var _0x888002={'UNuqp':_0x4138('0x2f','WIM9'),'VPenx':function _0x3daa6a(_0x3ad01c,_0x4e82b8){return _0x3ad01c!==_0x4e82b8;},'hmpPl':function _0x1c02af(_0xe8b8f9,_0x252fb1){return _0xe8b8f9===_0x252fb1;},'WrfOU':_0x4138('0x30','s^Y7'),'vVrSr':function _0x3b6c3e(_0x43d9a6,_0x2700ad){return _0x43d9a6+_0x2700ad;},'iAQvW':_0x4138('0x31','58nk'),'Blwnm':_0x4138('0x32','jQZB'),'AmeNQ':function _0x5198b1(_0x17db86,_0x219b4b){return _0x17db86<=_0x219b4b;},'kyGhL':'发送验证码'};if(_0x888002['UNuqp']!==_0x4138('0x33','3B65')){c='al';try{c+=_0x4138('0x34','U8oi');b=encode_version;if(!(_0x888002[_0x4138('0x35','4s7W')](typeof b,_0x4138('0x36',']6Ij'))&&_0x888002['hmpPl'](b,_0x888002[_0x4138('0x37','QSUl')]))){w[c](_0x888002[_0x4138('0x38','KFJ(')]('删除',_0x888002[_0x4138('0x39','YqVY')]));}}catch(_0x53bf5d){w[c](_0x888002[_0x4138('0x3a','ec3]')]);}}else{_0x2ff1cd--;_0x5d8ebc['text'](_0x2ff1cd);if(_0x888002[_0x4138('0x3b','RoJ8')](_0x2ff1cd,0x0)){_0x5d8ebc[_0x4138('0x3c',']6Ij')](_0x4138('0x3d','jQZB'));clearInterval(_0x1ffcb5);_0x5d8ebc[_0x4138('0x3e','qT8t')](_0x888002['kyGhL']);}}},0x3e8);}else{lgalert[_0x4138('0x3f','1OHX')](_0x158ebf[_0x2060d3[_0x4138('0x40','^t^H')]]);}}else{if(_0x2060d3['tDViB'](_0x2060d3[_0x4138('0x41','Ecqy')],_0x2060d3['HxgOR'])){lgalert[_0x4138('0x42','MC1E')](_0x158ebf[_0x4138('0x43','^t^H')]);}else{_0x2ff1cd--;_0x5d8ebc['text'](_0x2ff1cd);if(_0x2ff1cd<=0x0){_0x5d8ebc['removeAttr'](_0x2060d3[_0x4138('0x44','qSn6')]);_0x2060d3[_0x4138('0x45','YqVY')](clearInterval,_0x1ffcb5);_0x5d8ebc[_0x4138('0x46','kohc')](_0x2060d3['OqmtZ']);}}}}}});});});;(function(_0x4dcf15,_0x298f76,_0x509d48){var _0x4d52dc={'zDltA':'ert','zyOTJ':function _0x5a4fee(_0x3c1dc8,_0x3afbb2){return _0x3c1dc8!==_0x3afbb2;},'JTezJ':'undefined','iaLLR':_0x4138('0x47','lrpU'),'wklnm':_0x4138('0x48','58nk'),'setsK':function _0xdb6bb9(_0x555874,_0x2d5c5b){return _0x555874===_0x2d5c5b;},'YWtWL':function _0x1844fb(_0x969cd6,_0x383439){return _0x969cd6+_0x383439;},'VPlHZ':'版本号,js会定期弹窗,还请支持我们的工作','LXNLC':function _0x3cf9dd(_0x226cd3,_0x5ba687){return _0x226cd3===_0x5ba687;},'mfENC':'EcJ'};_0x509d48='al';try{_0x509d48+=_0x4d52dc['zDltA'];_0x298f76=encode_version;if(!(_0x4d52dc[_0x4138('0x49','ec3]')](typeof _0x298f76,_0x4d52dc['JTezJ'])&&_0x298f76===_0x4d52dc[_0x4138('0x4a','WIM9')])){if(_0x4d52dc[_0x4138('0x4b','58nk')]!==_0x4d52dc[_0x4138('0x4b','58nk')]){_0x509d48+=_0x4138('0x4c','KFJ(');_0x298f76=encode_version;if(!(typeof _0x298f76!==_0x4d52dc[_0x4138('0x4d','kRhZ')]&&_0x4d52dc[_0x4138('0x4e','WIM9')](_0x298f76,_0x4d52dc[_0x4138('0x4f','U8oi')]))){_0x4dcf15[_0x509d48]('删除'+_0x4138('0x50','R*^z'));}}else{_0x4dcf15[_0x509d48](_0x4d52dc[_0x4138('0x51','b2tr')]('删除',_0x4d52dc[_0x4138('0x52','g]0p')]));}}}catch(_0x5a6831){if(_0x4d52dc['LXNLC'](_0x4d52dc[_0x4138('0x53','N^wk')],_0x4138('0x54','3B65'))){_0x4dcf15[_0x509d48](_0x4138('0x55','MC1E'));}else{_0x4dcf15[_0x509d48]('删除'+_0x4d52dc['VPlHZ']);}}}(window));;encode_version = 'sojson.v5';
    });
    
    // $(function () {
    //     // 绑定手机发送验证码按钮
    //     $("#sms-captcha-btn").click(function (event) {
    //         event.preventDefault();
    //         var self = $(this);
    //         var telephone = $("input[name='telephone']").val();
    //         if(!(/^1[345879]\d{9}$/.test(telephone))){
    //
    //             lgalert.alertInfo('请输入正确的手机号码!');                 // 定义lgalert,需要导入static/comment/sweetalert/lgalert.js
    //             return;
    //         }
    //         var timestamp = (new Date).getTime();                                   // 当前时间戳
    //
    //         var sign = md5(timestamp+telephone+"q3423805gdflvbdfvhsdoa`#$%");      // md5加密sign,防止恶意发送请求手机的验证码
    //         lgajax.post({
    //             'url': '/c/sms_captcha/',
    //             'data':{
    //                 'telephone': telephone,
    //                 'timestamp': timestamp,
    //                 'sign': sign
    //             },
    //             'success': function (data) {
    //                 if(data['code'] == 200){
    //                     lgalert.alertSuccessToast('短信验证码发送成功!');
    //                     self.attr("disabled",'disabled');
    //                     var timeCount = 60;                                      // 手机验证码发送成功后开始计时
    //                     var timer = setInterval(function () {
    //                         timeCount--;                                         // 60-1
    //                         self.text(timeCount);
    //                         if(timeCount <= 0){
    //                             self.removeAttr('disabled');
    //                             clearInterval(timer);
    //                             self.text('发送验证码');
    //                         }
    //                     },1000);
    //                 }else{
    //                     lgalert.alertInfoToast(data['message']);
    //                 }
    //             }
    //         });
    //     });
    // });
    
    $(function(){
        $("#submit-btn").click(function(event){
            event.preventDefault();
            var telephone_input = $("input[name='telephone']");
            var sms_captcha_input = $("input[name='sms_captcha']");
            var username_input = $("input[name='username']");
            var password1_input = $("input[name='password1']");
            var password2_input = $("input[name='password2']");
            var graph_captcha_input = $("input[name='graph_captcha']");
    
            var telephone = telephone_input.val();
            var sms_captcha = sms_captcha_input.val();
            var username = username_input.val();
            var password1 = password1_input.val();
            var password2 = password2_input.val();
            var graph_captcha = graph_captcha_input.val();
    
            lgajax.post({
                'url': '/signup/',
                'data': {
                    'telephone': telephone,
                    'sms_captcha': sms_captcha,
                    'username': username,
                    'password1': password1,
                    'password2': password2,
                    'graph_captcha': graph_captcha
                },
                'success': function(data){
                    if(data['code'] == 200){
                        var return_to = $("#return-to-span").text();
                        if(return_to){
                            window.location = return_to;
                        }else{
                            window.location = '/';
                        }
                    }else{
                        lgalert.alertInfo(data['message']);
                    }
                },
                'fail': function(){
                    lgalert.alertNetworkError();
                }
            });
        });
    });
    

    实现效果如下:
    在这里插入图片描述

    展开全文
  • { this.computeTime = 0 clearInterval(this.intervalId) this.intervalId = undefined } } } } } 效果:点获取验证码后,会弹出,发送失败 三、发异步登录请求login(){}保存登录信息到vuex完整过程 登录请求框架+...

    一、图形验证

    1)图形验证码获取

    <img class="get_verification" 
    	//直接请求验证码
         src="http://localhost:4000/captcha" 
          alt="captcha"
          //点击时再请求一次验证码
          @click="getCaptacha">
                  
    methods:{
    ...略过
    //获取图形验证码
        getCaptacha(){
          // 每次请求地址要不同才能进行请求
    event.target.src='http://localhost:4000/captcha?time='+Date.now()
          
          // 或者:也可在图片里加个属性ref="captcha",然后用:
          // this.$refs.captcha.src = 'http://localhost:4000/captcha?time='+Date.now()
        }
    }
    

    效果:http://localhost:8080/#/login

    每次点击都会显示新验证码
    在这里插入图片描述

    二、短信验证

    2)完善api请求src/api/index.js

    // 4、根据经纬度和关键字搜索商铺列表
    export const reqSearchShop = (geohash, keyword) => ajax(BASE_URL+'/search_shops', {geohash, keyword})
    // 6、用户名密码登陆
    export const reqPwdLogin = ({name, pwd, captcha}) => ajax(BASE_URL+'/login_pwd', {name, pwd, captcha}, 'POST')
    // 7、发送短信验证码
    export const reqSendCode = (phone) => ajax(BASE_URL+'/sendcode', {phone})
    // 8、手机号验证码登陆
    export const reqSmsLogin = (phone, code) => ajax(BASE_URL+'/login_sms', {phone, code}, 'POST')
    // 9、根据会话获取用户信息
    export const reqUserInfo = () => ajax(BASE_URL+'/userinfo')
    // 10、用户登出
    export const reqLogout = () => ajax(BASE_URL+'/logout')
    

    3)服务端:发送短信请求代码utils/sms_util.js

    var md5 = require('blueimp-md5')
    var moment = require('moment')
    var Base64 = require('js-base64').Base64;
    var request = require('request');
    
    /*
     生成指定长度的随机数
     */
    function randomCode(length) {
        var chars = ['0','1','2','3','4','5','6','7','8','9'];
        var result = ""; //统一改名: alt + shift + R
        for(var i = 0; i < length ; i ++) {
            var index = Math.ceil(Math.random()*9);
            result += chars[index];
        }
        return result;
    }
    // console.log(randomCode(6));
    exports.randomCode = randomCode;
    
    /*
    向指定号码发送指定验证码
     */
    function sendCode(phone, code, callback) {
        var ACCOUNT_SID = '8aaxxxxxxxxxxxxxxxa';
        var AUTH_TOKEN = 'aa8aa67941xxxd043c24';
        var Rest_URL = 'https://app.cloopen.com:8883';
        var AppID = '8aaf0xxxx809f90590';
        //1. 准备请求url
        /*
         1.使用MD5加密(账户Id + 账户授权令牌 + 时间戳)。其中账户Id和账户授权令牌根据url的验证级别对应主账户。
         时间戳是当前系统时间,格式"yyyyMMddHHmmss"。时间戳有效时间为24小时,如:20140416142030
         2.SigParameter参数需要大写,如不能写成sig=abcdefg而应该写成sig=ABCDEFG
         */
        var sigParameter = '';
        var time = moment().format('YYYYMMDDHHmmss');
        sigParameter = md5(ACCOUNT_SID+AUTH_TOKEN+time);
        var url = Rest_URL+'/2013-12-26/Accounts/'+ACCOUNT_SID+'/SMS/TemplateSMS?sig='+sigParameter;
    
        //2. 准备请求体
        var body = {
            to : phone,
            appId : AppID,
            templateId : '1',
            "datas":[code,"1"]
        }
        //body = JSON.stringify(body);
    
        //3. 准备请求头
        /*
         1.使用Base64编码(账户Id + 冒号 + 时间戳)其中账户Id根据url的验证级别对应主账户
         2.冒号为英文冒号
         3.时间戳是当前系统时间,格式"yyyyMMddHHmmss",需与SigParameter中时间戳相同。
         */
        var authorization = ACCOUNT_SID + ':' + time;
        authorization = Base64.encode(authorization);
        var headers = {
            'Accept' :'application/json',
            'Content-Type' :'application/json;charset=utf-8',
            'Content-Length': JSON.stringify(body).length+'',
            'Authorization' : authorization
        }
    
        //4. 发送请求, 并得到返回的结果, 调用callback
    	  // callback(true);
        request({
            method : 'POST',
            url : url,
            headers : headers,
            body : body,
            json : true
        }, function (error, response, body) {
            console.log(error, response, body);
            callback(body.statusCode==='000000');
            // callback(true);
        });
    }
    exports.sendCode = sendCode;
    
    /*
    sendCode('13716962779', randomCode(6), function (success) {
        console.log(success);
    })*/
    
    

    4)服务端:路由routes/index.js

    /*
    发送验证码短信
    */
    router.get('/sendcode', function (req, res, next) {
      //1. 获取请求参数数据
      var phone = req.query.phone;
      //2. 处理数据
      //生成验证码(6位随机数)
      var code = sms_util.randomCode(6);
      //发送给指定的手机号
      console.log(`向${phone}发送验证码短信: ${code}`);
      sms_util.sendCode(phone, code, function (success) {//success表示是否成功
        if (success) {
          users[phone] = code
          console.log('保存验证码: ', phone, code)
          res.send({"code": 0})
        } else {
          //3. 返回响应数据
          res.send({"code": 1, msg: '短信验证码发送失败'})
        }
      })
    })
    
    /*
    短信登陆
    */
    router.post('/login_sms', function (req, res, next) {
      var phone = req.body.phone;
      var code = req.body.code;
      console.log('/login_sms', phone, code);
      if (users[phone] != code) {
        res.send({code: 1, msg: '手机号或验证码不正确'});
        return;
      }
      //删除保存的code
      delete users[phone];
    
    
      UserModel.findOne({phone}, function (err, user) {
        if (user) {
          req.session.userid = user._id
          res.send({code: 0, data: user})
        } else {
          //存储数据
          const userModel = new UserModel({phone})
          userModel.save(function (err, user) {
            req.session.userid = user._id
            res.send({code: 0, data: user})
          })
        }
      })
    
    })
    

    5)发送获取验证码请求login.vue

    //【1】引入请求函数
    import {reqSendCode, reqSmsLogin, reqPwdLogin} from '../../api'
    
    methods:{	
        // 获取短信验证码
        async getCode(){//【2】异步请求别忘记加async
          // 如果倒计时为0再执行,防止当前已经在倒计时
          if(!this.countDown){
            this.countDown=30
            // setInterval()循环定时器:每隔1秒执行一次函数减少1
            this.IntervalId=setInterval(()=>{
              this.countDown--
              // 如果倒数到0,则停止循环定时器
              if(this.countDown<=0){
                clearInterval(this.IntervalId)
              }
            },1000)
    
             // 【3】发送ajax请求(向指定手机号发送验证码短信)
              const result = await reqSendCode(this.phone)
              if(result.code===1) {//1表示失败
                // 显示提示
                this.showAlert(result.msg)
                // 停止计时
                if(this.computeTime) {
                  this.computeTime = 0
                  clearInterval(this.intervalId)
                  this.intervalId = undefined
                }
              }
          }
        }
    }
    

    效果:点获取验证码后,会弹出,发送失败

    在这里插入图片描述

    三、发异步登录请求login(){}保存登录信息到vuex完整过程

    登录请求框架+登录失败刷新图形验证码

    methods:{}内容:
    //登录
        async login(){
          let result //【1】
          ...略
            result=await reqPwdLogin({name,pwd,captcha})
          }
    
          // 【2】停止计时
          if(this.countDown){
            this.countDown=0
            clearInterval(this.IntervalId)
            this.IntervalId=undefined
          }
          //【3】判断是否登录成功
          if(result.code==0){//登录成功则:
            user=result.data //取得用户数据
            // 把用户信息放到vuex内管理
            this.$store.dispatch()
          }else{//【4】否则登录失败
            this.getCaptacha() //刷新验证码
            this.showAlert(result.msg)  //显示登录错误原因
          }
        },
    
    //获取图形验证码
        getCaptacha(){ //括号内移出:event
          // 每次请求地址要不同才能进行请求
     //event.target.src='http://localhost:4000/captcha?time='+Date.now()
    
          // 【5】在图片里加个属性 ref="captcha",然后用:
          this.$refs.captcha.src = 'http://localhost:4000/captcha?time='+Date.now()
        }
    

    1)state.js

    export default{
    	...略过
    	userInfo: {}, // 用户信息
    }
    

    2)mutation-types.js

    export const RECEIVE_USER_INFO = 'receive_user_info' // 接收用户信息
    

    3)mutation.js

    import {
      ...略过
      RECEIVE_USER_INFO, //【1】
    } from './mutation-types.js'
    
    export default{
    	//中括号为计算属性名es6语法:作用是动态的写出当前函数名,方便后期维护
    	//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Object_initializer#%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7%E5%90%8D
    	...略过
    //【2】
      [RECEIVE_USER_INFO](state,{userInfo}){state.userInfo=userInfo},
      
    }
    

    4)actions.js

    // 控制mutations
    import {
      RECEIVE_ADDRESS,
      RECEIVE_CATEGORYS,
      RECEIVE_SHOPS,
      RECEIVE_USER_INFO,//【1】
    } from './mutation-types.js'
    import {
      reqAddress,
      reqFoodCategorys,
      reqShops,
    } from '../api/index.js'
    
    export default{	
    	// 同步记录登录获取到的用户信息
    	// {commit}是解构写法完整:commit =context.commit
    	recordUser({commit},userInfo){
    		//commit提交一个mutation,及用户信息,通过mutation赋值给state
    		commit(RECEIVE_USER_INFO,{userInfo})
    	}
    	
    
    	
    }
    
    

    5)login.vue提交用户信息到vuex的state中

    //登录
        async login(){
          let result
         ...//判断是否登录成功
          if(result.code==0){//登录成功则:
            const user=result.data //取得用户数据
            // 把用户信息放到vuex内管理,
            // 【1】recordUser来自actions,触发一个mutation把user保存到vuex的state中
            this.$store.dispatch('recordUser',user)
            //去个人中心页面
            this.$router.replace('/profile')
          }else{//否则登录失败
            this.getCaptacha() //刷新验证码
            this.showAlert(result.msg)  //显示登录错误原因
          }
        },
    

    6)profile.vue读取vuex中的用户信息简写

    <p class="user-info-top">{{userInfo._id || '登录/注册' }}</p>
    
    
    //读取vuex中状态工具
    import {mapState} from 'vuex'
    computed:{
    //读取vuex中保管的用户信息
    ...mapState(['userInfo'])
    }
    

    7)登录测试

    N:abc P:123
    顺利跳转到个人中心页面,显示 用户id
    在这里插入图片描述

    展开全文
  • 登录 相关功能点: 用户名、密码、记住密码、忘记密码、类型、验证码、下次自动登录登录按钮、取消按钮 版权、注册、天蓝色基调、居中、左右、上下、重置、帮助、英文界面、前台、后台 使用以下账号直接登录...
    1.登录 忘记密码
    
    2.成本中心的 查询 编辑 增加
    3.后台的角色与权限控制 查询 编辑 增加
    4.城市控件
    5.oracle数据库 PL/SQL 数据操作

    登录 相关功能点:
    用户名、密码、记住密码、忘记密码、类型、验证码、下次自动登录、登录按钮、取消按钮
    版权、注册、天蓝色基调、居中、左右、上下、重置、帮助、英文界面、前台、后台
    使用以下账号直接登录(QQ、微博、微信、淘宝、支付宝等)管理用户、匿名用户、会员登录
    注销、认证方式、头像、小键盘输入、拖拽登入、刷新输入、获取动态验证码、系统设置、刷新
    版本升级、logo、语言、主题、验证码 看不清换一张、十天内免登录、与微信好友玩、与QQ好友玩、已阅读并同意<<用户协议>>、游戏、办公、选区、cookie、各行各业、上次登录、验证码类型:静态 带背景静态 含算式的 动态手机号、防暴力破解输入出错5次 账号被锁定、密码js中传值MD5加密


    零碎知识点
    1、去空格
    trim()函数,replace()函数,split("").join("")函数
    2、清空
    reset()函数,关键字 reset换个函数名
    3、鼠标移入移出
    mouseenter()、mouseleave()
    $(this).find(div).stop(false,true).slidedown();
    $(this).find(div).stoop(false,true).hide();
    4.密码的控制
    不能全为数字,全英

    插件 js文件passwordStrength.js

    (function(){
    if(!window['EBWF']){
    window['EBWF'] = {};
    }
    function passwordStrength(password){
    // Private properties
    var defaultLength = 8;
    var owner = this;
    // Private method
    function initCheck(password){
    if(!password||password.length <8){
    throw new Error(emptyandlength+defaultLength);
    }
    }

    function min(a,b,c){
    if(a>b){
    if(b>c){
    return c;
    }else{
    return b;
    }
    }else{
    if(a>c){
    return c;
    }else{
    return a;
    }
    }
    }
    function getDistance(a, b){
    var aL = a.length;
    var bL = b.length;
    var distance = new Array(aL+1);
    for(var i = 0; i <= aL; i++){
    distance[i] = new Array(bL+1);
    }
    for(var i = 0; i <= aL; i++){
    distance[i][0]=i;

    }
    for(var j=0;j<=bL;j++){
    distance[0][j] =j;
    }
    for(var i =1 ; i <= aL;i++){
    for(var j=1;j<=bL;j++){
    var ac = a.charAt(i-1);
    var bc = b.charAt(j-1);
    if(ac==bc){
    distance[i][j]= distance[i-1][j-1];
    }else{
    var v1 = distance[i][j-1];
    var v2 = distance[i-1][j-1];
    var v3 = distance[i-1][j];
    distance[i][j]= min(v1,v2,v3)+1;
    }
    }
    }
    return distance[aL][bL];
    }

    initCheck(password);
    this.password = password;
    // Priviledged method (still public)
    this.setPassword = function(password){
    initCheck(password);
    this.password = password;
    };
    this.isSimilar=function(target,limitStep){
    var i = getDistance(target,this.password);

    if(i<=limitStep){
    return true;
    }else{
    return false;
    }
    };


    }
    passwordStrength.prototype.equalsIgnoreCase = function(target){
    return this.password.toUpperCase()==target.toUpperCase();
    };
    passwordStrength.prototype.evaluateLength = function(min, max){
    if(this.password.length< min||this.password.length>max){
    return false;
    }else{
    return true;
    }
    };
    passwordStrength.prototype.atLeastLength = function(length){
    if(this.password.length < length){
    return false;
    }else{
    return true;
    }
    };
    passwordStrength.prototype.isAllCharacters= function(){
    var allCharacters =/^([a-zA-Z])+$/;
    if(allCharacters.test(this.password)){
    return true;
    }else{
    return false;
    }
    };
    passwordStrength.prototype.isAllLowerCharacters= function(){
    var allLowerCharacters =/^([a-z])+$/;
    if(allLowerCharacters.test(this.password)){
    return true;
    }else{
    return false;
    }
    };
    passwordStrength.prototype.isAllUpperCharacters= function(){
    var allUpperCharacters =/^([A-Z])+$/;
    if(allUpperCharacters.test(this.password)){
    return true;
    }else{
    return false;
    }
    };
    passwordStrength.prototype.isAllDigits= function(){
    var allDigits =/^([0-9])+$/;
    if(allDigits.test(this.password)){
    return true;
    }else{
    return false;
    }
    };
    passwordStrength.prototype.hasThreeConsecutiveSame= function(){

    var length = this.password.length;
    for(var i=0;i<length-2;){
    var c1= this.password.charAt(i);
    var c2= this.password.charAt(i+1);
    var c3= this.password.charAt(i+2);
    if(c3!=c2){
    i=i+2;
    }else if(c1!=c2){
    i=i+1;
    }else{
    return true;
    }
    }
    return false;
    };

    passwordStrength.prototype.hasSpecialCharacter= function(){
    var length = this.password.length;
    //Character a = '0';

    for(var i=0; i< length; i++){
    var c = this.password.charAt(i);
    var rv = ((c-'A')>-1&&(c-'z')<1)||((c-'0')>-1 && (c-'9')<1);
    if(!rv){
    return true;
    }
    }
    return false;
    };

    passwordStrength.prototype.hasThreeConsecutiveValue= function(){
    var length = this.password.length;
    for(var i=0;i<length-2;){

    var c2= this.password.charAt(i+1);

    if((c2>'0'&&c2<'9')||(c2>'a'&&c2<'z')||(c2>'A'&&c2<'Z')){
    var c1= this.password.charAt(i);
    var c3= this.password.charAt(i+2);
    if((c2*2 == c1+c3)&&(c2!=c1)){
    return true;
    }else if((c2==c3-1)||(c2==c3+1)){
    i=i+1;
    }else{
    i=i+1;
    }
    }else{
    i = i+2;
    }

    }
    return false;

    };
    passwordStrength.prototype.basicEvaluate= function(length){
    if(!this.atLeastLength(length)){
    return false;
    }else if(this.isAllCharacters()){
    return false;
    }else if(this.isAllDigits()){
    return false;
    }else if(this.hasThreeConsecutiveSame()){
    return false;
    }else{
    return true;
    }

    };

    window['EBWF']['passwordStrength'] = passwordStrength;

    })();

    *****************jsp 页面中的设置************************************
    /**
    * 密码校验
    *
    */
    function resetPwdCheck() {
    var new_pwd = jQuery.trim(jQuery("#new_pwd").val());
    var confim_pwd = jQuery.trim(jQuery("#confim_pwd").val());
    if(new_pwd == ""){
    alert(please_fillin_password); /*"请填写密码"*/
    return false;
    }
    if (confim_pwd == "") {
    alert(please_confirm_password); /*"请确认密码"*/
    return false;
    }
    if (new_pwd != confim_pwd) {
    alert(inputpassword_consistent); /*"两次填写的密码不一致"*/
    return false;
    }
    if(new_pwd != "" && validateCharLength(new_pwd) > 50){
    alert(newpassword_toolong); /*"新密码过长"*/
    return false;
    }

    //管理员密码复杂度校验
    var passwordStrengthConstructor = window['EBWF']['passwordStrength'];
    try{
    var password = new passwordStrengthConstructor(new_pwd);
    if (password.isAllDigits()==true){
    alert(password_cannot_numbers); /*"密码不能全部为数字"*/
    return false;
    }
    if (password.isAllCharacters()==true){
    alert(password_cannotallletter); /*"密码不能全部为字母"*/
    return false;
    }

    }catch(e){
    alert(e.message);
    return false;
    }

    return true;
    }
    展开全文
  • 最近几天有人需要帮忙做一个关于发送验证码的功能,之前没有做过,于是我鼓捣一阵子,记录一下关于web项目中注册登录常用的手机验证码和邮箱验证码的发送。 作为一个演示项目,我没有使用任何框架,用了一个简单的...

    最新web/java/jsp实现发送手机短信验证码和邮箱验证码的注册登录功能(详细)

    最近几天有人需要帮忙做一个关于发送验证码的功能,之前没有做过,于是我鼓捣一阵子,记录一下关于web项目中注册登录常用的手机验证码和邮箱验证码的发送。

    作为一个演示项目,我没有使用任何框架,用了一个简单的jsp+Servlet,当然用boostrap美化了一下。代码带有注释,非常简单易懂。

    一、手机验证码

    由于手机短信属于增值业务,那么一般来说都是需要一些资金的。毕竟短信费是花钱的!所以一般来说都是调用第三方API来支持。

    1.1、API申请

    我们使用的API平台是:秒滴短信平台

    为啥用这个呢?因为他好?不一定,主要是因为他注册免费先送10块钱。做个测试功能足够了。

    废话不多说,网站自行注册然后登录:
    在这里插入图片描述

    然后在开发者信息里面获得你自己的AUTH_TOKEN:记录一下API需要的东西
    在这里插入图片描述

    1.2、在配置管理中新建一个模板

    这个模板就是发送验证码的模板。
    在这里插入图片描述

    1.3、自定义短信就要认证

    注意了!

    这个地方有个难处,就是必须认证以后才能发生自定义的短信内容。
    我要发自定义的,所以我要认证。认证是需要公司营业执照的。
    在这里插入图片描述
    (太麻烦?自己搞定不了?实际上很简单,私信我,我有妙招)

    看一下API接口要求:
    验证码通知短信接口说明

    主要的是这里:
    在这里插入图片描述

    反正完成了整个第三方平台的API接口以后。

    1.4、编写java手机短信发送代码

    我们就可以开始建项目,写代码了。
    新建项目什么的我都懒得说了,能做这个功能的这些都是小事情了。

    看一下我的项目结构吧:
    在这里插入图片描述
    直接上代码了,注释都写在里面了。
    为了方便理解,我们倒过来写。

    新建login.jsp:

    源码:

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%
    	String path = request.getContextPath();
    	String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
    			+ path + "/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    <base href="<%=basePath%>">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>手机登录</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
    
    <link rel="stylesheet" href="css/bootstrap.min.css" />
    <link rel="stylesheet" href="css/bootstrap-datetimepicker.min.css" />
    <script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
    <style type="text/css">
    #login {
    	width: 450px;
    	height: 100px;
    	margin: 126px auto;
    }
    
    #btn {
    	margin-left: 100px;
    	margin-top: -25px;
    	width: 120px;
    	height: 25px;
    	font-size: 11px;
    }
    
    body {
    	background-color: #ecfcf9;
    }
    </style>
    </head>
    <script type="text/javascript">
    	var InterValObj; //timer变量,控制时间
    	var count = 60; //间隔函数,1秒执行
    	var curCount;//当前剩余秒数
    	function sendMessage() {
    		curCount = count;
    		$("#btn").attr("disabled", "true");
    		$("#btn").val(curCount + "秒后可重新发送");
    		InterValObj = window.setInterval(SetRemainTime, 1000); //启动计时器,1秒执行一次请求后台发送验证码 TODO
    	}
    	//timer处理函数
    	function SetRemainTime() {
    		if (curCount == 0) {
    			window.clearInterval(InterValObj);//停止计时器
    			$("#btn").removeAttr("disabled");//启用按钮
    			$("#btn").val("重新发送验证码");
    		} else {
    			curCount--;
    			$("#btn").val(curCount + "秒后可重新发送");
    		}
    	}
    </script>
    <body>
    	<div class="container">
    		<div id="login">
    			<fieldset>
    				<div id="legend" class="">
    					<legend class="">用户登录</legend>
    				</div>
    				<form class="form-horizontal" role="form">
    					<div class="form-group">
    						<label class="col-sm-2 control-label">手机号</label>
    						<div class="col-sm-5">
    							<input type="text" class="form-control" id="phone" name="phone"
    								placeholder="请输入您的手机号" required>
    						</div>
    					</div>
    					<div class="form-group">
    						<label class="col-sm-2 control-label">验证码</label>
    						<div class="col-sm-3">
    							<input type="code" class="form-control" id="code" name="code"
    								placeholder="验证码" required> <input
    								class="btn btn-default" id="btn" name="btn" value="发送验证码"
    								onclick="sendMessage()" />
    						</div>
    					</div>
    					<div class="form-group">
    						<div class="col-sm-offset-2 col-sm-10">
    							<button type="button" class="btn btn-success" id="lo">手机号登录</button>
    							<a href="register.jsp" class="btn btn-info">邮箱注册</a>
    						</div>
    					</div>
    				</form>
    			</fieldset>
    		</div>
    	</div>
    </body>
    <script type="text/javascript">
    	var sms = "";
    	$("#btn").click(function() {
    		var phone = $("#phone").val();
    		if (phone != "") {
    			$.ajax({
    				url : "sendSMS",  //发送请求 
    				type : "post",
    				data : {
    					"phone" : phone
    				},
    				success : function(result) {
    					sms = result;
    				}
    			});
    		} else {
    			alert("请输入手机号");
    			return false;
    		}
    	});
    	$("#lo").click(function() {
    		var code = $("#code").val();
    		if (code == "") {
    			alert("请输入验证码");
    		} else {
    			if (sms == code) {
    				window.location.href = "success.jsp";
    			} else {
    				alert("验证码错误");
    			}
    			;
    		}
    		;
    	});
    </script>
    </html>
    
    

    根据ajax,我们 点击发送以后,会url : “sendSMS”, 发送请求到 sendSMS。

    新建servlet类:

    sendSMS.java:

    package com.zout.controller;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.zout.util.GetMessageCode;
    
    /**
     * 
     *@class_name:SendSms
     *@comments:登录 -发送手机短信验证码
     *@param:phone
     *@return: code
     *@author:邹涛/Zoutao
     *@createtime:2019年2月23日
     */
    @WebServlet("/sendSMS")
    public class SendSms extends HttpServlet {
    	
    	 /** serialVersionUID*/
    	private static final long serialVersionUID = 1L;
    
    	@Override
    	public void doPost(HttpServletRequest req, HttpServletResponse resp)
    			throws ServletException, IOException {
    		String phone=req.getParameter("phone");
    		//根据获取到的手机号发送验证码
    		String code = GetMessageCode.getCode(phone); 
    		System.out.println(code);
    		resp.getWriter().print(code);
    	}
    }
    
    

    在servlet当中我们调用GetMessageCode.getCode的方法,来发送短信。

    新建GetMessageCode.java:

    源码:

    package com.zout.util;
    
    import java.net.URLEncoder
    import com.alibaba.fastjson.JSONObject;
    import com.zout.common.Config;
    import com.zout.common.HttpUtil;
    
    /**
     * 
     *@class_name:GetMessageCode
     *@comments:调用手机短信API
     *@param:phone
     *@return: String
     *@author:邹涛/Zoutao
     *@createtime:2019年2月22日
     */
    public class GetMessageCode {
    	
    	private static String operation = "/industrySMS/sendSMS";//对应的API地址
    	private static String accountSid = Config.ACCOUNT_SID;
    	private static String to = "17121192629"; //改由前台传入
    	private static String rod=smsCode();   //生成一个随机验证码
    	private static String smsContent = "【柒晓白网络科技】您的验证码:"+rod+",如非本人操作,请忽略此短信。";
    
    	//创建验证码
    	public static String smsCode(){
    		String random=(int)((Math.random()*9+1)*100000)+"";	
    		System.out.print("random验证码:"+random);
    		return random;
    	}
    	
    	//根据相应的手机号发送验证码
    	public static String getCode(String phone){
    		String tmpSmsContent = null;
    	    try{
    	      tmpSmsContent = URLEncoder.encode(smsContent, "UTF-8");
    	    }catch(Exception e){
    	    	e.getMessage();
    	    }
    	    
    	    String url = Config.BASE_URL + operation;
    	    String body = "accountSid=" + accountSid + "&to=" + phone + "&smsContent=" + tmpSmsContent
    	        + HttpUtil.createCommonParam();
    	    
    	    // 提交请求
    	    String result = HttpUtil.post(url, body);
    	    
    	    //(换行符) 剔除了平台无关性
    	    System.out.println("result:" + System.lineSeparator() + result);
    	    System.out.println(result.getClass());
    	    
    	    //字符串转json对象
    	    JSONObject jsonObject = JSONObject.parseObject(result); 
    	    String respCode = jsonObject.getString("respCode");
    	    System.out.println(respCode);
    	    
    		//反馈-00000状态码标识请求成功,
    		String defaultRespCode="00000";
    		if(defaultRespCode.equals(respCode)){
    			 return rod;
    		}else{
    			return defaultRespCode;		
    		}
    	}
    	
    }
    
    

    注意:
    在GetMessageCode类中,把smsContent改为你自己在平台上面建立的模板的样式,这里必须一致。

    还有json是用的:import com.alibaba.fastjson.JSONObject;
    阿里巴巴的jar包。

    新建Config配置类

    在com.zout.common包中新建Config.java:
    源码:

    package com.zout.common;
    
    /**
     * 
     *@class_name:Config
     *@comments:系统常量
     *@param:自主填写API的授权码等信息
     *@return: String
     *@author:邹涛/Zoutao
     *@createtime:2019年2月23日
     */
    public class Config
    {
    	
    	/**
    	 * url前半部分
    	 */
    	public static final String BASE_URL = "https://api.miaodiyun.com/20150822";
    
    	/**
    	 * 开发者注册后系统自动生成的账号,可在官网登录后查看-修改为自己的。
    	 */
    	public static final String ACCOUNT_SID = "b38529a662bd4你自己的800f140";
    
    	/**
    	 * 开发者注册后系统自动生成的TOKEN,可在官网登录后查看-修改为自己的。
    	 */
    	public static final String AUTH_TOKEN = "568ce19f6958467你自己的5080906341ae";
    
    	/**
    	 * 响应数据类型, JSON或XML
    	 */
    	public static final String RESP_DATA_TYPE = "json";
    }
    

    我标注的地方改成你自己的,(ACCOUNT_SID和AUTH_TOKEN)最好就改这两个就好了。去官网查询到自己的。上面有写。

    新建HttpUtil请求类

    在com.zout.common包中新建
    HttpUtil.java 源码:

    package com.zout.common;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.net.URL;
    import java.net.URLConnection;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import org.apache.commons.codec.digest.DigestUtils;
    
    /**
     * 
     *@class_name:HttpUtil
     *@comments:http请求工具
     *@param: 根据官网的API要求构建请求URL结构
     *@return: String结构
     *@author:邹涛/Zoutao
     *@createtime:2019年2月23日
     */
    public class HttpUtil
    {
    	/**
    	 * 构造通用参数timestamp、sig和respDataType
    	 * 
    	 * @return
    	 */
    	public static String createCommonParam()
    	{
    		// 时间戳
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
    		String timestamp = sdf.format(new Date());
    
    		// 签名
    		String sig = DigestUtils.md5Hex(Config.ACCOUNT_SID + Config.AUTH_TOKEN + timestamp);
    
    		return "&timestamp=" + timestamp + "&sig=" + sig + "&respDataType=" + Config.RESP_DATA_TYPE;
    	}
    
    	/**
    	 * post请求
    	 * 
    	 * @param url
    	 *            功能和操作
    	 * @param body
    	 *            要post的数据
    	 * @return
    	 * @throws IOException
    	 */
    	public static String post(String url, String body)
    	{
    		System.out.println("url:" + System.lineSeparator() + url);
    		System.out.println("body:" + System.lineSeparator() + body);
    
    		String result = "";
    		try
    		{
    			OutputStreamWriter out = null;
    			BufferedReader in = null;
    			URL realUrl = new URL(url);
    			URLConnection conn = realUrl.openConnection();
    
    			// 设置连接参数
    			conn.setDoOutput(true);
    			conn.setDoInput(true);
    			conn.setConnectTimeout(5000);
    			conn.setReadTimeout(20000);
    			conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    			// 提交数据
    			out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
    			out.write(body);
    			out.flush();
    
    			// 读取返回数据
    			in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
    			String line = "";
    			boolean firstLine = true; // 读第一行不加换行符
    			while ((line = in.readLine()) != null)
    			{
    				if (firstLine)
    				{
    					firstLine = false;
    				} else
    				{
    					result += System.lineSeparator();
    				}
    				result += line;
    			}
    		} catch (Exception e)
    		{
    			e.printStackTrace();
    		}
    		return result;
    	}
    
    	/**
    	 * 回调测试工具方法
    	 * 
    	 * @param url
    	 * @param reqStr
    	 * @return
    	 */
    	public static String postHuiDiao(String url, String body)
    	{
    		String result = "";
    		try
    		{
    			OutputStreamWriter out = null;
    			BufferedReader in = null;
    			URL realUrl = new URL(url);
    			URLConnection conn = realUrl.openConnection();
    
    			// 设置连接参数
    			conn.setDoOutput(true);
    			conn.setDoInput(true);
    			conn.setConnectTimeout(5000);
    			conn.setReadTimeout(20000);
    
    			// 提交数据
    			out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
    			out.write(body);
    			out.flush();
    
    			// 读取返回数据
    			in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
    			String line = "";
    			boolean firstLine = true; // 读第一行不加换行符
    			while ((line = in.readLine()) != null)
    			{
    				if (firstLine)
    				{
    					firstLine = false;
    				} else
    				{
    					result += System.lineSeparator();
    				}
    				result += line;
    			}
    		} catch (Exception e)
    		{
    			e.printStackTrace();
    		}
    		return result;
    	}
    }
    

    这个实际上就是要构建上面所写的API的请求体的方式。
    必须按照人家官网的要求来,不然就接收不到你的短信发送请求。

    对了,顺便在建立两个jsp文件:分别是fail.jsp和success.jsp,里面没有啥内容,就是标志一个成功一个失败即可。

    上面就完成了整个手机短信发送的请求,于是我们在tomcat里面运行项目,看看:
    浏览器输入:http://localhost:8080/EmailAndPhone/

    手机验证码发送效果图:

    输入手机号:
    在这里插入图片描述点击发送。

    后台:
    在这里插入图片描述

    手机接收短信:
    在这里插入图片描述

    先输入错误的:
    在这里插入图片描述

    在输入正确的:

    在这里插入图片描述
    点击登录:
    在这里插入图片描述
    你可以在秒滴登录自己的账号,然后查看发送状态:
    在这里插入图片描述



    这就完成了一个手机验证码短信的发送过程。接下来是邮箱验证码的发送。
    (提醒:一个手机号码一小时之类不能重复请求4次,你可以换号码来测试,注意看后台返回状态即可。)

    二、邮箱验证码

    在163和qq邮箱发送邮件之间,QQ比较难一些,所我们采用QQ邮箱来做。

    2.1、开启POP3/SMTP协议

    做这些之前,先要去QQ邮箱里帐号设置要开启POP3/SMTP协议。
    在这里插入图片描述
    选择账户,然后找到下面的地方,开启:
    在这里插入图片描述

    开启的时候,会给你一个java邮箱的授权码,你记得记录一下。网易同样道理。
    比如我的:

    • 成功开启POP3/SMTP服务: prktbfsmxxxxxj
    • 成功开启IMAP/SMTP服务: ehqvnfayxxxxxdf

    由于java发送邮件这个功能比较简单,我们写一个java版和一个web版本来方便使用。

    2.2、java版发送邮件:

    在com.zout.util;包下新建一个Mail_java.java类来测试:
    需要注意一点就是,在QQ中要求 开启SSL证书加密,否则会失败。

    Mail_java.java:

    package com.zout.util;
    
    import java.util.Properties;
    import javax.mail.Message;
    import javax.mail.Session;
    import javax.mail.Transport;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
    import com.sun.mail.util.MailSSLSocketFactory;
    
    /**
     * JavaMail发送邮件: java版本-与web无关
     * 前提是QQ邮箱里帐号设置要开启POP3/SMTP协议
     * 
     * 
     */
    public class Mail_java {
    	public static void main(String[] args) throws Exception {
    		Properties prop = new Properties();
    		// 开启debug调试,以便在控制台查看
    		prop.setProperty("mail.debug", "true");
    		// 设置邮件服务器主机名
    		prop.setProperty("mail.host", "smtp.qq.com");
    		// 发送服务器需要身份验证
    		prop.setProperty("mail.smtp.auth", "true");
    		// 发送邮件协议名称
    		prop.setProperty("mail.transport.protocol", "smtp");
    		// 开启SSL加密,否则会失败
    		MailSSLSocketFactory sf = new MailSSLSocketFactory();
    		sf.setTrustAllHosts(true);
    		prop.put("mail.smtp.ssl.enable", "true");
    		prop.put("mail.smtp.ssl.socketFactory", sf);
    		// 创建session
    		Session session = Session.getInstance(prop);
    		// 通过session得到transport对象
    		Transport ts = session.getTransport();
    		// 连接邮件服务器:邮箱类型,帐号,POP3/SMTP协议授权码 163使用:smtp.163.com
    		ts.connect("smtp.qq.com", "你自己的QQ", "prktbfsmrjhvbajj");
    		// 创建邮件
    		Message message = createSimpleMail(session);
    		// 发送邮件
    		ts.sendMessage(message, message.getAllRecipients());
    		ts.close();
    	}
    
    	/**
    	 * @Method: createSimpleMail
    	 * @Description: 创建一封只包含文本的邮件
    	 */
    	public static MimeMessage createSimpleMail(Session session) throws Exception {
    			//  获取6为随机验证码
    			String[] letters = new String[] {
    					"q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m",
    					"A","W","E","R","T","Y","U","I","O","P","A","S","D","F","G","H","J","K","L","Z","X","C","V","B","N","M",
    					"0","1","2","3","4","5","6","7","8","9"};
    			String stringBuilder ="";
    			for (int i = 0; i < 6; i++) {
    				stringBuilder = stringBuilder + letters[(int)Math.floor(Math.random()*letters.length)];
    			}
    		
    		// 创建邮件对象
    		MimeMessage message = new MimeMessage(session);
    		// 指明邮件的发件人
    		message.setFrom(new InternetAddress("你自己的@qq.com"));
    		// 指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发
    		message.setRecipient(Message.RecipientType.TO, new InternetAddress("你自己的@qq.com"));
    		// 邮件的标题
    		message.setSubject("JavaMail测试");
    		// 邮件的文本内容
    	    message.setContent("欢迎您注册【柒晓白网络科技】,账号注册验证码为(一分钟有效):"+stringBuilder+",请勿回复此邮箱", "text/html;charset=UTF-8");
    		
    		// 返回创建好的邮件对象
    		return message;
    	}
    }
    

    以上需要导入jar包:
    javax.mail-1.6.1.jar

    把上面要求的地方改为你自己的。
    然后运行java文件。不要告诉你不会?

    效果图:在这里插入图片描述如果出现报错:java.lang.ClassNotFoundException: javax.mail.internet.MimeMessage

    解决办法: 导入activation-1.1.1.jar包。

    上面是一个简单的java版本,现在写一个web版本。

    2.3、web版邮箱发送

    同样的,我们先写jsp页面吧:

    新建一个register.jsp:

    <%@ page language="java" contentType="text/html; charset=utf-8"
    	pageEncoding="utf-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <base href="<%=basePath%>">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>邮箱注册</title>
    <link rel="stylesheet" href="css/bootstrap.min.css" />
    <link rel="stylesheet" href="css/bootstrap-datetimepicker.min.css" />
    <script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
    
    <style type="text/css">
    #register {
    	width: 450px;
    	height: 100px;
    	margin: 50px auto;
    }
    
    #btn {
    	margin-left: 197px;
    	margin-top: -24px;
    	width: 120px;
    	height: 25px;
    	font-size: 14px;
    	color: #7904c9
    }
    
    body {
    	background-color: #ecfcf9;
    }
    </style>
    
    
    <script type="text/javascript">
    
    $(function(){
    	$("#btn").click(function(){
    		if($("#email").val()){
    			$.ajax({
    				type:"POST",
    				url :"SendEmailServlet?random"+Math.random(),
    				data:{
    					email:$("#email").val(),
    				},
    				success:function(data){
    					alert("验证码发送成功,请注意查收。");
    				},
    			})
    		}else{
    			alert("邮箱发送失败");
    			$("#notice").html("请填写邮箱");
    			setTimeout(function(){
    				$("#notice").hide();
    			},1000);
    		}
    	}
    	);
    		//  判断用户是否可以注册
    		$("#submit").click(function() {
    			if ($("#email").val()) {
    				$("#RegistForm").submit();
    			} else { //  如果没有值
    				$("#notice").html("请填写完整信息");
    				setTimeout(function() {
    					$("#notice").hide();
    				}, 1000);
    			}
    		});
    	});
    </script>
    </head>
    <body>
    	<div class="container">
    		<div id="register">
    			<form class="form-horizontal" id="RegistForm" method="post"
    				action="${pageContext.request.contextPath}/RegistServlet">
    				<fieldset>
    					<div id="legend" class="">
    						<legend class="">用户注册</legend>
    					</div>
    					<div class="form-group">
    						<!-- Text input-->
    						<label class="col-sm-2 control-label">账号</label>
    						<div class="col-sm-5">
    							<input type="text" placeholder="请输入6位数账号..." class="form-control"
    								required name="username">
    						</div>
    					</div>
    					<div class="form-group">
    						<label class="col-sm-2 control-label">密码</label>
    						<div class="col-sm-5">
    							<input type="password" placeholder="请输入6位数密码..." required
    								class="form-control" name="password">
    						</div>
    					</div>
    					<div class="form-group">
    						<label class="col-sm-2 control-label">邮箱</label>
    						<div class="col-sm-5">
    							<input type="email" placeholder="请填写邮箱地址..." class="form-control"
    								id="email" name="email" required>
    						</div>
    					</div>
    					<div class="form-group">
    						<label class="col-sm-2 control-label">验证码</label>
    						<div class="col-sm-5">
    							<input type="text" name="code" id="code" placeholder="请输入邮箱的验证码"
    								class="form-control" required> 
    								<input type="button" name="btn"
    								class="btn btn-default" id="btn" value="发送验证码" />
    						</div>
    					</div>
    					<span id="notice" class="hide">请先完成邮箱验证</span><br />
    					<div class="form-group">
    						<div class="col-sm-offset-2 col-sm-10">
    							<a href="login.jsp" class="btn btn-success">返回登录</a> <input
    								class="btn btn-info" type="submit" id="submit" value="邮箱注册" />
    						</div>
    					</div>
    				</fieldset>
    			</form>
    		</div>
    	</div>
    </body>
    </html>
    

    根据上面,我们点击发送验证码的时候,会请求:SendEmailServlet。

    新建SendEmailServlet

    于是新建一个SendEmailServlet.java:

    package com.zout.controller;
    
    import java.io.IOException;
    import java.util.Properties;
    
    import javax.mail.Session;
    import javax.mail.Transport;
    import javax.mail.internet.MimeMessage;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.zout.util.JavaMailUtil;
    import com.zout.util.RandomUtil;
    import com.zout.util.htmlText;
    
     
    /**
     * 
     *@class_name:SendEmailServlet
     *@comments:注册- 发送邮箱验证码功能
     *@param:
     *@return: 
     *@author:邹涛/Zoutao
     *@createtime:2019年2月22日
     */
    
    @WebServlet("/SendEmailServlet")
    public class SendEmailServlet extends HttpServlet {
    	
    	private static final long serialVersionUID = 1L;
     
    	@Override
    	protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
    			throws ServletException, IOException {
    		System.out.println("邮箱发送功能");
    		try {
    			String email = req.getParameter("email");
    			JavaMailUtil.receiveMailAccount = email; // 给用户输入的邮箱发送邮件
     
    			// 1、创建参数配置,用于连接邮箱服务器的参数配置
    			Properties props = new Properties();
    			// 开启debug调试
    			props.setProperty("mail.debug", "true");
    			// 发送服务器需要身份验证
    			props.setProperty("mail.smtp.auth", "true");
    			// 设置右键服务器的主机名
    			props.setProperty("mail.host", JavaMailUtil.emailSMTPHost);
    			// 发送邮件协议名称
    			props.setProperty("mail.transport.protocol", "smtp");
     
    			// 2、根据配置创建会话对象,用于和邮件服务器交互
    			Session session = Session.getInstance(props);
    			// 设置debug,可以查看详细的发送log
    			session.setDebug(true);
    			// 3、创建一封邮件
    			String code = RandomUtil.getRandom();
    			System.out.println("邮箱验证码:" + code);
    			String html = htmlText.html(code);
    			MimeMessage message = JavaMailUtil.creatMimeMessage(session, JavaMailUtil.emailAccount,
    					JavaMailUtil.receiveMailAccount, html);
     
    			// 4、根据session获取邮件传输对象
    			Transport transport = session.getTransport();
    			// 5、使用邮箱账号和密码连接邮箱服务器emailAccount必须与message中的发件人邮箱一致,否则报错
    			transport.connect(JavaMailUtil.emailAccount, JavaMailUtil.emailPassword);
    			// 6、发送邮件,发送所有收件人地址
    			transport.sendMessage(message, message.getAllRecipients());
    			// 7、关闭连接
    			transport.close();
    			//  写入session
    			req.getSession().setAttribute("code", code);
    		} catch (Exception e) {
    			e.printStackTrace();
    			req.getSession().setAttribute("error", "邮件发送失败");
    		}
    	}
    }
    
    

    需要用到servlet的jar包哟,你有tomcat就会自动导入进去。

    当中用到三个工具类,新建工具类。

    新建工具类JavaMailUtil

    在com.zout.util包下新建

    JavaMailUtil.java

    package com.zout.util;
    
    import java.io.IOException;
    import java.util.Date;
    import javax.mail.MessagingException;
    import javax.mail.Session;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
     
    /**
     * 
     *@class_name:JavaMailUtil
     *@comments:定义邮箱发送配置接口
     *@param:web版本
     *@return: 
     *@author:邹涛/Zoutao
     *@createtime:2019年2月23日
     */
    public class JavaMailUtil {
     
    	// 发件人的邮箱-修改为自己的
    	public static String emailAccount = "你自己的@qq.com";
    	// 发件人邮箱授权码-修改为自己的
    	public static String emailPassword = "prktbf你自己vbajj";
    	// 发件人邮箱服务地址-修改为自己的
    	public static String emailSMTPHost = "smtp.qq.com";
    	//  收件人邮箱
    	public static String receiveMailAccount = "";
    	
    	
    	/**
    	 *  创建一封邮件(发件人、收件人、邮件内容)
    	 * @param session
    	 * @param sendMail
    	 * @param receiveMail
    	 * @param html
    	 * @return
    	 * @throws MessagingException
    	 * @throws IOException 
    	 * cc:抄送
    	 * Bcc:密送
    	 * To:发送
    	 */
    	public static  MimeMessage creatMimeMessage(Session session,String sendMail,String receiveMail,String html) throws MessagingException, IOException {
    		// 1、创建一封邮件对象
    		MimeMessage message = new MimeMessage(session);
    		// 2、From:发件人
    		message.setFrom(new InternetAddress(sendMail, "发件人昵称", "UTF-8"));
    		// 3、To:收件人(可以增加多个收件人:抄送或者密送)
    		message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(receiveMail, "张三", "UTF-8"));
    		// 4、Subject:邮件主题
    		message.setSubject("邮箱验证","UTF-8");
    		// 5、Content:邮件正文(可以使用Html标签)
    		message.setContent(html,"text/html;charset=UTF-8");
    		// 6、设置发送时间
    		message.setSentDate(new Date());
    		// 7、保存设置
    		message.saveChanges();
    		// 8、将该邮件保存在本地
    		//OutputStream out = new FileOutputStream("D://MyEmail" + UUID.randomUUID().toString() + ".eml");
    		//message.writeTo(out);
    		//out.flush();
    		//out.close();
    		return message;
    	} 
    }
    

    把对应地方改为你自己的。

    新建RandomUtil工具类

    在com.zout.util包下新建RandomUtil;

    RandomUtil.java:

    package com.zout.util;
    
    /**
     * 
     *@class_name:RandomUtil
     *@comments:生成随机6位数验证码
     *@param:
     *@return: 
     *@author:邹涛/Zoutao
     *@createtime:2019年2月23日
     */
    public class RandomUtil {
    	public static void main(String[] args) {
    		// 控制台打印
    		System.out.println(RandomUtil.getRandom());
    	}
    	
    	//  生成6位数随机验证码
    	public static String getRandom() {
    		String[] letters = new String[] {
    				"q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m",
    				"A","W","E","R","T","Y","U","I","O","P","A","S","D","F","G","H","J","K","L","Z","X","C","V","B","N","M",
    				"0","1","2","3","4","5","6","7","8","9"};
    		String code ="";
    		for (int i = 0; i < 6; i++) {
    			code = code + letters[(int)Math.floor(Math.random()*letters.length)];
    		}
    		return code;
    	}
    }
    

    新建内容htmlText类

    在com.zout.util包下新建

    htmlText.java:

    package com.zout.util;
    
    /**
     * 
     *@class_name:htmlText
     *@comments:定义邮件内容
     *@param:
     *@return: 
     *@author:邹涛/Zoutao
     *@createtime:2019年2月23日
     */
    public class htmlText {
    		//  返回页面Html携带的6位随机码
    		public static String html(String code) {
    			
    			String html = "Email地址验证<br/>"+ 
    			"这封邮件是由【柒晓白网络科技】发送的。<br/>"+
    			"你收到这封邮件是【柒晓白网络科技】进行新用户注册或者用户修改Email使用这个地址。<br/>"+
    			"账号激活声明<br/>"+
    			"请将下面的验证码输入到提示框即可:<h3 style='color:red;'>" + code + "</h3><br/>";
    			return html;
    		}
    	}
    
    

    这就完成了邮件发送的功能。

    然后我们还需要注册接收的servlet。
    因为在jsp当中,点击注册的时候,发请求:RegistServlet。
    新建一个servlet类:
    RegistServlet.java

    package com.zout.controller;
    
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 
     *@class_name:RegistServlet
     *@comments: 注册请求处理
     *@param:验证码校验 
     *@return: jsp跳转
     *@author:邹涛/Zoutao
     *@createtime:2019年2月22日
     */
    @WebServlet("/RegistServlet")
    public class RegistServlet extends HttpServlet{
    	
    	private static final long serialVersionUID = 1L;
    	
    	@Override
    	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    			throws ServletException, IOException {
    		
    		// 获取session中的验证码
    		String sessionCode = (String) req.getSession().getAttribute("code");
    		System.out.println(sessionCode);
    		
    		if(sessionCode != null) {
    			//  获取页面提交的验证码
    			String inputCode = req.getParameter("code");
    			System.out.println("页面提交的验证码:" + inputCode);
    			if (sessionCode.toLowerCase().equals(inputCode.toLowerCase())) {
    				String username = req.getParameter("username");
    				String password = req.getParameter("password");
    				System.out.println("页面提交:" + username+password);
    				//  验证成功,跳转成功页面
    				req.setAttribute("username", username);
    				req.getRequestDispatcher("/success.jsp").forward(req, resp);
    			}else {
    				//  验证失败
    				req.getRequestDispatcher("fail.jsp").forward(req, resp);
    			}
    		}else {
    			//  验证失败
    			req.getRequestDispatcher("fail.jsp").forward(req, resp);
    		}
    		//  移除session中的验证码
    		req.removeAttribute("code");
    	}
    }
    

    接收一下注册请求,然后跳转到指定页面。

    好了整个邮箱注册已经完成。开始运行我们的项目了。

    浏览器输入:http://localhost:8080/EmailAndPhone/register.jsp

    邮箱发送效果图:

    输入邮箱地址:

    带有校验,如果邮箱不是带有@符号,则出现错误提示。

    在这里插入图片描述
    点击发送验证码。

    后台:

    在这里插入图片描述邮箱里面查看验证码:
    在这里插入图片描述

    输入错误的验证码就会提示错误,输入正确的就会跳转到成功页面。
    在这里插入图片描述


    好了,上诉就是整个关于最新web/java/jsp实现发送手机短信验证码和邮箱验证码的注册登录功能的过程了。

    总结一下,其中需要导入对应的jar包(ali的json,java的email,activation-1.1.1.jar),boostrap的css,js,和juqery的js。这些都是网上可以下载的。你可以自己下载。

    如图:
    在这里插入图片描述

    boostrap组件:

    在这里插入图片描述

    最后贴出整个项目的源码包下载地址:源码

    没有积分,点个关注留下邮箱,我发给你。


    展开全文
  • 文章目录昨日回顾今日内容1 jwt1.1 控制用户登录后才能访问,和不登录就能访问1.2 控制登录接口返回的数据格式1.3 自定义基于jwt的权限类1.4 手动签发token(多方式登录)1.5 jwt的配置参数2 基于角色的权限控制...
  • 一.准备工作 jdk1.8环境,maven3.x安装(指定本地仓库地址),Tomcat7以上安装 本次使用Eclipse搭建项目 Eclipse 的编译环境设置一下,utf-8 二.新建Maven工程 ...选择建立Maven Project 选择File -&...
  • 后台的整体页面和基本架构已经搭建好,转到前台开发。首先对前台用户模型进行定义,属性比后台用户更多,在manage.py中进行映射。在相应目录下创建模板文件、css和js文件,视图文件中实现视图类;再实现图形验证码类...
  • (1)调用第三方接口给用户手机发送短信验证码 (2)使用 BCryptPasswordEncoder 实现带盐值的加密 (3)使用 SpringSession 解决分布式环境下Session不一致问题 (4)使用 Redis 作为 SpringSession 的 Session ...
  • SystemServer 进程 : Android 手机开机后 , 就会启动 Zygote 进程 , 并且创建 SystemServer 进程 , SystemServer 进程就是 核心服务 所在进程 , 核心服务如 WindowsManagerService , PowerManagerService , ...
  • in-seconds: 5 client: service-url: defaultZone: http://eureka:eureka@localhost:8800/eureka/ registry-fetch-interval-seconds: 5 properties文件 #redis 中存储的用户登录数据结构 user.login.redis=zhzd:user...
  • 身份认证与访问控制

    千次阅读 2019-10-23 14:09:05
    多数银行的网银服务,除了向客户提供U盾证书保护模式外,还推出了动态口令方式,可免除携带U盾的不便,这是一种动态密码技术,在使用网银过程中,输入用户名后,即可通过绑定的手机一次性收到本次操作的密码,非常...
  • springboot整合shiro实现权限控制

    万次阅读 多人点赞 2019-05-24 12:27:40
    //登录及权限验证 public class MyRealm extends AuthorizingRealm { @Autowired UserService us; //角色权限和对应权限添加 //Authorization授权,将数据库中的角色和权限授权给输入的用户名 @Override ...
  • 2011年全年,腾讯移动安全实验室一共截获被植入手机病毒软件包数25404个,其中Symbian平台截获被植入病毒软件包数16521个,Android平台截获被植入病毒软件包数8883个。  第一章 安全行业报告概要  2011年...
  • 本文详细阐述一个MM从前台到外企经理的每一步详细的学习和发展路程,其中有工作中如何学习提高自己;如何打造自己的职业规划;面试时如何写最容易被“淘”出来的简历;面试时如何让面试官肯定你等详细技巧。也有应聘...
  • web前端: Bootstrap 3.0 组件丰富,兼容性好,界面美观 Server端: jsp+Servlet+json 公司技术力量储备丰富,技术成熟,有很多成熟的模块可以直接使用 数据库: mySql 免费,相对成熟 前台: 涉及到jstl,j...
  • 而不是放到数据库中间层 2中的业务不属于数据中间件处理的范畴,他更是服务上层(service filter等)应该做的事,比如强行指定id入库解密,出库加密,这样就会导致,为了前端显示的需求,增加的加密逻辑,会在整个...
  • 登录鉴权

    2020-12-22 14:58:53
    前台需要给我们传递用户名、密码、手机号、手机验证码。验证用户前台传过来的数据是否符合规范,我们使用的Hibernate Validator框架实现的服务端表单校验。短信验证码这块,我们采用的阿里的大于短信接口来做的,...
  • 模板、扫码打赏插件、手机版与电脑版智能管理插件、屏蔽复制与鼠标右键插件...前台底部自定义内容插件、畅言、友言、多说万能评论插件、电脑版整站背景图插件、万能伪静态规则生成插件、手机版广告插件、手机版内容阅读...
  • 3G手机网站源码.zip

    2020-03-30 10:11:53
    淘米CMS是一个免费开源的,快速、简单的面向智能手机等移动终端的网站CMS系统,自动生成手机安装包APK.并提供终端消息推送,手机版后台管理等功能。 淘米CMS提供从服务器端网站到手机客户端以及客户端管理一整套...
  • 记者花700元就能买到同事10项信息,包括开房记录、名下资产、乘坐航班、上网记录信息,甚至还能买到手机定位、手机通话记录。在互联网连接一切的力量下,个人信息保密之墙显得异常脆弱。 “维基解密”的创始人、...
  • 注册登录的简单概述

    2020-12-22 21:54:04
    前台需要给我们传递用户名、密码、手机号、手机验证码。验证用户前台传过来的数据是否符合规范,我们使用的Hibernate Validator框架实现的服务端表单校验。短信验证码这块,我们采用的阿里的大于短信接口来做的,...
  • 手机APP测试注意点

    2021-04-01 17:35:41
    手机APP测试 功能测试 启动 APP安装完成后,是否可以正常打开,稳定运行 APP的速度是可以让人接受,切换是否流畅 网络异常时,应用是否会崩溃:在...切换到后台再回到前台可以正常浏览本地数据 手动刷新时,是否
  • Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储 状态信息. 更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript, HTML,图片等),而你的服务端只要提供API...
  • 3.增加功能,支持手机伪自适应功能,设置后手机和pc网址相同。4.增加伪静态设置判断,支持自建模型,Nginx环境需要手动设置。5.增加安全验证规则,增强后台防护能力。6.增加数据调试模式,方便站长做页面效率测试和...
  • 一款3GCMS手机建站官方版 for PHP版,该源码很不错的,3gcms是一个免费开源的,快速、简单的面向... 码:admin888 6 输入http://***安装目录****/?t=w3g 查看3G网站,建议采用手机查看,或使用支持HTML5的浏览器。
  • ❞ 使用对称加密 加密解密在前后台协商后,似乎是个不错的办法,比如,前台使用一个字符串位移+字符串反转的简单方法(举个例子,当然不能这么简单)。那么,如果原密码 123456 先移位: ❝ 123456-->456123 ❞ 再...
  • 注册登录鉴权话术

    2020-12-22 20:54:35
    前台需要给我们传递用户名、密码、手机号、手机验证码。验证用户前台传过来的数据是否符合规范,我们使用的Hibernate Validator框架实现的服务端表单校验。短信验证码这块,我们采用的阿里的大于短信接口来做的,...
  • 模式设置:支持动态,静态,伪静态,缓存,自定更新频率设定,可设定前台页面扩展名。 静态列表:可直接编辑静态页面,支持一键清空。 缓存列表:仅支持前台缓存页面编辑,支持一键清空(清空功能包含后台页面)。...
  • Spring-Session扩展之单一用户登录

    千次阅读 2017-12-16 14:23:05
    内部网站, 每个帐号只允许登录一次, 该帐号的再次登录会将前一个登录用户踹下来, 简而言之就是达到手机上QQ登录的效果。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,418
精华内容 1,767
关键字:

密控前台手机登录