单点登录SSO

登录使用shiro框架的SecurityUtil.getSubject().login(new UserNamePasswordToken("telphone","pass“))

退出:SecurityUtil.getSubject().loginOut();

1、单点登录适用于多应用关联的情况(如果是多节点单点登录,那么需要使用shiro框架的session,来保证对节点获取的sessionId是相同的,见另一篇shiro框架文章https://blog.csdn.net/wohaqiyi/article/details/81342741)

2、需要创建拦截器来识别单点登录信息

3、登录Controller,需要将token放到COOKIE里面,设置域为“/”,这样同服务器下的应用可获得添加的该token实现单点登录

package com.liu.web.sso;
 import com.alibaba.fastjson.JSON;
 import com.liu.beans.OutputObject;
 import com.liu.web.Filter.FilterController;
 import com.liu.web.utils.AesEncryDecryUtil;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 import redis.clients.jedis.JedisCluster;

 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;

@RestController
@RequestMapping(path = "/SingleSign")
public class SingleSignController {

    @Autowired
    private JedisCluster jedisCluster;
    private String SESSION_USER="SESSION_USER_";
    //sesssion失效 60秒
    private int SESSION_USER_EXPIRE=60;
    private String TOKEN_INFO="TOKEN_INFO_";

    Logger logger = LoggerFactory.getLogger(SingleSignController.class);

    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public OutputObject  login(String account, String password, HttpSession session, HttpServletResponse response){
        OutputObject out =  new com.liu.beans.OutputObject();
        try{
            //
            String sessionId = session.getId();
            //每次重启工程就不一样,只要不重启工程,每次请求的值都是相同的,所以最好还是用sessionId来判断每个IP
            logger.info("--------sessionId:"+sessionId);
            if(StringUtils.isNotBlank(account) && "123".equals(password)){
                Map<String,Object> userMap = new HashMap();
                userMap.put("account",account);
                userMap.put("password",password);
                logger.info("---------userMap:"+ JSON.toJSONString(userMap));
                //验证成功
                //根据sessionId将用户信息保存到redis
                jedisCluster.setex(SESSION_USER+sessionId,SESSION_USER_EXPIRE,JSON.toJSONString(userMap));
                //添加cookie
                //生成token,需将token加密放到cookie
                String token = UUID.randomUUID().toString().replace("-","")+"_"+account;
                logger.info("------token:"+token);
                String key = AesEncryDecryUtil.getAesKey();
                String encryToken = AesEncryDecryUtil.aesEncry(token,key).toString();
                logger.info("------encryToken:"+encryToken);
                //将token根据员工账号保存到redis
                jedisCluster.setex(TOKEN_INFO+account,SESSION_USER_EXPIRE,JSON.toJSONString(userMap));

                //添加cookie到response
                Cookie cookie = new Cookie("my-Token",encryToken);
                //setPath("/")设置同一服务器都可获得改cookie,(适用于多个应用使用该cookie)
                cookie.setPath("/");
                //cookie的有效时长
                cookie.setMaxAge(6000);
//                通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性
                cookie.setHttpOnly(true);
                response.addCookie(cookie);
                //将用户信息根据token保存到redis
            }

//            String requestSessionId = request.getRequestedSessionId();
//            //第一此登录时requestSessionId为NULL,之后和sessionId值一样
//            logger.info("-------requestSessionId:"+requestSessionId);
//            StringBuffer url = request.getRequestURL();
//            String addr = request.getRemoteAddr();
//            String host =request.getRemoteHost();
//            int port = request.getRemotePort();
//            logger.info("-------url:"+url+"-------addr:"+addr+"------host:"+host+"------port:"+port);

        }catch (Exception e){

        }
        return out;
    }
}

4、增加拦截器配置

package com.liu.web.sso;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {

    @Bean
    public SingleSignOnAdapter  getSingleSignOnAdapter(){
        return new SingleSignOnAdapter();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //增加单点登录拦截器,除了error,swagger-sources页面,其余路径全部拦截
       registry.addInterceptor(getSingleSignOnAdapter()).addPathPatterns("/**")
               .excludePathPatterns("/error")
               .excludePathPatterns("/swagger-sources");
    }
}

5、单点登录拦截器实现类

package com.liu.web.sso;

import com.alibaba.dubbo.rpc.service.GenericException;
import com.liu.web.Filter.FilterController;
import com.liu.web.utils.JsonUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import redis.clients.jedis.JedisCluster;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

public class SingleSignOnAdapter extends HandlerInterceptorAdapter {
    Logger logger = LoggerFactory.getLogger(FilterController.class);
    @Autowired
    private JedisCluster jedisCluster;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try{
            String sessionId = request.getSession().getId();
            Cookie[] cookies = request.getCookies();
            for(Cookie cookie:cookies){
                if("my-token".equals(cookie.getName())){
                    //为拼接每个用户账号的token
                   String token = cookie.getValue();
                   String account = token.split("_")[1];
                   String redisKey = "ACCOUNT_INFO_"+account;
                   String userInfo = jedisCluster.get(redisKey);
                   if(StringUtils.isBlank(userInfo)){
                       //为空则根据token远程调用登陆工程的服务,返回当前用的信息
                       String res = "{\"rstCode\":\"0\",\"bean\":{\"account\":\"001\"}}";
                       Map<String,String> map = BeanUtils.describe(res);
                       String rstCode = map.get("rstCode");
                       if("0".equals(rstCode)) {
                           String userString = map.get("bean");
                           if(StringUtils.isBlank(userString)){
                               throw new GeneralException("-1001","登录失效!");
                           }
                           jedisCluster.setex(redisKey,300,userString);
                           return true;
                       }else{
                           logger.info("------服务繁忙稍后再试");
                           throw new GeneralException("2999","服务繁忙稍后再试!");
                       }
                   }else{
                       return true;
                   }
                }
            }
            logger.info("----------------登录失效");
            throw new GeneralException("-1001","登录失效!");
        }catch (Exception e){
            logger.info("----------------登录失效");
            throw new GeneralException("-1001","登录失效!");
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值