一、单体应认证
在传统的单体应用中,用户的认证过程非常简单,cookie保存在用户自己的浏览器本地,session保存在服务器本地,只要在各自设定的有效期内,都能便捷的实现随取随用。
但在微服务架构中将变得不在那么容易,微服务本着服务自治的理念,服务被拆分为多个单体服务,并将这些不同的服务运行在不同的主机上,而且有时候由于高并发的需求,某个服务可能部署了多个实例,这些服务都需要进行用户的认证以及权鉴;
二、微服务会话共享
1、方案一
如图电商的微服务中,有专为用户认证提供的认证服务-----认证中心
用户通过网关访问认证中心,在认证中心中,进行用户认证以及权鉴,通过后生成session,以及cookie,cookie随响应返回给用户,保存在用户的浏览器上,而session将被同步到微服务集群中的每一个实例上,用户下次访问是携带cookie将可以访问任意一个服务
- 优点:
该同步很简单不需要大量的代码,只需在Tomcat配置文件中添加相应的配置即可 - 缺点:
在用户量比较大时,需要同步大量的数据,并且造成系统的数据的大量冗余,而且维护这么多数据的一致性等,浪费大量的系统资源
注意:
在添加返回cookie时,必须保证该cookie可以共享在域名的所有子域中并且作用的路径为/
否则不能访问其他服务
1、什么是子域
如:taobao.com为根
那么:
—— pay.taobao.com
—— member.taobao.com
—— wuliu.taobao.com
都为taobao.com的子域
所以要将cookie的作用域提高到taobao.com上,才能共享到各个子域,将作用路径设置为/
,在访问时才会被请求带上
Cookie cookie = new Cookie("Tocken",tocken);
cookie.setDomain("taobao.com");
cookie.setPath("/");
response.addCookie(cookie);
方案二
spring cloud为我们提供了较为简单的解决方案----springSession + redis来实现session的全局共享,数据只需要保存一份,便可全局访问
用户认证通过之后,将数据保存在redis内存数据库中,用户会访问时将携带的cookie带到服务后,从redis中查找session,获取用户的信息
spring-session使用
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>
2、application.yml配置
spring:
application:
name: gulimail-member
cloud:
nacos:
discovery:
server-addr: http://192.168.244.10:8848
thymeleaf:
cache: false
redis:
host: 192.168.244.10
port: 6379
session:
store-type: redis
前提安装了redis服务
业务代码
登录
public String toLogin(AuthUser authUser, HttpServletResponse response,HttpSession session){
User user = userServer.AuthUserLogin(authUser);
if (user == null){
return "redirect:/login/login";
}
String tocken = user.getPassWord();
redisTemplate.opsForValue().set("Tocken",tocken);
Cookie cookie = new Cookie("Tocken",tocken);
cookie.setDomain("taobao.com");
cookie.setPath("/");
response.addCookie(cookie);
session.setAttribute("user",user);
return "redirect:/main";
}
登录后访问其他服务的主页
@GetMapping("/main")
public String main(HttpSession session, Model model,@CookieValue(value = "Tocken",required = false)String Tocken){
String redistocken = (String) redisTemplate.opsForValue().get("Tocken");
if(redistocken!=null && redistocken.equals(Tocken)){
model.addAttribute("user",session.getAttribute("user"));
return "main";
}
return "redirect:/login/login";
}
在将user保存在redis时必须要实例化,user实现实例化接口
@Data
public class User implements Serializable {
private String Id;
private String UserName;
private String PassWord;
private String Sex;
private Date BrithDay;
private String Avatar;
private String Iphone;
private String WeChart;
private String address;
private String IdentityNumber;
}
spring-session的配置类
@Configuration
public class SpringSessionConfig {
@Bean
public CookieSerializer cookieSerializer(){
DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
defaultCookieSerializer.setDomainName("taobao.com");
defaultCookieSerializer.setCookieName("TAOBAO");
return defaultCookieSerializer;
}
@Bean
public RedisSerializer<Object> redisSerializer(){
return new GenericJackson2JsonRedisSerializer();
}
}
便可实现会话的共享与单点登录
上述代码中设置了两个cookie,前一个是本人在测试单点登录时编写,其实会话共享和单点登录使用一个springSession的cookie即可。
springSession原理
springSession其实是使用拦截器对HttpServletRequest和HttpServletResponse进行了分装,将具体的业务逻辑进行了替换而已
分析源码,在拦截器中访问了redis数据库将HttpSession中的数据进行了更新
在每个使用springSession的服务中都要导入上述依赖和配置。
单点登录方案
所谓的单点登录就是一处认证通过,其他服务皆放行
认证后将cookie发给用户,session实现共享,用户带着cookie即可访问任意服务
上述会话共享方案就是单点登录的雏形。