XXL-SSO 实现SSO单点登录

一、 概述:

本文旨在使用XXL-SSO开源架构 实现单点登录系统。

XXL-SSO 是一个分布式单点登录框架、只需要登录一次就可以访问所有相互信任的应用系统。

拥有”轻量级、分布式、跨域、Cookie+Token均支持、Web+APP均支持”等特性。现已开放源代码,开箱即用。

官网地址:分布式单点登录框架XXL-SSO

二、 准备:

  • 下载XXL-SSO

GitHub - xuxueli/xxl-sso: A distributed single-sign-on framework.(分布式单点登录框架XXL-SSO)
xxl-sso: 一个分布式单点登录框架。只需要登录一次就可以访问所有相互信任的应用系统。 拥有"轻量级、分布式、跨域、Cookie+Token均支持、Web+APP均支持"等特性;。现已开放源代码,开箱即用。

安装 xxl-sso-core-1.1.0.jar 到maven仓库:

mvn install:install-file -Dfile=D:/yourpath/xxl-sso-core-1.1.0.jar -DgroupId=com.xuxueli -DartifactId=xxl-sso-core -Dversion=1.1.0 -Dpackaging=jar

  • 安装redis、并启动...
  • 执行sql脚本:mysql创建用户表等相关操作,详细参考文末代码

三、实现单点登录服务端:

1)使用架构:

  1. springboot
  2. mybatisPlus  for mysql
  3. swagger
  4. xxl-sso

2)代码参考如下:

  •  pom.xml
        <!-- sso core -->
        <dependency>
            <groupId>com.xuxueli</groupId>
            <artifactId>xxl-sso-core</artifactId>
            <version>1.1.0</version>
        </dependency>
        <!-- jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>
  • XxlSsoConfig.java
    @Configuration
    public class XxlSsoConfig implements InitializingBean, DisposableBean {
    
        @Value("${xxl.sso.redis.address}")
        private String redisAddress;
    
        @Value("${xxl.sso.redis.expire.minite}")
        private int redisExpireMinite;
    
        @Override
        public void afterPropertiesSet() throws Exception {
            SsoLoginStore.setRedisExpireMinite(redisExpireMinite);
            SsoTokenLoginHelper.setRedisExpireMinite(redisExpireMinite);
            JedisUtil.init(redisAddress);
        }
    
        @Override
        public void destroy() throws Exception {
            JedisUtil.close();
        }
    
    }
  • 登录页初始化
    @RequestMapping(Conf.SSO_LOGIN)
    public String login(Model model, HttpServletRequest request, HttpServletResponse response) {

        // login check
        XxlSsoUser xxlUser = SsoWebLoginHelper.loginCheck(request, response);
        if (xxlUser != null) {
            // success redirect
            String redirectUrl = request.getParameter(Conf.REDIRECT_URL);
            if (redirectUrl != null && redirectUrl.trim().length() > 0) {

                String sessionId = SsoWebLoginHelper.getSessionIdByCookie(request);
                String redirectUrlFinal = redirectUrl + "?" + Conf.SSO_SESSIONID + "=" + sessionId;
                return "redirect:" + redirectUrlFinal;
            } else {
                return "redirect:/";
            }
        }
        // 查询账套(自定义查询)
        List<TSystemSob> sobs = sysUserService.qrySobLst();
        model.addAttribute("sobs", sobs);
        model.addAttribute("errorMsg", request.getParameter("errorMsg"));
        model.addAttribute(Conf.REDIRECT_URL, request.getParameter(Conf.REDIRECT_URL));
        return "login";
    }
  • 登录动作
