用户微服务单点登录
为什么要使用单点登录原理
链接:https://blog.csdn.net/weixin_45528987/article/details/105365115
架构图
看图可能还有点懵,下面贴过程与代码
第一步:在用户微服务下添加两个依赖
<!--jwt tokens生成工具-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>
<!--redis缓存工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
第二步:application.yml配置文件配置redis与jjwt的配置
redis:
host: 127.0.0.1
token_name: token
jwt:
config:
key: searchroom #jwt言
ttl: 360000 #jwt过期时间
用户登录时的代码逻辑
采用了手机号免注册的登录方式,当数据库中不存在此用户时创建用户,并且返回携带token的cookie。假如存在用户判断手机验证码是否正确,正确则返回token。其中token还要将token存入redis中。
代码中的一些只有变量名的名字即对应相对应的类。
/**
* 手机验证登录
* @param phone
* @param smsCode
* @return
*/
@Override
public ServiceResult loginByPhone(String phone, String smsCode, HttpServletRequest request){
ServiceResult result = new ServiceResult();
//当前时间
Date date = new Date();
User user = userMapper.selectByPhone(phone);
//如果没有这个用户就创建此用户
if (user == null && StringUtils.equals(smsCode, "123456")){
User userCreater = new User();
userCreater.setName(phone.substring(0,3)+"****"+phone.substring(7));
userCreater.setPhoneNumber(phone);
userCreater.setCreateTime(date);
userCreater.setLastUpdateTime(date);
userCreater.setLastLoginTime(date);
userMapper.regiestUser(userCreater);
return ServiceResult.seccess("登录成功", this.userIPAndSetRedis(userCreater, request));
}else {
//由于是手机号登录所以需要验证验证码
if (StringUtils.equals(smsCode, "123456")){
user.setLastLoginTime(date);
userMapper.updateByPrimaryKeySelective(user);
return ServiceResult.seccess("登录成功", this.userIPAndSetRedis(user, request));
}else{
result.setStatus(ServiceResult.Status.PARAMERROR.getCode());
result.setMessage("验证码不正确");
}
}
return result;
}
public String userIPAndSetRedis(User user, HttpServletRequest request){
//生成令牌
String token = jwtUtil.createJWT(String.valueOf(user.getId()), user.getPhoneNumber(), "");
//获取用户真实ip地址
String userIP = CusAccessObjectUtil.getIpAddress(request);
System.out.println(userIP);
//token存入redis中 key=token_userID
//可以通过此实现但设备登录与防止token盗用的情况
redisTemplate.opsForValue().set("token_"+user.getId(), userIP , 15, TimeUnit.MINUTES);
return token;
}
判断token是否过期或者存在盗用的风险
/**
* 检测token是否过期,或者存在被盗用的情况,单设备登录
* @param token
* @return
*/
@Override
public ServiceResult checkToken(String token,HttpServletRequest request) {
ServiceResult result = new ServiceResult();
if (StringUtils.isBlank(token)){
result.setStatus(ServiceResult.Status.PARAMERROR.getCode());
result.setMessage("不能传空参数");
return result;
}
try {
//获取用户真实ip地址
String userIP = CusAccessObjectUtil.getIpAddress(request);
Claims claims = jwtUtil.parseJWT(token);
Object value = redisTemplate.opsForValue().get("token_"+claims.getId());
//判断是否token盗用
if (!StringUtils.equals(String.valueOf(value), userIP)){
result.setStatus(ServiceResult.Status.EXCEPTION.getCode());
result.setMessage("token存在问题,请重新登录");
// User user = userMapper.selectByPrimaryKey(Integer.valueOf(claims.getId()));
// //短信通知用户他的登录地点方式可能存在风险
// rabbitTemplate.convertAndSend("sms", user.getPhoneNumber());
return result;
}
String username = claims.getSubject();
return ServiceResult.seccess(username);
}catch (Exception e){
e.printStackTrace();
result.setStatus(ServiceResult.Status.EXCEPTION.getCode());
result.setMessage("登录已过期");
return result;
}
}
登录成功后会自动跳转到首页的微服务工程的首页页面,看到前后域名会改变,cookie要注意不同域问题(跨域),这时候可以看到浏览器中存在名字为token的cookie。
我们浏览网站会发现,网站的域名是不会改变的,例如我们浏览开源中国,域名总为www.oschina.net,如何做到呢?
链接:
技术:https://blog.csdn.net/weixin_45528987/article/details/105385152
例子:https://blog.csdn.net/weixin_45528987/article/details/105392337