项目第十二天

短信验证码

可以在利用中国网建的接口

网址:
http://www.smschinese.cn/
1.注册
在这里插入图片描述
demo学习
在这里插入图片描述
浏览器模拟
https://blog.csdn.net/sswltt/article/details/80415284

后台实现api封装

写短信发送接口-commonservice
Feign

@FeignClient(value = "HRM-COMMON", fallbackFactory = SmsClientFallbackFactory.class )//服务提供
@RequestMapping("/sms")
public interface SmsClient {

    //feign如果要传递Map list等需要特殊处理
    @PostMapping
    AjaxResult send(@RequestParam String params);
}

短信接口常用类

public interface SmsContants {
    //注册名
    public static final String SMS_UID="中国网建的注册名";
    //密钥
    public static final String SMS_KEY="密钥";
}

service

//参数可变
@Override
public AjaxResult sendSmsCode(Map<String, String> params)  {

    PostMethod post = null;
    try {

        HttpClient client = new HttpClient();
        post = new PostMethod("http://utf8.api.smschinese.cn");
        post.addRequestHeader("Content-Type",
                "application/x-www-form-urlencoded;charset=utf-8");//在头文件中设置转码

        //动态参数 //map===>list====>array
        List<NameValuePair> datas = new ArrayList<>();
        for (String key : params.keySet()) {
            datas.add( new NameValuePair(key, params.get(key) ));
        }
        NameValuePair[] data = datas.toArray(new NameValuePair[]{});
        post.setRequestBody(data);

        client.executeMethod(post);
        Header[] headers = post.getResponseHeaders();
        int statusCode = post.getStatusCode(); //400 404 200 500
        String result = new String(post.getResponseBodyAsString().getBytes("utf-8"));
        System.out.println("statusCode:"+statusCode);
        System.out.println(result); //打印返回消息状态
        if (statusCode==200){
            //对各种错误码进行处理
            return AjaxResult.me().setMessage(result);
        }else{
            return AjaxResult.me().setSuccess(false).setMessage(result);
        }

    }catch (Exception e){
        e.printStackTrace();
    }
    finally {
        if (post != null) {
            post.releaseConnection();
        }
    }
    return null;
}

调用短信服务

@Override
public AjaxResult sendSmsCode(Map<String, String> params) {
    // 一 接收参数
    //手机号
    String mobile = params.get("mobile");
    //图片验证码
    String imageCode = params.get("imageCode");
    //图片验证码的key
    String imageCodeKey = params.get("imageCodeKey");
    // 二 做检验
    //2.1 图片验证 通过key从redis获取存放验证码和输入的进行对比
    String imgCodeforReids = redisClient.get(imageCodeKey);
    if (imgCodeforReids==null || !imageCode.equals(imgCodeforReids)){
        return AjaxResult.me().setSuccess(false).setMessage("图片验证码不正确!");
    }
    //2.2 手机号的验证-判null,是否已经注册了
    if (mobile==null){
        return AjaxResult.me().setSuccess(false).setMessage("请输入正确的手机号码");
    }
    List<Sso> ssos = ssoMapper
            .selectList(new EntityWrapper<Sso>().eq("phone", mobile));
    if (ssos!=null && ssos.size()>0){
        return AjaxResult.me().setSuccess(false).setMessage("你的手机号已经注册了,可以直接使用!");
    }
    // 三 发送短信验证码
    return sendSmsCode(mobile);
}