@RequestMapping("/doLogin")
    public String doLogin(HttpServletRequest request,
                          HttpServletResponse response,
                          RedirectAttributes redirectAttributes,
                          @RequestParam String username,
                          @RequestParam String password,
                          @RequestParam Integer sob,
                          String ifRemember) {

        boolean ifRem = (ifRemember != null && "on".equals(ifRemember)) ? true : false;
        redirectAttributes.addAttribute(Conf.REDIRECT_URL, request.getParameter(Conf.REDIRECT_URL));
        // valid login
        TSysUser usr = sysUserMapper.qryOne(username, sob);
        if (usr == null) {
            redirectAttributes.addAttribute("errorMsg", "用户不存在!");
            return "redirect:/login";
        }
        if (!Md5Util.isMatchPassword(password.trim(), usr.getPassword())) {
            redirectAttributes.addAttribute("errorMsg", "用户名或密码错误!");
            return "redirect:/login";
        }
        // 1、make xxl-sso user
        XxlSsoUser xxlUser = new XxlSsoUser();
        xxlUser.setUserid(String.valueOf(usr.getAccount()));
        xxlUser.setUsername(usr.getRealName());
        xxlUser.setVersion(UUID.randomUUID().toString().replaceAll("-", ""));
        xxlUser.setExpireMinite(SsoLoginStore.getRedisExpireMinite());
        xxlUser.setExpireFreshTime(System.currentTimeMillis());

        // 2、make session id
        String sessionId = SsoSessionIdHelper.makeSessionId(xxlUser);
        // 3、login, store storeKey + cookie sessionId
        SsoWebLoginHelper.login(response, sessionId, xxlUser, ifRem, redisExpireMinite * 60);
        // 4、return, redirect sessionId
        String redirectUrl = request.getParameter(Conf.REDIRECT_URL);
        if (redirectUrl != null && redirectUrl.trim().length() > 0) {
            String redirectUrlFinal = redirectUrl + "?" + Conf.SSO_SESSIONID + "=" + sessionId;
            return "redirect:" + redirectUrlFinal;
        } else {
            return "redirect:/";
        }
    }
  • 退出登录
    @RequestMapping(Conf.SSO_LOGOUT)
    public String logout(HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirectAttributes) {
        // logout
        SsoWebLoginHelper.logout(request, response);
        // del sessionData
        removeStorageData(request);
        redirectAttributes.addAttribute(Conf.REDIRECT_URL, request.getParameter(Conf.REDIRECT_URL));
        return "redirect:/login";
    }
  • 登录页面( freemarker模板文件 
<form action="${request.contextPath}/doLogin">
        <div class="login-box-body">
            <p class="login-box-msg">统一认证中心</p>
            <div class="form-group has-feedback">
                <input type="text" name="username" class="form-control" placeholder="Please input username."
                       value="admin" maxlength="50">
                <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
            </div>
            <div class="form-group has-feedback">
                <input type="password" name="password" class="form-control" placeholder="Please input password."
                       value="123456" maxlength="50">
                <span class="glyphicon glyphicon-lock form-control-feedback"></span>
            </div>
            <div class="form-group">
                <select class="form-control input-s-sm inline" name="sob">
                    <#list sobs as ss>
                    <option value="${ss.id}">${ss.sobName}</option>
                    </#list>
                </select>
            </div>
            <#if errorMsg?exists>
                <p style="color: red;">${errorMsg}</p>
            </#if>
            <div class="row">
                <div class="col-xs-8">
                    <div class="checkbox icheck">
                        <label>
                            <input type="checkbox" name="ifRemember">记住密码
                        </label>
                    </div>
                </div><!-- /.col -->
                <div class="col-xs-4">
                    <input type="hidden" name="redirect_url" value="${redirect_url!''}"/>
                    <button type="submit" class="btn btn-primary btn-block btn-flat">Login</button>
                </div>
            </div>
        </div>
    </form>


四、实现客户端:

  • 配置文件
@Configuration
public class XxlSsoConfig implements DisposableBean {


    @Value("${xxl.sso.server}")
    private String xxlSsoServer;

    @Value("${xxl.sso.logout.path}")
    private String xxlSsoLogoutPath;

    @Value("${xxl.sso.excluded.paths}")
    private String xxlSsoExcludedPaths;

    @Value("${xxl.sso.redis.address}")
    private String xxlSsoRedisAddress;


    @Bean
    public FilterRegistrationBean xxlSsoFilterRegistration() {

        // xxl-sso, redis init
        JedisUtil.init(xxlSsoRedisAddress);

        // xxl-sso, filter init
        FilterRegistrationBean registration = new FilterRegistrationBean();

        registration.setName("XxlSsoWebFilter");
        registration.setOrder(1);
        registration.addUrlPatterns("/*");
        registration.setFilter(new XxlSsoWebFilter());
        registration.addInitParameter(Conf.SSO_SERVER, xxlSsoServer);
        registration.addInitParameter(Conf.SSO_LOGOUT_PATH, xxlSsoLogoutPath);
        registration.addInitParameter(Conf.SSO_EXCLUDED_PATHS, xxlSsoExcludedPaths);

        return registration;
    }

    @Override
    public void destroy() throws Exception {

        // xxl-sso, redis close
        JedisUtil.close();
    }

}
  • 首页跳转
    @RequestMapping("/")
    public String index(Model model, HttpServletRequest request) {

        XxlSsoUser xxlUser = (XxlSsoUser) request.getAttribute(Conf.SSO_USER);
        model.addAttribute("xxlUser", xxlUser);
        return "index";
    }

五、启动程序

启动顺序1. SSOServerApp、2.ClientApp

客户端port:8088

服务端port:8086

在浏览器地址栏输入:http://127.0.0.1:8088/client

完成跳转,如图

注:账套为本人自定义信息,可酌情删除。

用户名:admin   、密码:123456

登录成功:

六、备注:

以上即实现了xxl-sso架构的单点登录系统,由于架构较轻量,即功能性单一,不过扩展较方便。

本文在xxl-sso-core核心包中,做了几处简单修改,旨在实现登出跳转,打印log等功能,喜欢扩展的朋友可自行修改。


本文源码地址:

ym-paas-sso-xxl: 使用xxl-sso实现web单点登录系统、支持跨域、登录页支持多账套......   

ym-paas-commons

下载代码的朋友点下star,多谢支持

点赞本文,再次感谢

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该项目是采用目前比较流行的SpringBoot/SpringCloud构建微服务电商项目,项目叫 《果然新鲜》,实现一套串联的微服务电商项目。完全符合一线城市微服务电商的需求,对学习微服务电商架构,有非常大的帮助,该项目涵盖从微服务电商需求讨论、数据库设计、技术选型、互联网安全架构、整合SpringCloud各自组件、分布式基础设施等实现一套完整的微服务解决方案。 项目使用分布式微服务框架,涉及后台管理员服务、地址服务、物流服务、广告服务、商品服务、商品类别服务、品牌服务、订单服务 、购物车服务、首页频道服务、公告服务、留言服务、搜索服务、会员服务等。  系统架构图   SpringBoot+SpringCloud+SSM构建微服务电商项目使用SpringCloud Eureka作为注册中心,实现服务治理使用Zuul网关框架管理服务请求入口使用Ribbon实现本地负载均衡器和Feign HTTP客户端调用工具使用Hystrix服务保护框架(服务降级、隔离、熔断、限流)使用消息总线Stream RabbitMQ和 Kafka微服务API接口安全控制和单点登录系统CAS+JWT+OAuth2.0分布式基础设施构建分布式任务调度平台XXL-JOB分布式日志采集系统ELK分布式事务解决方案LCN分布式锁解决方案Zookeeper、Redis分布式配置中心(携程Apollo)高并发分布式全局ID生成(雪花算法)分布式Session框架Spring-Session分布式服务追踪与调用链Zipkin项目运营与部署环境分布式设施环境,统一采用Docker安装使用jenkins+docker+k8s实现自动部署微服务API管理ApiSwagger使用GitLab代码管理(GitHub  GitEE)统一采用第三方云数据库使用七牛云服务器对静态资源实现加速 开发环境要求JDK统一要求:JDK1.8Maven统一管理依赖 统一采用Docker环境部署编码统一采用UTF-8开发工具IDEA 或者 Eclipse 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值