单点登录SSO

  1. 分布式,SSO(single sign on)模式在这里插入图片描述

解决 :
1.用户身份信息独立管理,更好的分布式管理。
2.可以自己扩展安全策略
3,跨域不是问题
缺点:
1.认证服务器访问压力较大。

  1. 单点登录流程图
    在这里插入图片描述

3.UmsMember.java

public class UmsMember implements Serializable {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private String id;
    private String memberLevelId;
    private String username;
    private String password;
    private String nickname;
    private String phone;
    private int status;
    private Date createTime;
    private String icon;
    private String gender;
    private Date birthday;
    private String city;
    private String job;
    private String personalizedSignature;
    private String sourceType;
    private int integration;
    private int growth;
    private int luckeyCount;
    private int historyIntegration;

    private Long sourceUid;
    private String accessToken;
    private String accessCode;

4.UmsService.java

public interface UserService {
    List<UmsMember> getAllUser();

    List<UmsMemberReceiveAddress> getUmsMemberReceiveAddress(String memberId);

    UmsMember login(UmsMember umsMember);

    void addUserToken(String token, String memberId);

    UmsMember addOldOauthUser(UmsMember umsMember);

    UmsMember checkOauthUser(UmsMember umsCheck);

    UmsMemberReceiveAddress getReceiveAddressById(String receiveAddressId);
}

4.UserMapper.java

public interface UserMapper extends Mapper<UmsMember>{
    List<UmsMember> selectAllUser();
}

5.UmsMemberReceiveAddressMapper.java

public interface UmsMemberReceiveAddressMapper extends Mapper<UmsMemberReceiveAddress>{
}

6.UserServiceImpl.java

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UmsMemberReceiveAddressMapper umsMemberReceiveAddressMapper;

    @Autowired
    RedisUtil redisUtil;

    @Override
    public List<UmsMember> getAllUser() {
        List<UmsMember> umsMemberList= userMapper.selectAll();
        return umsMemberList;
    }

    @Override
    public List<UmsMemberReceiveAddress> getUmsMemberReceiveAddress(String memberId) {
        UmsMemberReceiveAddress umsMemberReceiveAddress=new UmsMemberReceiveAddress();
        umsMemberReceiveAddress.setMemberId(memberId);
        List<UmsMemberReceiveAddress> umsMemberReceiveAddresses = umsMemberReceiveAddressMapper.select(umsMemberReceiveAddress);
        return umsMemberReceiveAddresses;
    }

    @Override
    public UmsMember login(UmsMember umsMember) {
        Jedis jedis=null;
        try {
            jedis = redisUtil.getJedis();
            if(jedis!=null){

                String umsMemberStr = jedis.get("user:" + umsMember.getPassword() + ":info");

                if (StringUtils.isNotBlank(umsMemberStr)) {
                    //密码正确
                    UmsMember umsMemberFromCache = JSON.parseObject(umsMemberStr, UmsMember.class);
                    return umsMemberFromCache;
                }
            }
            //连接redis失败,开启数据库
            UmsMember umsMemberFromDb= loginFromDb(umsMember);
            if(umsMemberFromDb!=null){
                jedis.setex("user:" + umsMember.getPassword() +umsMember.getUsername()+ ":info",60*60*24,JSON.toJSONString(umsMemberFromDb));
            }
            return umsMemberFromDb;
        }finally {
            jedis.close();
        }
    }

    @Override
    public void addUserToken(String token, String memberId) {
        Jedis jedis = redisUtil.getJedis();
        jedis.setex("user:"+memberId+":token",60*60*2,token);

        jedis.close();
    }

    @Override
    public UmsMember addOldOauthUser(UmsMember umsMember) {
        userMapper.insertSelective(umsMember);
        return umsMember;
    }

    @Override
    public UmsMember checkOauthUser(UmsMember umsCheck) {
        UmsMember umsMember = userMapper.selectOne(umsCheck);
        return umsMember;
    }

    @Override
    public UmsMemberReceiveAddress getReceiveAddressById(String receiveAddressId) {
        UmsMemberReceiveAddress umsMemberReceiveAddress=new UmsMemberReceiveAddress();
        umsMemberReceiveAddress.setId(receiveAddressId);
        UmsMemberReceiveAddress memberReceiveAddress = umsMemberReceiveAddressMapper.selectOne(umsMemberReceiveAddress);
        return memberReceiveAddress;
    }