private AjaxResult sendSmsCode(String mobile) {
    String smsKey = "SMS_CODE:"+mobile;
    // 一 先产生一个验证码
    String smsCode = StrUtils.getComplexRandomString(4);   //面条 饭
    //二 如果原来验证码有效,替换生成哪个
    String smsCodeForRedis= redisClient.get(smsKey); //smsCode格式 code:time
    if (StringUtils.hasLength(smsCodeForRedis)){
        //2如果有效,判断是否已经过了重发时间,如果没有过就报错
        String[] split = smsCodeForRedis.split(":");
        String timeStr = split[1];
        long time = System.currentTimeMillis()-Long.valueOf(timeStr);
        if (time<1000*60){
            return AjaxResult.me().setSuccess(false).setMessage("请不要重复发送短信验证码!");
        }
        //如果过了,替换原来的验证码
        smsCode = split[0];
    }
    //三 存储到redis
    redisClient.addForTime(smsKey,smsCode+":"+System.currentTimeMillis(),60*5);//5分钟过期
    //四 都要进行发送
    System.out.println("[源码科技]已经发送验证码"+smsCode+"到用户手机:"+mobile);
    Map<String,String> params = new HashMap<>();
    //smsMob=手机号码&smsText=验证码:8888
    params.put("smsMob",mobile);
    params.put("smsText","验证码为:"+smsCode+",请在5分钟之内使用!");

    smsClient.send(JSONObject.toJSONString(params));
    return AjaxResult.me();
}

controller

public class SmsController {

    @Autowired
    private ISmsService smsService;
    //1 以下两个放到常量类中
    //Uid=本站用户名
    //Key=接口安全秘钥
    //2 以下两个是动态传入
    // smsMob=手机号码&smsText=验证码:8888
    @PostMapping
    AjaxResult send(@RequestParam String params){
        System.out.println(params);
        Map<String,String> paramsTmp =
                JSONObject.parseObject(params, Map.class);
        //封装参数
        paramsTmp.put("Uid", SmsContants.SMS_UID);
        paramsTmp.put("Key", SmsContants.SMS_KEY);
        return smsService.sendSmsCode(paramsTmp);
    }
}

前台

sendSmsCode(event){
                        //1.判断手机号不为空
						if(!this.formParams.mobile){
						    alert("手机号不能为空");
						    return;
						}

						//2.判断图片验证码不为空
                        if(!this.formParams.imageCode){
                            alert("图片验证码不能为空");
                            return;
                        }

                        //3.获取按钮,禁用按钮
						var sendBtn = $(event.target);
                        sendBtn.attr("disabled",true);

                        var param = {
                            mobile: this.formParams.mobile,
                            imageCode:this.formParams.imageCode,
							imageCodeKey:localStorage.getItem("imageCodeKey")
						};
						//4.发送ajax请求
                        this.$http.post("/user/verifycode/sendSmsCode",param).then(res=>{
                            var ajaxResult = res.data;
                            if(ajaxResult.success){
                                alert("手机验证码已经发送到您的手机,请在5分钟内使用");
                                //4.1.发送成:倒计时
								var time = 60;

								var interval = window.setInterval( function () {
								    //每一条倒计时减一
                                    time = time - 1 ;

                                    //把倒计时时间搞到按钮上
                                    sendBtn.html(time+"秒后重发");

                                    //4.2.倒计时完成恢复按钮
									if(time <= 0){
                                        sendBtn.html("重新发送");
                                        sendBtn.attr("disabled",false);
                                        //清除定时器
                                        window.clearInterval(interval);
									}
                                },1000);
							}else{
                                //4.3.发送失败:提示,恢复按钮
                                sendBtn.attr("disabled",false);
								alert("发送失败:"+ajaxResult.message);
							}
                        })
					}

注册实现

前台

submitRegister(){
                        //4.发送ajax请求
                        this.$http.post("/user/sso/register",this.formParams).then(res=>{
                            var ajaxResult = res.data;
                            if(ajaxResult.success){
                                alert("注册成功");
                                window.location.href = "http://127.0.0.1:6003/login.html";
                            }else{
                                alert("发送失败:"+ajaxResult.message);
                            }
                        })
					}

controller

//注册
@PostMapping("/register")
/**
 * mobile:'13330964748',
 password:'123456',
 imageCode:'',
 smsCode:''
 ==============Map接口---不是通过feign,通过zuul转发过来外部请求
 */
public AjaxResult register(@RequestBody Map<String,String> params)
{
    return ssoService.register(params);
}

