前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)

整合篇二

    • 整合JWT
      • 用户登录业务介绍
        • 单一服务器模式
        • SSO(single sign on)模式
        • SSO登录三种常见的方式
      • 传统用户身份验证
      • 解决方案
      • JWT令牌
      • JWT的原则
      • 整合
    • 整合腾讯云短信服务
      • 后端编码
      • 前端编码
    • 微信扫描登录
      • OAuth2
      • 开发流程
    • 整合首页课程和名师
      • 名师页面静态效果整合
      • 讲师列表页
      • 讲师详情页

整合JWT

用户登录业务介绍

单一服务器模式

一般情况是用户将账号密码发给服务器,服务器验证后把数据保存到session中(cookie是数据存在客户端,session是数据存在服务端)。服务端返回sessionId给客户端,客户端会把这个信息存入用户的cookie中,每次请求的从cookie中取值和服务端的保存的数据对比,确认身份。

最开始学javaweb的时候,做登录都是保存到session域中,保存之后判断用户登录与否通过取session域中的数据来决定

这种登录模式只适合单一的小项目,不方便横向扩展…

SSO(single sign on)模式

单点登录

客户端登录后,将账户密码存到认证中心,其余服务通过访问认证中心进行身份验证

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第1张图片

优点 :

用户身份信息独立管理,更好的分布式管理。

可以自己扩展安全策略

缺点:

认证服务器访问压力较大。

token模式登录流程

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第2张图片

SSO登录三种常见的方式

  • session广播
  • cookie+redis
  • 使用token实现token

优点:

无状态: token无状态,session有状态的

基于标准化: 你的API可以采用标准化的 JSON Web Token (JWT)

缺点:

占用带宽

无法在服务器端销毁

注:基于微服务开发,选择token的形式相对较多,因此我使用token作为用户认证的标准

传统用户身份验证

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第3张图片

Internet服务无法与用户身份验证分开。一般过程如下:

  1. 用户向服务器发送用户名和密码。
  2. 验证服务器后,相关数据(如用户角色,登录时间等)将保存在当前会话中。
  3. 服务器向用户返回session_id,session信息都会写入到用户的Cookie。
  4. 用户的每个后续请求都将通过在Cookie中取出session_id传给服务器。
  5. 服务器收到session_id并对比之前保存的数据,确认用户的身份。

这种模式最大的问题是,没有分布式架构,无法支持横向扩展。

解决方案

  1. session广播
  2. 将透明令牌存入cookie,将用户身份信息存入redis

另外一种灵活的解决方案:

使用自包含令牌,通过客户端保存数据,而服务器不保存会话数据。 JWT是这种解决方案的代表。

JWT令牌

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第4张图片

典型的,一个JWT看起来如下图:

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第5张图片

该对象为一个很长的字符串,字符之间通过"."分隔符分为三个子串。

每一个子串表示了一个功能块,总共有以下三个部分:JWT头、有效载荷和签名

JWT的原则

JWT的原则是在服务器身份验证之后,将生成一个JSON对象并将其发送回用户

{
“sub”: “1234567890”,
“name”: “Jack”,
“admin”: true
}

之后,当用户与服务器通信时,客户在请求中发回JSON对象。服务器仅依赖于这个JSON对象来标识用户。为了防止用户篡改数据,服务器将在生成对象时添加签名。

服务器不保存任何会话数据,即服务器变为无状态,使其更容易扩展。

客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中。

此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域,因此一般是将它放入HTTP请求的Header Authorization字段中。当跨域时,也可以将JWT被放置于POST请求的数据主体中。

优势:

  • 生产的token可以包含基本信息,比如id、用户昵称、头像等信息,避免再次查库
  • 存储在客户端,不占用服务端的内存资源

整合

添加依赖


    
    
        io.jsonwebtoken
        jjwt
    

创建JWT工具类

public class JwtUtils {

    public static final long EXPIRE = 1000 * 60 * 60 * 24;
    public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";

    public static String getJwtToken(String id, String nickname){

        String JwtToken = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                .setSubject("guli-user")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                .claim("id", id)
                .claim("nickname", nickname)
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compact();

        return JwtToken;
    }