    private UmsMember loginFromDb(UmsMember umsMember) {
        List<UmsMember> umsMembers = userMapper.select(umsMember);

        if(umsMembers!=null){
            return umsMembers.get(0);
        }
        return null;
    }
}

7.PassPortController.java

@Controller
public class PassPortController {

    @Reference
    UserService userService;

    @RequestMapping("vlogin")
    public String vlogin(String code,HttpServletRequest request){

        //授权码换取access_token
        String s3="https://api.weibo.com/oauth2/access_token?";
        //?client_id=3193708961&client_secret=df2b2370fbd3483cdd8a9eb422ca325&grant_type=authorization_code&redirect_uri=http://passport.gmall.com:8085/vlogin&code=CODE";

        HashMap<String, String> paramMap = new HashMap<>();
        paramMap.put("client_id","3193708961");
        paramMap.put("client_secret","df2b2370fbd3483cdd8a9eb422ca3253");
        paramMap.put("grant_type","authorization_code");
        paramMap.put("redirect_uri","http://passport.gmall.com:8085/vlogin");
        paramMap.put("code",code);

        String access_token_json = HttpclientUtil.doPost(s3, paramMap);
        Map<String,String> access_map = JSON.parseObject(access_token_json, Map.class);

        //access_token获取用户信息
        String access_token = access_map.get("access_token");
        String uid = access_map.get("uid");
        String s4="https://api.weibo.com/2/users/show.json?access_token="+access_token+"&uid="+uid;
        String s = HttpclientUtil.doGet(s4);
        Map<String,Object> map = JSON.parseObject(s, Map.class);

        //将用户信息保存到数据库,将用户类型设置为微博用户
        UmsMember umsMember = new UmsMember();
        umsMember.setSourceType("2");
        umsMember.setAccessCode(code);
        umsMember.setAccessToken(access_token);
        umsMember.setNickname((String)map.get("screen_name"));
        umsMember.setSourceUid(((Long)map.get("id")));
        umsMember.setCity((String) map.get("location"));
        umsMember.setGender((String) (map.get("gender")));

        UmsMember umsCheck = new UmsMember();
        umsCheck.setSourceUid(umsMember.getSourceUid());
        UmsMember checkUmsMember = userService.checkOauthUser(umsCheck);
        if(checkUmsMember==null){
            umsMember=userService.addOldOauthUser(umsMember);
        }else{
            umsMember=umsCheck;
        }

        //生成JWT的token,并且重定向到首页,携带token
        String token=null;
        //rpc主键返回策略失效
        String memberId = umsMember.getId();
        String nickname = umsMember.getNickname();

        Map<String,Object> userMap=new HashMap<>();
        userMap.put("memberId",memberId);
        userMap.put("nickname",nickname);

        String ip = request.getHeader("x-forwarded-for");
        //从request中获取IP
        if(StringUtils.isBlank(ip)) {
            ip=request.getRemoteAddr();
            if(StringUtils.isBlank(ip)) {
                ip="127.0.0.1";
            }
        }

        //按照设计的算法对参数进行加密后,生成token
        token = JwtUtil.encode("2019gmall0105", userMap, ip);

        return "redirect:http://search.gmall.com:8083/index?token="+token;
    }

    @RequestMapping("verify")
    @ResponseBody
    public String verify(String token,String currentIp){

        //通过jwt校验token真假
        Map<String,String> map=new HashMap<>();

        Map<String, Object> decode = JwtUtil.decode(token, "2019gmall0105", currentIp);
        if(decode!=null) {
            map.put("status", "success");
            map.put("memberId", (String) decode.get("memberId"));
            map.put("nickName", (String) decode.get("nickName"));
        }else{
            map.put("status", "fail");
        }
        return JSON.toJSONString(map);
    }

    @RequestMapping("login")
    @ResponseBody
    public String login(UmsMember umsMember, HttpServletRequest request){

        String token="";
        //调用用户服务验证用户名和密码
        UmsMember userMemberLogin= userService.login(umsMember);
        if(userMemberLogin!=null){
            //登陆成功

            //用jwt制作token

            //将token存入redis一份
            String memberId = userMemberLogin.getId();
            String nickname = userMemberLogin.getNickname();
            Map<String,Object> userMap=new HashMap<>();
            userMap.put("memberId",memberId);
            userMap.put("nickname",nickname);

            String ip = request.getHeader("x-forwarded-for");
            //从request中获取IP
            if(StringUtils.isBlank(ip)) {
                ip=request.getRemoteAddr();
                if(StringUtils.isBlank(ip)) {
                    ip="127.0.0.1";
                }
            }

            //按照设计的算法对参数进行加密后,生成token
            token = JwtUtil.encode("2019gmall0105", userMap, ip);

            //将token放入redis一份
            userService.addUserToken(token,memberId);

        }else{
            //登陆失败
            token="fail";
        }
        return token;
    }