service
@Override
public AjaxResult register(Map<String, String> params) {
    String mobile = params.get("mobile");
    String password = params.get("password");
    String smsCode = params.get("smsCode");
    //1 校验
    AjaxResult ajaxResult = validateParam(mobile,password,smsCode);
    if (!ajaxResult.isSuccess())
        return ajaxResult;
    // 2 保存sso信息
    Sso sso = new Sso();
    sso.setPhone(mobile);
    //获取随机验证-32位随机字符串
    String salt = StrUtils.getComplexRandomString(32);
    sso.setSalt(salt);
    //使用随机验证给密码md5加密,并设置
    //输入密码+以后做校验的时候先从数据库查询盐=md5,再和数据库查询出来进行比较
    String md5Password = MD5.getMD5(password + salt);
    sso.setPassword(md5Password);
    sso.setNickName(mobile);
    sso.setSecLevel(0);
    sso.setBitState(7L); // 二进制位来表示 2个小时(扩展)
    sso.setCreateTime(System.currentTimeMillis());
    ssoMapper.insert(sso);
    // 3 保存关联对象信息vipbase
    VipBase vipBase = new VipBase();
    vipBase.setCreateTime(System.currentTimeMillis());
    vipBase.setSsoId(sso.getId());
    vipBase.setRegChannel(1);
    vipBase.setRegTime(System.currentTimeMillis());
    vipBaseMapper.insert(vipBase);
    return AjaxResult.me();
}

private AjaxResult validateParam(String mobile,String password,String smsCode){
    // 手机号密码null校验
    if (!StringUtils.hasLength(mobile) || !StringUtils.hasLength(password))
        return AjaxResult.me().setSuccess(false).setMessage("请输入用户名或密码!");
    // 手机号时候已经注册
    List<Sso> ssoList = ssoMapper.selectList(new EntityWrapper<Sso>().eq("phone", mobile));
    if (ssoList!=null&&ssoList.size()>0)
        return AjaxResult.me().setSuccess(false).setMessage("您已经注册过了!可以直接使用!");
    // 短信验证码校验 通过key从redis获取
    String smsCodeStr = redisClient.get("SMS_CODE:" + mobile); // code:time
    String smsCodeOfRedis = smsCodeStr.split(":")[0];
    if (!smsCodeOfRedis.equals(smsCode))
        return AjaxResult.me().setSuccess(false).setMessage("请输入正确短信验证码");

    return AjaxResult.me();
}

单点登陆

zuul拦截

