SpringCloud系列——SSO 單點登錄
前言
作为分布式项目,单点登录是必不可少的,文本基于之前的的博客(猛戳:SpringCloud系列——Zuul 动态路由, 4、登录成功,sso-server生成accessToken,并作为key(用户名+时间戳,这里只是demo,正常项目的令牌应该要更为复杂)存到Redis,value值存用户id作为value(或者直接存储可暴露的部分用户信息也行)设置过期时间(我这里设置3分钟);设置cookie:new Cookie("accessToken",accessToken);,设置maxAge(60*3);、path("/"); 5、sso-server单点登录服务负责校验用户信息、获取用户信息、操作Redis缓存,提供接口,在eureka上注册 首先我们创建一个单点登录服务sso-server,并在eureka上注册(创建项目请参考之前的SpringCloud系列博客跟 SpringBoot系列——Redis) login.html 我们这里需要用到页面,要先maven引入thymeleaf 提供如下接口 引入feign,用于调用sso-server服务 创建SsoFeign.java接口 启动类加入@EnableFeignClients注解,否则启动会报错,无法注入SsoFeign对象 修改AccessFilter过滤逻辑,注入feign接口,用于调用sso-server检查Redis,修改run方法的过滤逻辑 修改配置文件,映射sso-server代理路径,超时时间与丢失cookie的解决 启动eureka、zuul-server、sso-server、config-server、myspringboot、springdatajpa(由两个应用组成,实现了ribbon负载均衡),记得启动我们的RabbitMQ服务和Redis服务! 刚开始,没有cookie且无Redis的情况下,浏览器访问 http://localhost:10010/myspringboot/feign/ribbon,被zuul-server拦截重定向到sso-server登录页面 开始登录校验,为了方便演示,我将密码的type改成text 登录失败,返回提示语 登录成功,重定向到之前的请求 cookie的值,以及过期时间 3分钟后我们再次访问 http://localhost:10010/myspringboot/feign/ribbon,cookie、Redis失效,需要从新登录 sso单点登录就记录到这里,这里只是实现了单机版的sso,以后在进行升级吧。 问题报错:我们在sso-server设置cookie后,在zuul-server的run方法里获取不到设置的cookie,去浏览器查看,cookie没有设置成功,Zuul丢失Cookie 解决方案:Zuul丢失Cookie的解决方案:https://blog.csdn.net/lindan1984/article/details/79308396 作者:huanzi-qch 出处:https://www.cnblogs.com/huanzi-qch/p/10249227.html 若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利. 代码编写
sso-server
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head>
<meta charset="UTF-8">
<title>登录页面</title></head><body>
<form action="/sso-server/sso/login" method="post">
<input name="url" type="hidden" th:value="${url}"/>
用户名:<input name="username" type="text"/>
密码:<input name="password" type="password"/>
<input value="登录" type="submit"/>
</form></body></html>
@RestController
@EnableEurekaClient
@SpringBootApplicationpublic class SsoServerApplication { public static void main(String[] args) {
SpringApplication.run(SsoServerApplication.class, args);
}
@Autowired private StringRedisTemplate template; /**
* 判断key是否存在 */
@RequestMapping("/redis/hasKey/{key}") public Boolean hasKey(@PathVariable("key") String key) { try { return template.hasKey(key);
} catch (Exception e) {
e.printStackTrace(); return false;
}
} /**
* 校验用户名密码,成功则返回通行令牌(这里写死huanzi/123456) */
@RequestMapping("/sso/checkUsernameAndPassword") private String checkUsernameAndPassword(String username, String password) { //通行令牌
String flag = null; if ("huanzi".equals(username) && "123456".equals(password)) { //用户名+时间戳(这里只是demo,正常项目的令牌应该要更为复杂)
flag = username + System.currentTimeMillis(); //令牌作为key,存用户id作为value(或者直接存储可暴露的部分用户信息也行)设置过期时间(我这里设置3分钟)
template.opsForValue().set(flag, "1", (long) (3 * 60), TimeUnit.SECONDS);
} return flag;
} /**
* 跳转登录页面 */
@RequestMapping("/sso/loginPage") private ModelAndView loginPage(String url) {
ModelAndView modelAndView = new ModelAndView("login");
modelAndView.addObject("url", url); return modelAndView;
} /**
* 页面登录 */
@RequestMapping("/sso/login") private String login(HttpServletResponse response, String username, String password, String url) {
String check = checkUsernameAndPassword(username, password); if (!StringUtils.isEmpty(check)) { try {
Cookie cookie = new Cookie("accessToken", check);
cookie.setMaxAge(60 * 3); //设置域// cookie.setDomain("huanzi.cn"); //设置访问路径
cookie.setPath("/");
response.addCookie(cookie); //重定向到原先访问的页面 response.sendRedirect(url);
} catch (IOException e) {
e.printStackTrace();
} return null;
} return "登录失败";
}
}
zuul-server
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@FeignClient(name = "sso-server", path = "/")public interface SsoFeign { /**
* 判断key是否存在 */
@RequestMapping("redis/hasKey/{key}") public Boolean hasKey(@PathVariable("key") String key);
}
@EnableZuulProxy
@EnableEurekaClient
@EnableFeignClients
@SpringBootApplicationpublic class ZuulServerApplication { public static void main(String[] args) {
SpringApplication.run(ZuulServerApplication.class, args);
}
@Bean public AccessFilter accessFilter() { return new AccessFilter();
}
}
/**
* Zuul过滤器,实现了路由检查 */public class AccessFilter extends ZuulFilter {
@Autowired private SsoFeign ssoFeign; /**
* 通过int值来定义过滤器的执行顺序 */
@Override public int filterOrder() { // PreDecoration之前运行
return PRE_DECORATION_FILTER_ORDER - 1;
} /**
* 过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型:
* public static final String ERROR_TYPE = "error";
* public static final String POST_TYPE = "post";
* public static final String PRE_TYPE = "pre";
* public static final String ROUTE_TYPE = "route"; */
@Override public String filterType() { return PRE_TYPE;
} /**
* 过滤器的具体逻辑 */
@Override public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletResponse response = ctx.getResponse(); //访问路径
String url = request.getRequestURL().toString(); //从cookie里面取值(Zuul丢失Cookie的解决方案:https://blog.csdn.net/lindan1984/article/details/79308396)
String accessToken = request.getParameter("accessToken"); for (Cookie cookie : request.getCookies()) { if ("accessToken".equals(cookie.getName())) {
accessToken = cookie.getValue();
}
} //过滤规则:cookie有令牌且存在于Redis,或者访问的是登录页面、登录请求则放行
if (url.contains("sso-server/sso/loginPage") || url.contains("sso-server/sso/login") || (!StringUtils.isEmpty(accessToken) && ssoFeign.hasKey(accessToken))) {
ctx.setSendZuulResponse(true);
ctx.setResponseStatusCode(200); return null;
} else {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401); //重定向到登录页面
try {
response.sendRedirect("http://localhost:10010/sso-server/sso/loginPage?url=" + url);
} catch (IOException e) {
e.printStackTrace();
} return null;
}
} /**
* 返回一个boolean类型来判断该过滤器是否要执行 */
@Override public boolean shouldFilter() { return true;
}
}
zuul.routes.sso-server.path=/sso-server/**zuul.routes.sso-server.service-id=sso-server
zuul.host.socket-timeout-millis=60000zuul.host.connect-timeout-millis=10000#Zuul丢失Cookie的解决方案:https://blog.csdn.net/lindan1984/article/details/79308396zuul.sensitive-headers=
测试效果
后记
共同學習,寫下你的評論
評論加載中...
作者其他優質文章