整合篇二
- 前言
- 整合JWT
- 用户登录业务介绍
- 单一服务器模式
- SSO(single sign on)模式
- SSO登录三种常见的方式
- 传统用户身份验证
- 解决方案
- JWT令牌
- JWT的原则
- 整合
- 整合腾讯云短信服务
- 后端编码
- 前端编码
- 微信扫描登录
- OAuth2
- 开发流程
- 整合首页课程和名师
- 名师页面静态效果整合
- 讲师列表页
- 讲师详情页
前言
源码代码:
https://github.com/YuyanCai/gulixueyuan-back–zshttps://github.com/YuyanCai/gulixueyuan-front–zs
前端页面:
https://github.com/YuyanCai/guli-xy-fd
整合JWT
用户登录业务介绍
单一服务器模式
一般情况是用户将账号密码发给服务器,服务器验证后把数据保存到session中(cookie是数据存在客户端,session是数据存在服务端)。服务端返回sessionId给客户端,客户端会把这个信息存入用户的cookie中,每次请求的从cookie中取值和服务端的保存的数据对比,确认身份。
最开始学javaweb的时候,做登录都是保存到session域中,保存之后判断用户登录与否通过取session域中的数据来决定
这种登录模式只适合单一的小项目,不方便横向扩展…
SSO(single sign on)模式
单点登录
客户端登录后,将账户密码存到认证中心,其余服务通过访问认证中心进行身份验证
优点 :
用户身份信息独立管理,更好的分布式管理。
可以自己扩展安全策略
缺点:
认证服务器访问压力较大。
token模式登录流程
SSO登录三种常见的方式
- session广播
- cookie+redis
- 使用token实现token
优点:
无状态: token无状态,session有状态的
基于标准化: 你的API可以采用标准化的 JSON Web Token (JWT)
缺点:
占用带宽
无法在服务器端销毁
注:基于微服务开发,选择token的形式相对较多,因此我使用token作为用户认证的标准
传统用户身份验证
Internet服务无法与用户身份验证分开。一般过程如下:
- 用户向服务器发送用户名和密码。
- 验证服务器后,相关数据(如用户角色,登录时间等)将保存在当前会话中。
- 服务器向用户返回session_id,session信息都会写入到用户的Cookie。
- 用户的每个后续请求都将通过在Cookie中取出session_id传给服务器。
- 服务器收到session_id并对比之前保存的数据,确认用户的身份。
这种模式最大的问题是,没有分布式架构,无法支持横向扩展。
解决方案
- session广播
- 将透明令牌存入cookie,将用户身份信息存入redis
另外一种灵活的解决方案:
使用自包含令牌,通过客户端保存数据,而服务器不保存会话数据。 JWT是这种解决方案的代表。
JWT令牌
典型的,一个JWT看起来如下图:
该对象为一个很长的字符串,字符之间通过"."分隔符分为三个子串。
每一个子串表示了一个功能块,总共有以下三个部分:JWT头、有效载荷和签名
JWT的原则
JWT的原则是在服务器身份验证之后,将生成一个JSON对象并将其发送回用户
{
“sub”: “1234567890”,
“name”: “Jack”,
“admin”: true
}
之后,当用户与服务器通信时,客户在请求中发回JSON对象。服务器仅依赖于这个JSON对象来标识用户。为了防止用户篡改数据,服务器将在生成对象时添加签名。
服务器不保存任何会话数据,即服务器变为无状态,使其更容易扩展。
客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中。
此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域,因此一般是将它放入HTTP请求的Header Authorization字段中。当跨域时,也可以将JWT被放置于POST请求的数据主体中。
优势:
- 生产的token可以包含基本信息,比如id、用户昵称、头像等信息,避免再次查库
- 存储在客户端,不占用服务端的内存资源
- …
整合
添加依赖
<dependencies>
<!-- JWT-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
</dependencies>
创建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");
}
}
整合腾讯云短信服务
这里整合的为腾讯云短信服务,视频中是阿里云短信。
由于阿里云短信申请不容易成功,所以我们这里用腾讯云。
看着sdk文档很容易就能整合成功~
短信 Java SDK-SDK 文档-文档中心-腾讯云-腾讯云 (tencent.com)
后端编码
建模块,改pom,yml,启动类
业务类
前端编码
主要技术点是:页面,倒计时功能
这两个功能主要是前端知识点,这里不过多展示
使用完这些插件之后,其余的套路和之前整合的一样
四大步:
- 添加路由
- 点击路由显示页面
- api文件夹创建js文件,定义后端接口地址和参数
- 创建vue页面引入js,调用方法实现功能
噢噢噢,这个是写后台管理系统的时候的套路对吧
前台系统也差不多的了
- api文件夹创建js文件,定义后端接口地址和参数
- 创建vue页面引入js,调用方法实现功能
微信扫描登录
OAuth2
OAuth2.0 详解 - 知乎 (zhihu.com)
什么是OAuth2?
OAuth 不是一个API或者服务,而是一个验证授权(Authorization)的开放标准,所有人都有基于这个标准实现自己的OAuth。
为什么要有OAuth?
OAuth2的出现是为了解决安全性问题,OAuth使得第三方应用对资源的访问更加安全
微信扫码登录的具体流程
httpclient就是不用在浏览器中输入url访问资源也能实现浏览器的过程
微信扫码登录流程
来自于微信开放平台官网
1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据 code 参数;
2. 通过 code 参数加上 AppID 和AppSecret等,通过 API 换取access_token;
3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
开发流程
微信扫码登录需要有商户微信信息
这里采用的是视频提供的
建模块,改pom,yml,启动类
有了access_token我们就可以通过接口来获取用户信息了,从而把用户保存到数据库中
存数据库
由官网可知,请求成功后返回的结果是一个json字符串
如下实例:
{"access_token":"56_jgDYj0kFSTarb6dLk3S8v32kVFmACL7MSBlAeBllfWMtfCqmFnvaAk2jfQTnjmVJ0tt7mAwaqHQ6NUt3DNJIYq8LH7utQA6QXIwfIdC46lE",
"expires_in":7200,
"refresh_token":"56_vQaXS1y1Fnp6zf4lZkFBDA7FNRdrkgDBPSytNMFmwdvey5oufKUIB2-7mjdIK7hjNzdD0pCAe3V7Heerszs1xiRm0jjqRufX_ddaDBviuIc",
"openid":"o3_SC501zRkVcwqQ_sbnIMcp4awU",
"scope":"snsapi_login",
"unionid":"oWgGz1FS61brgcCChgq5yO4mQuZM"}
数据库表的结构如下:
代码如下:
前端页面不多说了,了解即可(CV)
整合首页课程和名师
名师页面静态效果整合
<template>
<div id="aCoursesList" class="bg-fa of">
<!-- 讲师列表 开始 -->
<section class="container">
<header class="comm-title all-teacher-title">
<h2 class="fl tac">
<span class="c-333">全部讲师</span>
</h2>
<section class="c-tab-title">
<a id="subjectAll" title="全部" href="#">全部</a>
<!-- <c:forEach var="subject" items="${subjectList }">
<a id="${subject.subjectId}" title="${subject.subjectName }" href="javascript:void(0)" οnclick="submitForm(${subject.subjectId})">${subject.subjectName }</a>
</c:forEach>-->
</section>
</header>
<section class="c-sort-box unBr">
<div>
<!-- /无数据提示 开始-->
<section class="no-data-wrap">
<em class="icon30 no-data-ico"> </em>
<span class="c-666 fsize14 ml10 vam">没有相关数据,小编正在努力整理中...</span>
</section>
<!-- /无数据提示 结束-->
<article class="i-teacher-list">
<ul class="of">
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="姚晨" target="_blank">
<img src="~/assets/photo/teacher/1442297885942.jpg" alt>
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="姚晨" target="_blank" class="fsize18 c-666">姚晨</a>
</div>
<div class="hLh30 txtOf tac">
<span class="fsize14 c-999">。。。。。。。。。。。。。</span>
</div>
<div class="mt15 i-q-txt">
<p class="c-999 f-fA">北京师范大学法学院副教授</p>
</div>
</section>
</li>
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="谢娜" target="_blank">
<img src="~/assets/photo/teacher/1442297919077.jpg" alt>
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="谢娜" target="_blank" class="fsize18 c-666">谢娜</a>
</div>
<div class="hLh30 txtOf tac">
<span class="fsize14 c-999">。。。。。。。。。。。</span>
</div>
<div class="mt15 i-q-txt">
<p class="c-999 f-fA">资深课程设计专家,专注10年AACTP美国培训协会认证导师</p>
</div>
</section>
</li>
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="刘德华" target="_blank">
<img src="~/assets/photo/teacher/1442297927029.jpg" alt>
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="刘德华" target="_blank" class="fsize18 c-666">刘德华</a>
</div>
<div class="hLh30 txtOf tac">
<span class="fsize14 c-999">。。。。。。。。。。。。。。</span>
</div>
<div class="mt15 i-q-txt">
<p class="c-999 f-fA">上海师范大学法学院副教授</p>
</div>
</section>
</li>
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="周润发" target="_blank">
<img src="~/assets/photo/teacher/1442297935589.jpg" alt>
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="周润发" target="_blank" class="fsize18 c-666">周润发</a>
</div>
<div class="hLh30 txtOf tac">
<span class="fsize14 c-999">。。。。。。。。。。。</span>
</div>
<div class="mt15 i-q-txt">
<p class="c-999 f-fA">命题人</p>
</div>
</section>
</li>
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="钟汉良" target="_blank">
<img src="~/assets/photo/teacher/1442298121626.jpg" alt>
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="钟汉良" target="_blank" class="fsize18 c-666">钟汉良</a>
</div>
<div class="hLh30 txtOf tac">
<span class="fsize14 c-999">具备深厚的数学思维功底、丰富的小学教育经验,授课风格生动活泼,擅长用形象生动的比喻帮助理解、简单易懂的语言讲解难题,深受学生喜欢</span>
</div>
<div class="mt15 i-q-txt">
<p class="c-999 f-fA">毕业于师范大学数学系,热爱教育事业,执教数学思维6年有余</p>
</div>
</section>
</li>
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="唐嫣" target="_blank">
<img src="~/assets/photo/teacher/1442297957332.jpg" alt>
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="唐嫣" target="_blank" class="fsize18 c-666">唐嫣</a>
</div>
<div class="hLh30 txtOf tac">
<span class="fsize14 c-999">。。。。。。。。</span>
</div>
<div class="mt15 i-q-txt">
<p class="c-999 f-fA">中国人民大学附属中学数学一级教师</p>
</div>
</section>
</li>
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="周杰伦" target="_blank">
<img src="~/assets/photo/teacher/1442297969808.jpg" alt>
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="周杰伦" target="_blank" class="fsize18 c-666">周杰伦</a>
</div>
<div class="hLh30 txtOf tac">
<span class="fsize14 c-999">中教一级职称。讲课极具亲和力。</span>
</div>
<div class="mt15 i-q-txt">
<p class="c-999 f-fA">毕业于北京大学数学系</p>
</div>
</section>
</li>
<li>
<section class="i-teach-wrap">
<div class="i-teach-pic">
<a href="/teacher/1" title="陈伟霆" target="_blank">
<img src="~/assets/photo/teacher/1442297977255.jpg" alt>
</a>
</div>
<div class="mt10 hLh30 txtOf tac">
<a href="/teacher/1" title="陈伟霆" target="_blank" class="fsize18 c-666">陈伟霆</a>
</div>
<div class="hLh30 txtOf tac">
<span
class="fsize14 c-999"
>心理学博士、管理学博士后,北京师范大学马克思主义学院副教授。多年来总结出了一套行之有效的应试技巧与答题方法,针对性和实用性极强,能帮助考生在轻松中应考,在激励的竞争中取得高分,脱颖而出。</span>
</div>
<div class="mt15 i-q-txt">
<p class="c-999 f-fA">考研课程讲授和考研命题趋势与应试对策研究。考研辅导新锐派的代表。</p>
</div>
</section>
</li>
</ul>
<div class="clear"></div>
</article>
</div>
<!-- 公共分页 开始 -->
<div>
<div class="paging">
<!-- undisable这个class是否存在,取决于数据属性hasPrevious -->
<a href="#" title="首页">首</a>
<a href="#" title="前一页"><</a>
<a href="#" title="第1页" class="current undisable">1</a>
<a href="#" title="第2页">2</a>
<a href="#" title="后一页">></a>
<a href="#" title="末页">末</a>
<div class="clear"></div>
</div>
</div>
<!-- 公共分页 结束 -->
</section>
</section>
<!-- /讲师列表 结束 -->
</div>
</template>
<script>
export default {};
</script>
讲师列表页
后端开发
前端开发
测试
讲师详情页
动态路由实现
在详情页我们要查看讲师信息,课程信息
所以后端就两个接口,一个根据路径中的参数查询讲师信息
一个来查询讲师所讲的课程信息
效果如下:
根据讲师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);
}
前端开发
<template>
<div id="aCoursesList" class="bg-fa of">
<!-- 讲师介绍 开始 -->
<section class="container">
<header class="comm-title">
<h2 class="fl tac">
<span class="c-333">讲师介绍</span>
</h2>
</header>
<div class="t-infor-wrap">
<!-- 讲师基本信息 -->
<section class="fl t-infor-box c-desc-content">
<div class="mt20 ml20">
<section class="t-infor-pic">
<img :src="teacher.avatar">
</section>
<h3 class="hLh30">
<span class="fsize24 c-333">{{teacher.name}}
{{ teacher.level===1?'高级讲师':'首席讲师' }}
</span>
</h3>
<section class="mt10">
<span class="t-tag-bg">{{teacher.intro}}</span>
</section>
<section class="t-infor-txt">
<p
class="mt20">{{teacher.career}}</p>
</section>
<div class="clear"></div>
</div>
</section>
<div class="clear"></div>
</div>
<section class="mt30">
<div>
<header class="comm-title all-teacher-title c-course-content">
<h2 class="fl tac">
<span class="c-333">主讲课程</span>
</h2>
<section class="c-tab-title">
<a href="javascript: void(0)"> </a>
</section>
</header>
<!-- /无数据提示 开始-->
<section class="no-data-wrap" v-if="courseList.length==0">
<em class="icon30 no-data-ico"> </em>
<span class="c-666 fsize14 ml10 vam">没有相关数据,小编正在努力整理中...</span>
</section>
<!-- /无数据提示 结束-->
<article class="comm-course-list">
<ul class="of">
<li v-for="course in courseList" :key="course.id">
<div class="cc-l-wrap">
<section class="course-img">
<img :src="course.cover" class="img-responsive" >
<div class="cc-mask">
<a href="#" title="开始学习" target="_blank" class="comm-btn c-btn-1">开始学习</a>
</div>
</section>
<h3 class="hLh30 txtOf mt10">
<a href="#" :title="course.title" target="_blank" class="course-title fsize18 c-333">{{course.title}}</a>
</h3>
</div>
</li>
</ul>
<div class="clear"></div>
</article>
</div>
</section>
</section>
<!-- /讲师介绍 结束 -->
</div>
</template>
<script>
import teacherApi from '@/api/teacher'
export default {
//params.id获取路径id值
asyncData({ params, error }) {
return teacherApi.getTeacherInfo(params.id)
.then(response => {
return {
teacher: response.data.data.teacher,
courseList: response.data.data.courseList
}
})
}
};
</script>