上一章节讲了【SpringBoot项目之基于Cookie传输sessionId的分布式会话解决方案(三)】,但是若是某些网站禁用了浏览器的cookie,我们的cookie方案就不能生效了,其实现在很多流行的互联网行业的网站都是基于token来实现分布式会话的,下面我们来看一下具体是如何实现的
1)依然是首先项目集成引入配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
2)新建一个配置,这个配置用来做我们redis的定制化的开发,例如自定义设置session的过期时间等等,这里我们先不做具体实现,所以先空着:
@Component
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
public class RedisConfig {
}
3)配置文件我们需要修改,但是因为我们之前讲解一直在使用外挂配置文件的方式,所以这一块的配置得存放到两个服务器项目的【application.properties】中。下面是具体的配置内容:
#配置springboot对redis的依赖
spring.redis.host=192.168.124.34
spring.redis.port=6379
spring.redis.database=0
spring.redis.lettuce.pool.max-active=10000
spring.redis.jedis.pool.max-idle=50
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.lettuce.pool.min-idle=0
spring.redis.password=
#设置jedis连接池
spring.redis.jedis.pool.max-active=50
spring.redis.jedis.pool.min-idle=20
这里我们依然使用了192.168.124.34这台服务器作为redis的服务器
上图是我们的服务架构,简单回顾
4)对我们服务器安装好的redis做出如下修改:
我们安装好redis之后,【redis.conf】需要做一下简单修改:
a.将原来的 bind 127.0.0.1 修改为: bind 192.168.124.34
b.将原来的 protected-mode yes 修改为 protected-mode no
5)我们的用户登陆是如何实现的
引入我们操作redis的操作类
@Autowired
private RedisTemplate redisTemplate;
然后实现我们的login方法 ,下面是部分代码:
/**
* 基于token实现
*/
//用户登陆服务,用来校验用户登陆是否合法
UserModel userModel = userService.validateLogin(telphone,this.EncodeByMd5(password));
//修改成若用户登录验证成功后将对应的登录信息和登录凭证一起存入redis中
//生成登录凭证token,UUID
String uuidToken = UUID.randomUUID().toString();
//建立token和用户登陆态之间的联系
redisTemplate.opsForValue().set(uuidToken,userModel);
//设置过期时间
redisTemplate.expire(uuidToken,1, TimeUnit.HOURS);
return CommonReturnType.create(uuidToken);
核心思想便是首先验证我们的登陆账号和密码,验证通过之后,然后我们利用UUID生成token
建立用户态和生成token之间的联系,然后借助redisTemplate存储到redis中,并设置过期时间。
6)前端页面的实现,在我们的【login.html】页面,获取到后台返回的token,存储到localStroage中,核心代码如下:
success:function(data){
if(data.status == "success"){
alert("登陆成功");
var token = data.data;
window.localStorage["token"] = token;
window.location.href="listitem.html";
}else{
alert("登陆失败,原因为"+data.data.errMsg);
}
},
7)然后当我们在商品页面下单的时候,需要用到这个存储在localStroage中的token,我们获取到之后携带到后台,部分代码如下:
$("#createorder").on("click",function(){
var token = window.localStorage["token"];
if(token == null){
alert("没有登录,不能下单");
window.location.href="login.html";
return false;
}
$.ajax({
type:"POST",
contentType:"application/x-www-form-urlencoded",
url:"http://"+g_host+"/order/createorder?token="+token,
data:{
"itemId":g_itemVO.id,
"amount":1,
"promoId":g_itemVO.promoId
},
xhrFields:{withCredentials:true},
success:function(data){
if(data.status == "success"){
alert("下单成功");
window.location.reload();
}else{
alert("下单失败,原因为"+data.data.errMsg);
if(data.data.errCode == 20003){
window.location.href="login.html";
}
}
},
注意我们的url , url:"http://"+g_host+"/order/createorder?token="+token, 是携带了获取到的token去请求后台下单方法的
8)调用到后台方法,我们拿到token首先校验是否为空,若不为空再去redis进行校验,若存在此token对应的用户就可以下单,若不存在提示用户未登录,核心部分代码如下:
String token = httpServletRequest.getParameterMap().get("token")[0];
if(StringUtils.isEmpty(token)){
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN,"用户还未登陆,不能下单");
}
//获取用户的登陆信息
UserModel userModel = (UserModel) redisTemplate.opsForValue().get(token);
if(userModel == null){
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN,"用户还未登陆,不能下单");
}
9)然后是我们的项目打包,重启之后整个的演示
首先访问我们的nginx服务器登陆
http://192.168.124.35/resources/login.html
登陆成功之后我们查看一下浏览器中是否存储了我们的token
token存储成功
然后查看我们的redis是否存储成功我们的键值对(key对应token,value对应userModel)
存储成功
然后我们进行下单操作
提示下单成功,至此我们的SpringBoot项目基于Token的分布式会话解决方案介绍完毕。