单点登录
单点登录的意思就是,我登录一个网站。这个网站包含在别的单点登录里面的系统。我都无需登录、可以直接访问。
想要实现这种效果,原理3点
-
我需要把用户信息放到一个全局对象里面,但是每个网站服务器不一样,所以我们应该放到mysql或者redis中,因为用户登录信息这种时效性。所以我们使用redis来作为session对象。
-
如果A网站登录了,我们访问B网站的时候,想要实现取到这个用户的信息,总要有个k去redis中取,不然B网站怎么知道是内个用户登录了呢?所以我们需要有个保存在浏览器中的对象。也就是cookie,我A网站登录的时候,我把用户信息放到redis中,我还需要把redis中的key 放到cookie中。这样去访问B网站的时候,我就可以通过浏览器保存的cookie对象直接从redis中查出来。从而实现单点登录。
-
我们要明白的事情就是 A ,B网站都是一个服务器,单点登录是另外一个服务器。
我们登录A或者B网站的时候,都会去判断是否用户登录,如果没有用户登录,我们需要直接通过访问到单点登录服务器,去进行登录操作,登录操作进行完毕,会把用户信息存放到redis中,同时会创建cookie对象。
然后完成登录后,会跳转到A 或者B网站。此时cookie中有数据,然后A服务器还需要通过cookie里面的key去单点登录服务器中拿到值,然后放到session对象中,登录就结束了。
上代码 服务器有client1(A),client2(B),sso(单点登录)
这块代码 A服务器
A B服务器代码都是一样的,大概流程 先去判断是否有token,第一次登陆指定没有,然后我们就会带着url跳转到单点登陆服务器中。
/**
* 需要登录状态访问
*/
@GetMapping(value = "/employees")
public String employees(Model model, HttpSession session,
@RequestParam(name = "token", required = false) String token) {
if (!StringUtils.isEmpty(token)) {
// 根据token去sso认证中心获取用户信息
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> entity = restTemplate.getForEntity("http://sso.com:8080/userinfo?token=" + token, String.class);
session.setAttribute("loginUser", entity.getBody());
}
Object loginUser = session.getAttribute("loginUser");
if (loginUser == null && token == null) {
// 未登录,跳转认证服务器登录
return "redirect:http://sso.com:8080/login.html?redirect_url=http://client1.com:8081/employees";
} else {
// 登录状态显示
List<String> emps = new ArrayList<>();
emps.add("张三");
emps.add("李四");
model.addAttribute("emps", emps);
return "employees";
}
}
这块代码 B服务器
@GetMapping(value = "/employees")
public String employees(Model model, HttpSession session,
@RequestParam(name = "token", required = false) String token) {
if (!StringUtils.isEmpty(token)) {
// 根据token去sso认证中心获取用户信息
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> entity = restTemplate.getForEntity("http://sso.com:8080/userinfo?token=" + token, String.class);
session.setAttribute("loginUser", entity.getBody());
}
Object loginUser = session.getAttribute("loginUser");
if (loginUser == null && token == null) {
// 未登录,跳转认证服务器登录
return "redirect:http://sso.com:8080/login.html?redirect_url=http://client2.com:8082/employees";
} else {
// 登录状态显示
List<String> emps = new ArrayList<>();
emps.add("张三");
emps.add("李四");
model.addAttribute("emps", emps);
return "employees";
}
下面是单点登录的代码
接下来的就是核心
我们进入会有两种情况
第一种
通过 @CookieValue(value = “sso_token”, required = false) String token 这个代码去判断。如果cookie里面没有值就说明我们是第一次登录。
首次登录。我们登录后回创建cookie对象和redis存放。
然后登录。
第二种,cookie里面有对象,我们直接带着cookie里面的值,也就是代码中的token。然后返回到当初服务器的方法,重新进行访问,这个时候方法中的token参数就有了值,这样就可以实现A B服务器的单点登录。
@Controller
public class LoginController {
@Autowired
StringRedisTemplate redisTemplate;
@ResponseBody
@GetMapping("/userinfo")
public String userInfo(@RequestParam("token") String token) {
String username = redisTemplate.opsForValue().get(token);
return username;
}
/**
* 访问登录页
* @param url 登录成功回调页
* @param sso_token cookie值
*/
@GetMapping(value = "/login.html")
public String login(@RequestParam("redirect_url") String url, Model model,
@CookieValue(value = "sso_token", required = false) String token) {
// 根据token获取用户信息
if (!StringUtils.isEmpty(token)) {
String username = redisTemplate.opsForValue().get(token);
if (!StringUtils.isEmpty(username)) {
// token正确,已登录状态,跳转回客户端【当前访问客户端共享了其他客户端的登录状态】
return "redirect:" + url + "?token=" + token;
}
}
// 不存在sso_token,未登录返回登录页,并将回调地址链路下传
model.addAttribute("url", url);
return "login";
}
/**
* 登录
* @param url 登录成功回调页
*/
@PostMapping(value = "/doLogin")
public String doLogin(String username, String password, String url,
Model model, HttpServletResponse response) {
if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {
// 登录成功,跳转回调页
String token = UUID.randomUUID().toString().replace("-", "");
// token作为key,用户信息作为value存入redis中
redisTemplate.opsForValue().set(token, username);
// 在sso.com域名下设置cookie,使得不同客户端访问单点登录时可以带上cookie值成功登录
Cookie cookie = new Cookie("sso_token", token);
response.addCookie(cookie);
return "redirect:" + url + "?token=" + token;
}
// 登录失败
model.addAttribute("url", url);
return "login";
}
}
瞎写的 看不懂拉倒