单点登录
・
・
单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
・
・
・
主要思想、主要解决的问题(适用于下面实例中)
・
1、给登录服务器留下登录痕迹
・
2、登录服务器要将token信息重定向的时候,带到url地址上
・
3、其他系统要处理url地址上的关键token,只要有,将token对应的用户保存到自己的session中
・
4、自己系统将用户保存在自己的会话中
・
・
・
・
实例演示:
・
前期准备:
建立三个微服务:
1、ssoserver
2、client1
3、client2
host域名映射:
127.0.0.1 ssoserver.com
127.0.0.1 client1.com
127.0.0.1 client2.com
client1:创建Controller类
・
@Controller
public class HelloController {
@Value("${sso.server.url}")
String ssoServerUrl;
@ResponseBody
@GetMapping(value = "/hello")
public String hello() {
return "hello";
}
@GetMapping("/employees")
public String employees(Model model, HttpSession session, @RequestParam(value = "token", required = false) String token) {
if (!StringUtils.isEmpty(token)) {
RestTemplate restTemplate=new RestTemplate();
ResponseEntity<String> forEntity = restTemplate.getForEntity("http://ssoserver.com:8080/userinfo?token=" + token,String.class);
String body = forEntity.getBody();
session.setAttribute("loginUser", body);
}
Object loginUser = session.getAttribute("loginUser");
if (loginUser == null) {
return "redirect:" + ssoServerUrl+"?redirect_url=http://client1.com:8081/employees";
} else {
List<String> emps = new ArrayList<>();
emps.add("张三");
emps.add("李四");
model.addAttribute("emps", emps);
return "list";
}
}
}
・
ssoServerUrl: 的值是 http://ssoserver.com:8080/login.html
・
当client1访问employees时 employees方法就会进行判断用户是否登录( Object loginUser = session.getAttribute(“loginUser”); 从session中查有loginUser值没有),如果没有登录则重定向到ssoserver服务进行登录操作并带上此次请求的地址方便ssoserver登录完成后返回到client1微服务。
・
・
client2:创建Controller类
・
@Controller
public class HelloController {
@Value("${sso.server.url}")
String ssoServerUrl;
@ResponseBody
@GetMapping(value = "/hello")
public String hello() {
return "hello";
}
@GetMapping(value = "/boss")
public String employees(Model model, HttpSession session, @RequestParam(value = "token", required = false) String token) {
if (!StringUtils.isEmpty(token)) {
RestTemplate restTemplate=new RestTemplate();
ResponseEntity<String> forEntity = restTemplate.getForEntity("http://ssoserver.com:8080/userinfo?token=" + token, String.class);
String body = forEntity.getBody();
session.setAttribute("loginUser", body);
}
Object loginUser = session.getAttribute("loginUser");
if (loginUser == null) {
return "redirect:" + ssoServerUrl+"?redirect_url=http://client2.com:8082/boss";
} else {
List<String> emps = new ArrayList<>();
emps.add("张三");
emps.add("李四");
model.addAttribute("emps", emps);
return "list";
}
}
}
・
ssoserver微服务
・
@Controller
public class LoginController {
@Autowired
StringRedisTemplate redisTemplate;
//根据token查询用户信息
@ResponseBody
@GetMapping("/userinfo")
public String userinfo(@RequestParam(value = "token") String token) {
String s = redisTemplate.opsForValue().get(token);
return s;
}
@GetMapping("/login.html")
public String loginPage(@RequestParam("redirect_url") String url, Model model, @CookieValue(value = "sso_token", required = false) String sso_token) {
if (!StringUtils.isEmpty(sso_token)) {
return "redirect:" + url + "?token=" + sso_token;
}
model.addAttribute("url", url);
return "login";
}
@PostMapping(value = "/doLogin")
public String doLogin(@RequestParam("username") String username,
@RequestParam("password") String password,
@RequestParam("redirect_url") String url,
HttpServletResponse response) {
//登录成功跳转,跳回到登录页
if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {
String uuid = UUID.randomUUID().toString().replace("_", "");
//把用户信息存在redis中
redisTemplate.opsForValue().set(uuid, username);
Cookie sso_token = new Cookie("sso_token", uuid);
//留下用户登录成功的痕迹,将用户登录成功生成的token利用Cookie保存在ssoserver.com:8080 这个域名下,以后浏览器在访问这个域名就会带上这个Cookie
response.addCookie(sso_token);
return "redirect:" + url + "?token=" + uuid;
}
return "login";
}
}
・
当用户从client1因为没登录来到ssoserver时会先访问到 @GetMapping("/login.html")loginPage这个方法,这个方法会将用client1传来的自己的地址保存到url中,然后在返回到login.html登录页,这个url会随着登录页的提交一起提交到 @PostMapping(value = “/doLogin”)doLogin这个方法中,进入这个方法这里只要帐号和密码不为空就算登录成功(为了简便就用这个代替做查数据库判断是否有这个用户这一步操作了),只要帐号和密码不为空就生成uuid然后uuid作为key,username作用value存入redis,关键一步来了,
Cookie sso_token = new Cookie(“sso_token”, uuid);
response.addCookie(sso_token);
将用户登录成功生成的uuid存在cookie中保存在ssoserver.com域名中下,浏览器访问ssoserver.com就会自动带上这个cookie,这样当client2登录来到ssoserver.com就会自动带上这个cookie就在访问登录 @GetMapping("/login.html") loginPage这个方法的第一步
if (!StringUtils.isEmpty(sso_token)) {
return “redirect:” + url + “?token=” + sso_token;
}
这个方法就直接带上sso_token登录成功返回到client2中的/boss请求路径下。有了sso_token就能成功访问了。