持续学习&持续更新中...
守破离
【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【20】认证服务04---SSO单点登录
xxl-sso
https://gitee.com/xuxueli0323/xxl-sso
xxl-sso是开源的一个单点登录框架
一个分布式单点登录框架。只需要登录一次就可以访问所有相互信任的应用系统。 拥有"轻量级、分布式、跨域、Cookie+Token均支持、Web+APP均支持"等特性;。现已开放源代码,开箱即用。
C:\Windows\System32\drivers\etc\hosts(模仿三个域名)
#模拟单点登录
127.0.0.1 xxlssoserver.com
127.0.0.1 client1.com
127.0.0.1 client2.com
打包之前修改这三个的配置文件:
举例:修改客户端:
修改完成打包命令:(打包所有)
启动服务器
启动两个客户端:
自己测试:
bash
C:\Users\lenovo\Desktop\xxl-sso\xxl-sso-server\target>java -jar xxl-sso-server-1.1.1-SNAPSHOT.jar
bash
C:\Users\lenovo\Desktop\xxl-sso\xxl-sso-samples\xxl-sso-web-sample-springboot\target>java -jar xxl-sso-web-sample-springboot-1.1.1-SNAPSHOT.jar --server.port=13000
bash
C:\Users\lenovo\Desktop\xxl-sso\xxl-sso-samples\xxl-sso-web-sample-springboot\target>java -jar xxl-sso-web-sample-springboot-1.1.1-SNAPSHOT.jar --server.port=12000
http://xxlssoserver.com:8080/xxl-sso-server/login
http://client1.com:12000/xxl-sso-web-sample-springboot/
http://client2.com:13000/xxl-sso-web-sample-springboot/
上面这三个地址,无论访问哪个都要求登录,并且一处登录,处处可用
多系统-单点登录
Single Sign On 一处登陆、处处可用(运行)
单点登录流程原理图
单点登录流程简单实现
认证服务:ssoserver.com:8080
java
@Controller
public class LoginController {
@Autowired
StringRedisTemplate redisTemplate;
/**
* TODO 开放接口给其他系统,让它们用来查询 token 对应的用户信息,判断该用户是否登录过,实现单点登录
*/
@ResponseBody
@GetMapping("/userInfo")
public String userInfo(@RequestParam("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("/doLogin")
public String doLogin(@RequestParam("username") String username,
@RequestParam("password")String password,
@RequestParam("url")String url,
HttpServletResponse response){
// 假设用户名密码不为空就登录成功
if(!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)){
//把登录成功的用户存起来。
String uuid = UUID.randomUUID().toString().replace("-","");
redisTemplate.opsForValue().set(uuid,username);
// 给浏览器留下登录痕迹
Cookie sso_token = new Cookie("sso_token",uuid);
response.addCookie(sso_token);
//登录成功,跳回之前页面,并带上token
return "redirect:"+url+"?token="+uuid;
}
//登录失败,展示登录页
return "login";
}
}
客户端1:client1.com:8081
java
@Controller
public class HelloController {
@Value("${sso.server.url}")
String ssoServerUrl;
/**
* 无需登录就可访问
* @return
*/
@ResponseBody
@GetMapping("/hello")
public String hello(){
return "hello";
}
/**
* TODO 如下判断,可以抽取出来放在一个Filter中,放在任何系统中,实现单点登录
*/
/**
* 感知这次是在 ssoserver 登录成功跳回来的。
* @param model
* @param session
* @param token 只要去ssoserver登录成功跳回来就会带上
* @return
*/
@GetMapping("/employees")
public String employees(Model model, HttpSession session,
@RequestParam(value = "token",required = false) String token){
//
if(!StringUtils.isEmpty(token)){
//TODO 应该去ssoserver获取当前token真正对应的用户信息
// 如果我们并不知道ssoserver的redis地址,也就是说客户端并不知道认证服务器将用户信息保存在哪里
// 我们就得用令牌去认证服务器再查一次用户信息,查询用户信息成功,表明登录成功
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){
//没登录,跳转到登录服务器进行登录
//跳转过去以后,使用url上的查询参数标识我们自己是哪个页面
//redirect_url=http://client1.com:8080/employees
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";
}
}
}
客户端2:client1.com:8082
java
@Controller
public class HelloController {
@Value("${sso.server.url}")
String ssoServerUrl;
@GetMapping("/boss")
public String boss(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> boss = new ArrayList<>();
boss.add("666");
boss.add("777");
model.addAttribute("boss",boss);
return "list";
}
}
}
参考
雷丰阳: Java项目《谷粒商城》Java架构师 | 微服务 | 大型电商项目.
本文完,感谢您的关注支持!