SSO单点登录

1. 单独的登陆系统

有时候做微服务拆分的时候,登录注册会抽取出来单独做一个模块

2. 单点登录的架构

2.0 总体流程

  1. SSO服务有登陆注册功能,还有验证token的功能
  2. 除SSO服务外的服务都注册一个拦截器,拦截本服务的请求,如果检测到 URL 或者 Cookie 里有 token(说明SSO登录完了或者被伪造了token),就向SSO发送一个验证token的请求,验证成功就放行;验证失败就 重定向到SSO的登录页面(重定向的时候在URL后拼接本次被拦截的url-A)
// 例子
www.sso.com?service=www.c21w.cc.com
  1. SSO登录成功后,往redis中存放用户信息,然后给客户端颁发 token ,并按照url-A重定向到url-A请求
  2. 之后再次被拦截,去验证token

2.1 创建一个sso模块

2.1.1 创建登录注册页面以及对应的请求路径

请求接收的参数要包含url-A
请求中还要验证token的合法性,如果通过,就跳转url-A,如果没有通过,就跳转到SSO登陆页面

2.1.2 创建POST表单提交请求

请求接收的参数要包含url-A
请求中判断登陆成功就把 用户信息存放redis, 并且向客户端颁发token, 然后跳转url-A,否则跳转SSO登陆页面

流程图

流程图 2


java代码流程:

  • 如果url中有token参数,就去SSO验证token是否合法,合法就保存到cookie中,然后把token存入响应头之后放行
  • 如果cookie中有token参数,就去SSO验证token是否合法,合法就把token存入响应头之后放行。
  • 都不满足但是是不用允许通行的url,就放行
  • 都不满足就重定向到SSO去登录~~
@Order(-1)
@Component
public class AuthFilter implements GlobalFilter {

    @Value("${let.path}")
    private List<String> LET_PATH;

    @Autowired
    private UserFeignClient feignClient;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        // 获取token
        String cookieToken = Optional.ofNullable(exchange.getRequest().getCookies().get("token")).orElse(new ArrayList<>()).stream().map(s -> s.toString().split("=")[1]).findFirst().orElse(null);
        String paramToken = Optional.ofNullable(Optional.ofNullable(exchange.getRequest().getQueryParams().get("token")).orElse(new ArrayList<>()).stream().findFirst().orElse(null)).orElse(cookieToken);

        // 如果 paramToken 存在
        if(paramToken != null){
            boolean authToken = feignClient.authToken(paramToken);    //验证token
            if(authToken){    //如果通过 创建cookie并把token放入响应头
                ResponseCookie cookie = ResponseCookie.from("token",paramToken)
                        .maxAge(60*60)
                        .httpOnly(true)
                        .path("/")
                        .build();
                exchange.getResponse().addCookie(cookie);
                exchange.getResponse().getHeaders().set("token",paramToken);
                return chain.filter(exchange);  // 放行
            }
        }

        // 如果 cookieToken 存在
        if(cookieToken != null){
            boolean authToken = feignClient.authToken(cookieToken);    //验证token
            if(authToken){    //如果通过 把token放入响应头
                exchange.getResponse().getHeaders().set("token",cookieToken);
                return chain.filter(exchange);  // 放行
            }
        }

        // 如果是不用拦截的网址就放行
        long count = Optional.ofNullable(LET_PATH).orElse(new ArrayList<>()).stream().filter(s -> exchange.getRequest().getPath().toString().startsWith(s + "/")).count();
        if(count > 0)
            return chain.filter(exchange);


        // 重定向到SSO登录页面
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.SEE_OTHER);
        response.getHeaders().set("Location", "SSO服务地址");
        return exchange.getResponse().setComplete();
    }
}
posted @ 2022-01-15 18:13  一只小白的进修路  阅读(378)  评论(0编辑  收藏  举报