SSO单点登录—基于redis共享服务
传统登录
在传统的java项目登录验证机制只涉及到单系统,因此可以直接使用session或者cookie实现。(登录的流程是:用户填写用户名和密码信息登录,后台服务器判断用户信息是否正确;若信息正确,则存储用户信息到session或者cookie中(例如,存储用户名),后面该用户通过浏览器请求服务,服务器会通过session或者cookie中存储的用户信息,了解该用户已经登录并正常响应服务)
SSO单点登录
如今比较流行的分布式服务中,都是拥有若干个服务相互协助,完成一整个系统的工作。那么在分布式服务中,便会出现以下问题。
问题:
由于浏览器的同源策略(即相同协议、相同端口、相同域名),cookie无法在多个服务中共享用户信息(即当用户登录了一个服务,那么其他的服务是无法获取登录用户信息)。正是如此,便出现了sso单点登录。
解决方法:
sso单点登录需要解决两个方面问题:第一方面是多个服务共享登录用户信息;第二方面是一个用户在多个服务中的cookie信息相同。
一、多个服务共享登录用户信息:
我们可以将redis缓存作为一个单独的服务,通过key/value数据结构,用于存储登录后的用户信息,代码如下:
redis服务提供的接口:
@RestController
public class RedisServerController {
@Autowired
private RedisServerService redisServerService;
@RequestMapping("/get")
public String get(String key) {
Object o = redisServerService.get(key);
if (o != null) {
String value = String.valueOf(o);
return value;
}
return null;
}
@RequestMapping("/put")
public String put(String key, String value, long seconds) {
redisServerService.put(key, value, seconds);
return "ok";
}
}
redis服务的service实现类:
@Service
public class RedisServerServiceImpl implements RedisServerService {
@Autowired
private RedisTemplate redisTemplate;
@Override
public void put(String key, Object value, long seconds) {
redisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS);
}
@Override
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
}
其他服务可以通过远程调用,获取redis服务中的用户信息。通过这样的一个设计,用户登录后,将用户信息存储到redis共享服务中,其他服务可以共享redis中的用户信息。
二、一个用户在多个服务中的cookie信息相同:
正是由于浏览器的同源策略,使得多个服务无法像单体系统一样,很容易获取cookie中的信息,那么如何在多个服务中获取相同的信息呢,其实有几种方法可以解决这个问题,例如:让多个服务的父域名相同、使用nginx反向代理多个服务、使用网关路由转发等。本章主要讲述使用网关解决浏览器的跨域问题,代码如下:
网关路由信息配置(使用的是springcloud gateway网关):
server:
port: 9090
spring:
application:
name: sso-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
- id: sso-server
uri: http://localhost:8080
predicates:
- Path=/sso-server/**
filters:
- StripPrefix=1
- id: sso-client
uri: http://localhost:8081
predicates:
- Path=/sso-client/**
filters:
- StripPrefix=1
通过统一网关路由配置,等同于“欺骗”浏览器所有服务都位于“一个服务”中,可以解决浏览器跨域问题。