SSO单点登录实例

单点登录流程图

系统登陆拦截器

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.jdcloud.policycloudapi.sso;

import com.alibaba.fastjson.JSON;
import com.jdcloud.policycloudapi.domain.response.RetResponse;
import com.jdcloud.policycloudapi.domain.vo.LoginUser;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class SsoClientInterceptor implements HandlerInterceptor {
    private Logger log = LoggerFactory.getLogger(this.getClass());
    private SsoProperties ssoProperties;
    private RemoteService remoteService;
    public SsoClientInterceptor(SsoProperties ssoProperties, RemoteService remoteService) {
        this.ssoProperties = ssoProperties;
        this.remoteService = remoteService;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        String tokenParam = null;
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for(int i = 0; i < cookies.length; ++i) {
                if (cookies[i].getName().equals("gunsToken")) {
                    tokenParam = cookies[i].getValue();
                    break;
                }
            }
        }
        if(!StringUtils.isNotBlank(tokenParam)){
            tokenParam=request.getParameter("gunsToken");
        }


        if (StringUtils.isNotBlank(tokenParam)) {
            //验证tokenParam是否正确
            Integer userId = this.remoteService.validateToken(tokenParam, HttpUtil.getRequestContextPath(request));
            if (userId != null) {
                request.setAttribute("SESSION_LOGIN_FLAG", tokenParam);
//              调用接口获取user,以及user权限列表
                LoginUser loginUser=remoteService.getLoginUser(userId,tokenParam);
//                log.info("loginUser:"+ JSON.toJSONString(loginUser));
//                RestTemplateUtils restTemplateUtils=new RestTemplateUtils();
//                LoginUser loginUser = restTemplateUtils.getLoginUser(tokenParam);
                request.setAttribute(SsoConstants.LOGIN_USER_SESSION, loginUser);
                return true;
            } else {
//                this.redirectSsoServer(request, response);
                return responseFalse(response);
            }
        } else {
//            this.redirectSsoServer(request, response);
            return responseFalse(response);
        }
//         return true;
    }

    private boolean responseFalse(HttpServletResponse response) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        out = response.getWriter();
        out.write(JSON.toJSONString(RetResponse.retFail()));
        out.flush();
        out.close();
        return false;
    }

    private void redirectSsoServer(HttpServletRequest request, HttpServletResponse response) {
        String redirectUrl = this.ssoProperties.getServerUrl() + "?" + "redirectUrl" + "=" + HttpUtil.encodeUrl(HttpUtil.getRequestFullPathNoParam(request));

        try {
            response.sendRedirect(redirectUrl);
        } catch (IOException var5) {
            this.log.error("跳转到服务器出错!", var5);
        }

    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

 

SSO服务器登录验证代码

package com.stylefeng.sso.server.modular.controller;

import com.stylefeng.guns.core.base.controller.BaseController;
import com.stylefeng.guns.core.util.ToolUtil;
import com.stylefeng.sso.plugin.constants.SsoConstants;
import com.stylefeng.sso.plugin.service.AuthService;
import com.stylefeng.sso.server.common.Rests;
import com.stylefeng.sso.server.modular.entity.SysUser;
import com.stylefeng.sso.server.modular.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import static com.stylefeng.sso.plugin.constants.SsoConstants.LOGOUT_URL;


/**
 * 登录验证控制器
 *
 * @author stylefeng
 * @Date 2018/2/3 22:23
 */
@Controller
@Slf4j
public class AuthController extends BaseController {

    private static final String LOGIN_TIPS = "tips";

    @Autowired
    AuthService authService;

    @Autowired
    private SysUserService sysUserService;

    private boolean isMobile(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        userAgent = userAgent.toLowerCase();
        if (userAgent.contains("iphone") || userAgent.contains("android")
                || userAgent.contains("ipad") || userAgent.contains("ipod")) {
            return true;
        }
        return false;
    }

    @RequestMapping (value = "/login", method = RequestMethod.GET)
    public String toLogin(HttpServletRequest request) {
        return isMobile(request)? "/login_m.html" : "/login.html";
    }

    @Value ("${spring.profiles.active}")
    private String profile;

    @RequestMapping (value = "/login", method = RequestMethod.POST)
    public String doLogin(HttpServletRequest request, HttpServletResponse response, Model model) {

        String returnUrl = isMobile(request)? "/login_m.html" : "/login.html";

        String tokenParam = null;
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
                if (cookies[i].getName().equals("gunsToken")) {
                    tokenParam = cookies[i].getValue();
                    break;
                }
            }
        }

        String redirectUrl = request.getParameter(SsoConstants.REDIRECT_PARAM_NAME);

        // 如果cookie中能取到token,则认为从其他页面登录,不继续登录流程,跳回原地址
//        if (StringUtils.isNotBlank(tokenParam) && StringUtils.isNotBlank(redirectUrl)){
//            log.info("用户已经处于登录状态,不继续登录流程,跳回原地址: {}", redirectUrl);
//            try {
//                response.sendRedirect(redirectUrl);
//                return null;
//            } catch (IOException e) {
//                log.warn("已经登录,跳回原地址失败", e);
//                model.addAttribute(LOGIN_TIPS, "网络异常!");
//                return "/login.html";
//            }
//        }

        String userName = request.getParameter("userName");
        String password = request.getParameter("password");


        // 登录失败是记录redirectUrl
        model.addAttribute(SsoConstants.REDIRECT_PARAM_NAME, redirectUrl);
        if (ToolUtil.isEmpty(userName) || ToolUtil.isEmpty(password) || ToolUtil.isEmpty(redirectUrl)) {
            model.addAttribute(LOGIN_TIPS, "请求信息不完整!");
            return returnUrl;
        } else {

            /**
             * 判断用户账号密码是否正确
             */
            Integer userId = authService.checkUserLogin(userName, password);
            if (userId != null) {

                //如果账号密码正确,跳转回业务系统的url
                String token = "";
                try {
                /*SysUser sysUser = sysUserService.getSysUser(userId);
                sysUserService.insertLoginUserIntoRedisDto(sysUser, token);*/
                    token = authService.createToken(userId);
                } catch (Exception e) {
                    log.warn("createToken失败",e);
                    model.addAttribute(LOGIN_TIPS, "登录失败,请稍后再试!");
                    return returnUrl;
                }

                if (profile.equals("dev")) {
                    Cookie localhost = new Cookie(SsoConstants.TOKEN_PARAM_NAME, token);
                    localhost.setDomain("jdcloud.com");
                    localhost.setPath("/");
                    localhost.setMaxAge(36000);
                    response.addCookie(localhost);
                } else {
                    Cookie cookie = new Cookie(SsoConstants.TOKEN_PARAM_NAME, token);
                    cookie.setPath("/");
                    response.addCookie(cookie);
                }

                try {
//                    String redirect=redirectUrl+"?"+SsoConstants.TOKEN_PARAM_NAME + "=" + token;
//                    response.sendRedirect(redirectUrl /*+ "?" + SsoConstants.TOKEN_PARAM_NAME + "=" + token*/);
                    response.sendRedirect(redirectUrl);
                    return null;
                } catch (IOException e) {
                    model.addAttribute(LOGIN_TIPS, "网络异常!");
                    return returnUrl;
                }
            } else {
                //如果账号密码错误
                model.addAttribute(LOGIN_TIPS, "账号或密码错误!");
                return returnUrl;
            }
        }
    }

    @ResponseBody
    @RequestMapping ("/hello")
    public String token() {
        return "暂未登录";
    }

    @RequestMapping (LOGOUT_URL)
    public String logout(HttpServletRequest request, HttpServletResponse response, Model model) {
        String tokenParam = null;
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
                if (cookies[i].getName().equals("gunsToken")) {
                    tokenParam = cookies[i].getValue();
                    break;
                }
            }
        }
        String redirectUrl = request.getParameter(SsoConstants.REDIRECT_PARAM_NAME);
        if (StringUtils.isNotBlank(tokenParam)){
            // 删除redis中保存的token,如果失败,不允许退出登录,跳回源地址
            if (!authService.removeCachedToken(tokenParam)) {
                try {
                    redirectUrl = redirectUrl + "?status="+SsoConstants.LOGIN_FAILED_FLAG+"?gunsToken"+tokenParam;
                    response.sendRedirect(redirectUrl);
                    return null;
                } catch (Exception e) {
                    log.error("重定向失败", e);
                    return "/404.html";
                }
            }

        }

        // 删除cookie
        // 开发环境为了方便前端本地测试配置域名hosts,cookie选择种到二级域下;线上环境域名一致,cookie种到默认的domain下
        if (profile.equals("dev")) {
            Cookie localhost = new Cookie(SsoConstants.TOKEN_PARAM_NAME, null);
            localhost.setPath("/");
            localhost.setMaxAge(0);
            response.addCookie(localhost);
        } else {
            Cookie newCookie = new Cookie(SsoConstants.TOKEN_PARAM_NAME, null); //假如要删除名称为username的Cookie
            newCookie.setMaxAge(0); //立即删除型
            newCookie.setPath("/"); //项目所有目录均有效,这句很关键,否则不敢保证删除
            response.addCookie(newCookie); //重新写入,将覆盖之前的
        }

        //跳转到登录页面
        model.addAttribute(SsoConstants.REDIRECT_PARAM_NAME, redirectUrl);
        return isMobile(request)? "/login_m.html" : "/login.html";
    }
}

  

原文地址:https://www.cnblogs.com/e206842/p/11770024.html