    @RequestMapping("index")
    public String index(String ReturnUrl, ModelMap map){

        map.put("ReturnUrl",ReturnUrl);
        return "index";
    }
}

6.AuthInterceptor.java拦截器

@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        /**
         * 拦截代码
         */

        //判断被拦截请求的访问方法的注解是否需要拦截
        HandlerMethod mh = (HandlerMethod) handler;
        LoginRequired methodAnnotation = mh.getMethodAnnotation(LoginRequired.class);

        StringBuffer url = request.getRequestURL();
        //是否拦截
        if(methodAnnotation==null){
            return true;
        }

        String token="";

        String oldToken = CookieUtil.getCookieValue(request, "oldToken", true);

        if(StringUtils.isNotBlank(oldToken)){
            token=oldToken;
        }
        String newToken = request.getParameter("token");
        if(StringUtils.isNotBlank(newToken)){
            token=newToken;
        }


        /**
         * 该请求是否登录成功
         */
        boolean loginSuccess = methodAnnotation.loginSuccess();

        //请用认证中心进行验证
        String success="fail";
        Map<String,String> successMap=new HashMap<String, String>();
        if(StringUtils.isNotBlank(token)){
            String ip = request.getHeader("x-forwarded-for");
            //从request中获取IP
            if(StringUtils.isBlank(ip)) {
                ip=request.getRemoteAddr();
                if(StringUtils.isBlank(ip)) {
                    ip="127.0.0.1";
                }
            }
            String successJson = HttpclientUtil.doGet("http://passport.gmall.com:8085/verify?token=" + token+"&currentIp="+ip);
            successMap = JSON.parseObject(successJson, Map.class);

            success=successMap.get("status");
        }
        if(loginSuccess){
            //必须登陆成功才能使用
           if(!success.equals("success")){
               //重定向passport登陆
               StringBuffer requestURL = request.getRequestURL();
               response.sendRedirect("http://passport.gmall.com:8085/index?ReturnUrl="+requestURL);
               return false;
           }
               //验证通过,覆盖token
               request.setAttribute("memberId",successMap.get("memberId"));
               request.setAttribute("nickname",successMap.get("nickName"));
            //验证通过,覆盖cookie里的token
            if(StringUtils.isNotBlank(token)) {
                CookieUtil.setCookie(request, response, "oldToken", token, 60 * 60 * 2, true);
            }

        }else{
            //没有登陆也可以用,但是必须校验
            if(success.equals("success")){
                //重定向passport登陆
                request.setAttribute("memberId",successMap.get("memberId"));
                request.setAttribute("nickname",successMap.get("nickName"));
            }

        }
        return true;
    }
}

7.application.properties

server.port=8070

#jdbc 配置
spring.datasource.url=jdbc:mysql://localhost:3306/crm?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=09091995aq


mybatis.mapper-locations=classpath:mapper/*Mapper.xml
mybatis.configuration.map-underscore-to-camel-case=true

#设置日志级别
logging.level.root=info

#扫描dubbo的配置
#dubbo中的服务名称
spring.dubbo.application=user-service
#dubbo的通讯协议名称
spring.dubbo.protocol.name=dubbo
#zookeeper注册中心地址
spring.dubbo.registry.address=47.101.36.177:2181
#zookeeper的注册名称
spring.dubbo.registry.protocol=zookeeper
#dubbo服务的扫描路径
spring.dubbo.base-package=com.atguigu.gmall

spring.dubbo.protocol.port=20880


#spring整合redis
#取配置文件中的redis的ip地址
#Redis数据库连接配置
spring.redis.host=47.101.36.177
spring.redis.port=6379
spring.redis.password=123
spring.redis.timeout=1000
spring.redis.database=0

8.GmallUserServiceApplication.java

@SpringBootApplication
@MapperScan(basePackages = "com.atguigu.gmall.user.mapper")
public class GmallUserServiceApplication {

	public static void main(String[] args) {
		SpringApplication.run(GmallUserServiceApplication.class, args);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值