    /**
     * 判断token是否存在与有效
     * @param jwtToken
     * @return
     */
    public static boolean checkToken(String jwtToken) {
        if(StringUtils.isEmpty(jwtToken)) return false;
        try {
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 判断token是否存在与有效
     * @param request
     * @return
     */
    public static boolean checkToken(HttpServletRequest request) {
        try {
            String jwtToken = request.getHeader("token");
            if(StringUtils.isEmpty(jwtToken)) return false;
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token获取会员id
     * @param request
     * @return
     */
    public static String getMemberIdByJwtToken(HttpServletRequest request) {
        String jwtToken = request.getHeader("token");
        if(StringUtils.isEmpty(jwtToken)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String)claims.get("id");
    }
}

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第6张图片

整合腾讯云短信服务

这里整合的为腾讯云短信服务,视频中是阿里云短信。

由于阿里云短信申请不容易成功,所以我们这里用腾讯云。

看着sdk文档很容易就能整合成功~

短信 Java SDK-SDK 文档-文档中心-腾讯云-腾讯云 (tencent.com)

后端编码

建模块,改pom,yml,启动类

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第7张图片

业务类

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第8张图片

前端编码

主要技术点是:页面,倒计时功能

这两个功能主要是前端知识点,这里不过多展示

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第9张图片

使用完这些插件之后,其余的套路和之前整合的一样

四大步:

  1. 添加路由
  2. 点击路由显示页面
  3. api文件夹创建js文件,定义后端接口地址和参数
  4. 创建vue页面引入js,调用方法实现功能

噢噢噢,这个是写后台管理系统的时候的套路对吧

前台系统也差不多的了

  1. api文件夹创建js文件,定义后端接口地址和参数
  2. 创建vue页面引入js,调用方法实现功能

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第10张图片

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第11张图片

微信扫描登录

OAuth2

OAuth2.0 详解 - 知乎 (zhihu.com)

什么是OAuth2?

OAuth 不是一个API或者服务,而是一个验证授权(Authorization)的开放标准,所有人都有基于这个标准实现自己的OAuth。

为什么要有OAuth?

OAuth2的出现是为了解决安全性问题,OAuth使得第三方应用对资源的访问更加安全

微信扫码登录的具体流程

微信开放平台 (qq.com)

准备工作 | 微信开放文档 (qq.com)

httpclient就是不用在浏览器中输入url访问资源也能实现浏览器的过程

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第12张图片

微信扫码登录流程

来自于微信开放平台官网

1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据 code 参数;
2. 通过 code 参数加上 AppID 和AppSecret等,通过 API 换取access_token;
3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。

开发流程

微信扫码登录需要有商户微信信息

这里采用的是视频提供的

建模块,改pom,yml,启动类

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第13张图片

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第14张图片

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第15张图片

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第16张图片

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第17张图片

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第18张图片

有了access_token我们就可以通过接口来获取用户信息了,从而把用户保存到数据库中

存数据库

由官网可知,请求成功后返回的结果是一个json字符串

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第19张图片

如下实例:

{"access_token":"56_jgDYj0kFSTarb6dLk3S8v32kVFmACL7MSBlAeBllfWMtfCqmFnvaAk2jfQTnjmVJ0tt7mAwaqHQ6NUt3DNJIYq8LH7utQA6QXIwfIdC46lE",
 "expires_in":7200,
 "refresh_token":"56_vQaXS1y1Fnp6zf4lZkFBDA7FNRdrkgDBPSytNMFmwdvey5oufKUIB2-7mjdIK7hjNzdD0pCAe3V7Heerszs1xiRm0jjqRufX_ddaDBviuIc",
 "openid":"o3_SC501zRkVcwqQ_sbnIMcp4awU",
 "scope":"snsapi_login",
 "unionid":"oWgGz1FS61brgcCChgq5yO4mQuZM"}

数据库表的结构如下:

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第20张图片

代码如下:

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第21张图片

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第22张图片

前端页面不多说了,了解即可(CV)

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第23张图片

整合首页课程和名师

名师页面静态效果整合



讲师列表页

后端开发

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第24张图片

前端开发

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第25张图片

测试

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第26张图片

讲师详情页

动态路由实现

在详情页我们要查看讲师信息,课程信息

所以后端就两个接口,一个根据路径中的参数查询讲师信息

一个来查询讲师所讲的课程信息

效果如下:

前后端分离项目知识汇总(JWT,腾讯云短信服务,微信扫码登录)_第27张图片

根据讲师id查询讲师所讲课程列表

/**
	 * 根据讲师id查询当前讲师的课程列表
	 * @param teacherId
	 * @return
	 */
@Override
public List<Course> selectByTeacherId(String teacherId) {

    QueryWrapper<Course> queryWrapper = new QueryWrapper<Course>();

    queryWrapper.eq("teacher_id", teacherId);
    //按照最后更新时间倒序排列
    queryWrapper.orderByDesc("gmt_modified");

    List<Course> courses = baseMapper.selectList(queryWrapper);
    return courses;
}

根据ID查询讲师

@ApiOperation(value = "根据ID查询讲师")
@GetMapping(value = "{id}")
public R getById(
		@ApiParam(name = "id", value = "讲师ID", required = true)
		@PathVariable String id){

	//查询讲师信息
	Teacher teacher = teacherService.getById(id);

	//根据讲师id查询这个讲师的课程列表
	List<Course> courseList = courseService.selectByTeacherId(id);

	return R.ok().data("teacher", teacher).data("courseList", courseList);
}

前端开发



你可能感兴趣的:(项目,微信开放平台,vue.js,spring,boot,spring,cloud,微服务)