首先我创建了一个SpringCloud项目,项目分层分别如下:
其中sso_common是公共调用模块~
创建前台,后台的重定向跳转,前台页面滤过。。。
首先测试一下,在首页点登录是否能够正常跳到登陆页面(这里携带了本次路径的参数)
而这里重点说下后台的写法,首先是需要在后台的viewcontroller层重定向跳转页面的:
//跳转到登录页面//@RequestParam(required = false,defaultValue = "" 这个参数可能不存在,就定义为空@GetMapping("/login")public String login(@RequestParam(required = false,defaultValue = "") String target,HttpSession session){ if (StringUtils.isEmpty(target)){ target="http://127.0.0.1:9010";//跳转到首页 } //这里还是需要做地址的校验的额 session.setAttribute("target",target);//存在session中 return "login";}
5.这时候session中就有target的值了,接下来在点击登录按钮的时候触发form表单中的post请求,跳到登录的Controller层:
@PostMappingpublic String Login(User user,HttpSession session){ String target = (String) session.getAttribute("target"); //模拟一下登录 Optional first = dbuser.stream().filter(dbuser -> dbuser.getUsername().equals(user.getUsername()) && dbuser.getPassword().equals(user.getPassword())).findFirst(); //判断first里面是否有值 if(first.isPresent()){ //随机生成一个token String token = UUID.randomUUID().toString(); //保存用户的信息 LoginCacheUtil.logionUser.put(token,first.get()); }else { //登陆失败 session.setAttribute("msg","登陆失败,或是密码错误~~啦啦啦"); return "login"; } //重定向到target页面中去 return "redirect:"+target;}
6.解释一下这里的LoginCacheUtil.logionUser它是一个自己定义的工具类,把登录的信息存到了一个map中
package com.sso.login.util;import com.sso.login.pojo.User;import java.util.HashMap;import java.util.Map;/** * @Author:dada * @Date:2020/10/31 19:01 * @Version 1.0 *///保存用户信息public class LoginCacheUtil { public static Map logionUser = new HashMap<>();}
7.声明一下dbuser模拟一下数据库的数据
//模拟一下数据库中的数据private static Setdbuser;static { dbuser=new HashSet<>(); dbuser.add(new User(0,"zhangsan","12345")); dbuser.add(new User(1,"lisi","123456")); dbuser.add(new User(2,"wangwu","1234567"));}
8.然后在方法中定义一个HttpServletResponse参数,作为相应给浏览器
Cookie cookie = new Cookie("TOKEN", token);
9.cookie要在系统中之间互相访问,这时候他们的域就应该是一样的
cookie.setDomain("127.0.0.1")//相应出去response.addCookie(cookie);
10.完整的login的接口:
@PostMappingpublic String Login(User user, HttpSession session, HttpServletResponse response){ String target = (String) session.getAttribute("target"); //模拟一下登录 Optional first = dbuser.stream().filter(dbuser -> dbuser.getUsername().equals(user.getUsername()) && dbuser.getPassword().equals(user.getPassword())).findFirst(); //判断first里面是否有值 if(first.isPresent()){ //随机生成一个token String token = UUID.randomUUID().toString(); //然后方法中定义一个HttpServletResponse参数,然后让response相应出去 Cookie cookie = new Cookie("TOKEN", token); //cookie要在子系统之间互相访问的话他们的域需要一样的 cookie.setDomain("127.0.0.1"); //相应出去 response.addCookie(cookie); //保存用户的信息 LoginCacheUtil.logionUser.put(token,first.get()); }else { //登陆失败 session.setAttribute("msg","登陆失败,或是密码错误~~啦啦啦"); return "login"; } //重定向到target页面中去 //return "redirect:"+target; return "/seccuss";}
11.通过token获取用户的信息接口,这里就是判断一下用户是否登陆过
//通过token获取用户的信息的接口,这里也就是来判断用户是否登录共过@GetMapping@ResponseBodypublic ResponseEntitygetUserInfo(String token){ //如果tiken不为空的话,说明已经登陆过了,有信息的话就返回回去 if (!StringUtils.isEmpty(token)){ User user = LoginCacheUtil.logionUser.get(token); return ResponseEntity.ok(user); }else { //为空的话就返回一个错误的请求 return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST); }}
12.为了在视图层跳转的规范,还应该在重定向的方法中加入一个Cookie的参数,这个参数可能有也可能没有:
//跳转到登录页面//@RequestParam(required = false,defaultValue = "" 这个参数可能不存在,就定义为空@GetMapping("/login")public String login(@RequestParam(required = false,defaultValue = "") String target,HttpSession session,@CookieValue(required = false,value="TOKEN") Cookie cookie){ if (StringUtils.isEmpty(target)){ target="http://127.0.0.1:9010";//跳转到首页 } //cookie不等于null就说明登录过了 if (cookie !=null){ String value = cookie.getValue();//获取到cookie的信息 User user = LoginCacheUtil.logionUser.get(value);//把这个cookie放到用户中去判段是否为空 if (user !=null){ return "/success"; } } //这里还是需要做地址的校验的额 session.setAttribute("target",target);//存在session中 return "login";}
在做到这个方案的时候有一个bug卡了我一个小时,必须记录下,在重定向跳转报错
org.thymeleaf.exceptions.TemplateInputException: Error resolving template [r
这里必须在重定向上加:return "redirect:"+返回路径,记得带冒号;
13.接下来测试,当一个服务的模块登陆成功之后,其他模块点击登录就直接显示登陆成功的页面;
14.然后继续优化,在main服务中,显示登录的信息,首先在启动类的容器中,这个注入是在调用其他服务的时候需要用到这个@Bean,把它放到SpringMVC中去~
@Beanpublic RestTemplate restTemplate(){ return new RestTemplate();}
15.然后在用到它的地方注入进来就可以了~~
//注入进来@AutowiredRestTemplate restTemplate;
16.然后再main的服务中的index重定向方法的参数中加上浏览器中的用户信息,@CookieValue(required = false,value = "TOKEN")解释一下它,这个获取cookie中的信息是必须的,因为在没有登陆的时候就是null,登陆过后就是有用户信息的了~
@CookieValue(required = false,value = "TOKEN") Cookie cookie
17.需要定义一个静态的访问远程服务的url,这个接口就是login服务中的接口,需要通过刚刚注入进来的restTemplate去获取这个路径
private final String LOGIN_INFO_TOKEN = "http://127.0.0.1:9000/login/info?token=";
18.最终如下:
package com.sso.main.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.CookieValue;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.client.RestTemplate;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.util.Map;/** * @Author:dada * @Date:2020/10/31 18:20 * @Version 1.0 */@Controller@RequestMapping("view")public class ViewController { //注入进来 @Autowired RestTemplate restTemplate; private final String LOGIN_INFO_TOKEN = "http://127.0.0.1:9000/login/info?token="; @GetMapping("/index") public String index(@CookieValue(required = false,value = "TOKEN") Cookie cookie, HttpSession session){ if (cookie!=null){ String token = cookie.getValue(); if (!StringUtils.isEmpty(token)){ //如果有信息的话去调用9000端口的服务,返回类型最后一个是个Map.class,不能用new Map,这里我们拿到了登录的信息 Map result = restTemplate.getForObject(LOGIN_INFO_TOKEN + token, Map.class); //拿到信息之后把登录的信息存到session中,保存完之后就去html页面展示吧~~ session.setAttribute("loginUser",result); } } return "/index"; }}
这是一个main的服务模块到这里就结束了,其他模块的代码也跟这个一样了,略微的需要修改一下,最终的效果就是在其中一个模块中登录了,其他的几个服务模块刷新之后就自动登录了~总结原理:就是所有服务模块跑起来之后,在某一个项目中登录了,需要把登陆人的信心保存到cookie中,然后在另几个服务模块中刷新就相当于重新请求后台接口,在请求的时候再次调用cookie里面的信息,根据前面定义的UUID去cookie中查询用户的信息(账号密码),如果存在,就代表已经登录过了,前提需要这些服务的域是一样的,比如我的网站dd16888.cn就都要以这个主域名看齐,不能出现其他的域名~
以上是我的个人笔记,探索未知密宝,记录学习笔记,分享有趣的故事,欢迎大家来访!