package com.sx.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class LoginFilter extends ZuulFilter {
    @Override
    public String filterType() {
        // 登录校验,肯定是在前置拦截
        return "pre";
    }

    @Override
    public int filterOrder() {
        //顺序设置为1
        return 1;
    }

    //登录放行
    @Override
    public boolean shouldFilter() {
        // 返回true,代表过滤器生效。
        return true;
    }

    @Override
    public Object run() throws ZuulException {

        // 登录校验逻辑。
        // 1)获取Zuul提供的请求上下文对象
        RequestContext ctx = RequestContext.getCurrentContext();
        // 2) 从上下文中获取request对象
        HttpServletRequest req = ctx.getRequest();

        //对登录放行
        String requestURI = req.getRequestURI();
        System.out.println(requestURI+"jjjjjjjjjjjjjjjjjj");
        if (requestURI.contains("login"))
            return  null;
        if (requestURI.contains("api-docs"))
            return  null;
        if(requestURI.contains("verifycode"))
            return null;
        // 3) 从请求中获取token
        String token = req.getHeader("access-token");

        // 4) 判断
        if(token == null || "".equals(token.trim())){
            // 没有token,登录校验失败,拦截
            ctx.setSendZuulResponse(false);
            // 返回401状态码。也可以考虑重定向到登录页。
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        // 校验通过,可以考虑把用户信息放入上下文,继续向后执行
        return null;
    }
    }

后台

controller

//登录
@PostMapping("/login")
/**
 * phone:'13330964748',
    password:'123456',
 */
public AjaxResult login(@RequestBody Sso sso){
   return ssoService.login(sso);
}

service

@Override
public AjaxResult login(Sso sso) {
    //校验用户是否存在,状态ok,是否已经过期等待
    if (!StringUtils.hasLength(sso.getPhone()) || !StringUtils.hasLength(sso.getPassword()))
        return AjaxResult.me().setSuccess(false).setMessage("请输入用户名或密码!");

    List<Sso> ssoList = ssoMapper.selectList(new EntityWrapper<Sso>()
            .eq("phone", sso.getPhone()));
    if (ssoList==null || ssoList.size()<1)
        return  AjaxResult.me().setSuccess(false).setMessage("用户不存在,请注册后再来登录!");

    //从数据库查询sso
    Sso ssoExsit = ssoList.get(0);

    //进行密码比对-输入密码+数据库盐值=md5再和数据库密码比对
    System.out.println(sso.getPassword());
    System.out.println(ssoExsit.getSalt());
    String md5Pwd = MD5.getMD5(sso.getPassword() + ssoExsit.getSalt());
    System.out.println(md5Pwd);
    if (!ssoExsit.getPassword().equals(md5Pwd)){
        return  AjaxResult.me().setSuccess(false).setMessage("请输入正确的用户名或密码!");
    }

    //用户存到redis并且返回token-60*30
    String accessToken = UUID.randomUUID().toString();
    redisClient.addForTime(accessToken, JSONObject.toJSONString(ssoExsit),30*60);
   return AjaxResult.me().setResultObj(accessToken);
}

获取用户
controller

@GetMapping("/ac/{accessToken}")
public Sso querySso(@PathVariable("accessToken") String accessToken){
    System.out.println(accessToken);
    return ssoService.querySso(accessToken);
}

service

@Override
public Sso querySso(String accessToken) {
    //登录时已经存放了redis,直接从redis获取就ok
    String sso = redisClient.get(accessToken);
    return JSONObject.parseObject(sso,Sso.class);
}

前台实现

login(){
                            //4.发送ajax请求
                            this.$http.post("/user/sso/login",this.formParams).then(res=>{
                                var ajaxResult = res.data;
                                if(ajaxResult.success){
                                    alert("登录成功");

let accessToken = ajaxResult.resultObj;
                                    //通过cookie共享accessToken给其他站点  user不能直接放入cookie,因为不安全,但是可以
                                    //存放access-token到时通过access-token就能获取用户了
                                    setCookie("access-token",accessToken,"m30"); //session过期也是30分钟
                                    //保存用户到localStorage
                                    this.$http.get("/user/sso/ac/"+accessToken).then(res=>{
                                        var user = res.data;
                                        localStorage.setItem("user",user)
                                     })
//跳转到主页面 localhost和127.0.0.1不同的不能共享cookie
//location.href = "http://user.hrm.com:6003/user.home.html"
location.href = "http://127.0.0.1:6003/user.home.html"
//以后所有对后端服务的访问都要携带accessToken
                                }else{
                                    alert("登录失败:"+ajaxResult.message);
                                }
                            })

common.js

/JS操作cookies方法!

//读取cookies
function getCookie(name)
{
    var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
    if(arr=document.cookie.match(reg)) return unescape(arr[2]);
    else return null;
}
//删除cookies
function delCookie(name)
{
    var exp = new Date();
    exp.setTime(exp.getTime() - 1);
    var cval=getCookie(name);
    if(cval!=null) document.cookie= name + "="+cval+";expires="+exp.toGMTString();
}
//使用示例
// setCookie("name","hayden");
// alert(getCookie("name"));


//如果需要设定自定义过期时间
//那么把上面的setCookie 函数换成下面两个函数就ok;


//写cookies
function setCookie(name,value)
{
    var Days = 30;
    var exp = new Date();
    exp.setTime(exp.getTime() + Days*24*60*60*1000);
    document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();
}
//程序代码
function setCookie(name,value,time){
    var strsec = getsec(time);
    var exp = new Date();
    exp.setTime(exp.getTime() + strsec*1);
    //所以hrm.com为父域名的任何路径都能共享cookie
    //document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString()+";path=/"+";domain=.hrm.com";
    document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString()+";path=/";
}
function getsec(str){
    var str1=str.substring(1,str.length)*1;
    var str2=str.substring(0,1);
    if (str2=="s"){
        return str1*1000;
    }else if (str2=="h"){
        return str1*60*60*1000;
    }else if (str2=="m"){
        return str1*60*1000;
    }else if (str2=="d"){
        return str1*24*60*60*1000;
    }
}
//这是有设定过期时间的使用示例:
//s20是代表20秒
//h是指小时,如12小时则是:h12
//d是天数,30天则:d30
//暂时只写了这三种,不知道谁有更好的方法,呵呵
// setCookie("name","hayden","s20");

//axios初始化
axios.interceptors.request.use(config => {
    //如果已经登录了,每次都把token作为一个请求头传递过程

    let accessToken = getCookie("access-token");
    if (accessToken) {
        // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
        config.headers['access-token'] = accessToken;
    }
    console.debug('config',config)
    return config
}, error => {
    // Do something with request error
    Promise.reject(error)
})
axios.defaults.baseURL = "http://127.0.0.1:1030/services"//配置前缀
Vue.prototype.$http = axios //给Vue这个类添加一个原型的属性,这个类的对象都能调用
Vue.config.productionTip = false

//登录拦截判断 时候有accessToken
//是否能从localStrage获取获取用户,如果有自己跳过
//否则需要获取用户,再跳过
//var loginUrl = "http://user.hrm.com:6003/login.html"
var loginUrl = "http://127.0.0.1:6003/login.html"
$().ready(function(){
    // 登录拦截 要放行 login.html register
    let href = location.href;
    if(href.indexOf("login")!=-1 || href.indexOf("reg") !=-1)
        return;
    let accessToken = getCookie("access-token");
    if(!accessToken)
        location.href = loginUrl;

    let user = localStorage.getItem("user");
    if(!user){
        //保存用户到localStorage
        axios.get("/user/sso/ac/"+accessToken).then(res=>{
            var user = res.data;
            localStorage.setItem("user",user)
        })
    }
})

其他站点: 登录拦截,获取ac,进而获取用户存放localstorage
common.js

//JS操作cookies方法!

//读取cookies
function getCookie(name)
{
    var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
    if(arr=document.cookie.match(reg)) return unescape(arr[2]);
    else return null;
}
//删除cookies
function delCookie(name)
{
    var exp = new Date();
    exp.setTime(exp.getTime() - 1);
    var cval=getCookie(name);
    if(cval!=null) document.cookie= name + "="+cval+";expires="+exp.toGMTString();
}
//使用示例
// setCookie("name","hayden");
// alert(getCookie("name"));


//如果需要设定自定义过期时间
//那么把上面的setCookie 函数换成下面两个函数就ok;


//写cookies
function setCookie(name,value)
{
    var Days = 30;
    var exp = new Date();
    exp.setTime(exp.getTime() + Days*24*60*60*1000);
    document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();
}
//程序代码
function setCookie(name,value,time){
    var strsec = getsec(time);
    var exp = new Date();
    exp.setTime(exp.getTime() + strsec*1);
    document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString()+";path=/";
}
function getsec(str){
    var str1=str.substring(1,str.length)*1;
    var str2=str.substring(0,1);
    if (str2=="s"){
        return str1*1000;
    }else if (str2=="h"){
        return str1*60*60*1000;
    }else if (str2=="m"){
        return str1*60*1000;
    }else if (str2=="d"){
        return str1*24*60*60*1000;
    }
}
//这是有设定过期时间的使用示例:
//s20是代表20秒
//h是指小时,如12小时则是:h12
//d是天数,30天则:d30
//暂时只写了这三种,不知道谁有更好的方法,呵呵
// setCookie("name","hayden","s20");
//axios初始化
axios.interceptors.request.use(config => {
    //如果已经登录了,每次都把token作为一个请求头传递过程

    let accessToken = getCookie("access-token");
    if (accessToken) {
        // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
        config.headers['access-token'] = accessToken;
    }
    console.debug('config',config)
    return config
}, error => {
    // Do something with request error
    Promise.reject(error)
})
axios.defaults.baseURL = "http://127.0.0.1:1030/services"//配置前缀
Vue.prototype.$http = axios //给Vue这个类添加一个原型的属性,这个类的对象都能调用
Vue.config.productionTip = false

//登录拦截判断 时候有accessToken
//是否能从localStrage获取获取用户,如果有自己跳过
//否则需要获取用户,再跳过
//var loginUrl = "http://user.hrm.com:6003/login.html"
var loginUrl = "http://127.0.0.1:6003/login.html"
$().ready(function(){
    // 登录拦截 要放行 login.html register
    let href = location.href;
    if(href.indexOf("login")!=-1 || href.indexOf("reg") !=-1)
        return;
    let accessToken = getCookie("access-token");
    if(!accessToken)
        location.href = loginUrl;

    let user = localStorage.getItem("user");
    if(!user){
        //保存用户到localStorage
        axios.get("/user/sso/ac/"+accessToken).then(res=>{
            var user = res.data;
            localStorage.setItem("user",user)
        })
    }
})

注意:
1 一定要保证同域名
2 引入js顺序 common.js是需要依赖axios

Docker

先在VMware 中安装 CentOS(桥接模式)
使用ip addr命令查看本地IP
在这里插入图片描述然后在cmd中ping ip地址 测试网络是否联通
然后在root登陆的终端中输入

yum install docker

查看Docker版本

docker version

启动与停止Docker
ystemctl命令是系统服务管理器指令,它是 service 和 chkconfig 两个命令组合。
启动docker:systemctl start docker
停止docker:systemctl stop docker
重启docker:systemctl restart docker
查看docker状态:systemctl status docker
开机启动:systemctl enable docker
查看docker概要信息:docker info
查看docker帮助文档:docker --help
列出镜像
docker images
在这里插入图片描述REPOSITORY:镜像所在的仓库名称
TAG:镜像标签
IMAGE ID:镜像ID
CREATED:镜像的创建日期(不是获取该镜像的日期)
SIZE:镜像大小
这些镜像都是存储在Docker宿主机的/var/lib/docker目录下
搜索镜像
docker search 镜像名称

阿里镜像

编辑该文件:vi /etc/docker/daemon.json // 如果该文件不存在就手动创建;说明:在centos7.x下,通过vi。
)在该文件中输入如下内容:(就截图下面的那一团代码)
在这里插入图片描述

删除镜像

1、docker rmi $IMAGE_ID:删除指定镜像
2、docker rmi docker images -q:删除所有镜像

Docker 容器操作

查看正在运行容器
docker ps

交互式容器 (只有测试的时候用)

创建一个交互式容器并取名为mycentos
docker run -it --name=mycentos centos:7 /bin/bash
这时我们通过ps命令查看,发现可以看到启动的容器,状态为启动状态

使用exit命令 退出当前容器

然后用ps -a 命令查看发现该容器也随之停止:

退出容器马上停止.
启动容器执行容器中的shell:
… /bin/bash -c ‘java -jar /usr/local/java/demo-0.0.1-SNAPSHOT.jar’

守护式容器

创建一个守护式容器:如果对于一个需要长期运行的容器来说,我们可以创建一个守护式容器。命令如下(容器名称不能重复):
docker run -di --name=mycentos2 centos:7
登录守护式容器方式:
docker exec -it container_name (或者 container_id) /bin/bash(exit退出时,容器不会停止)

进去以后出来不会关闭

停止与启动容器

停止正在运行的容器:docker stop 容器名
启动已运行过的容器:docker start 容器名

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值