微服务登录

1.不是微服务的架构做登录是浏览器登录发一个请求到tomcat,tomcat会去数据库验证你输入的用户和密码是否是正确的,查出来是正确会把信息存入到session中,并登录成功的时候返回一个页面,存入session有一个好处是hhtp协议是无状态协议的,当第二次登录的时候会去session里面查看信息。这里有一个问题是tomcat是怎么判断不同的session对应的浏览器发送请求。他们是有不同的sessionid并且他们是放在cookie中的。
微服务的登录事件你要考虑到一个问题,每个微服务就像一个单体架构,如果密码还是放在session里面的,用户浏览器访问别的微服务就后变成未登录状态。而且把密码放在session微服务就会变成有状态的服务。但是我们可以状态转移,把密码保存在客户端的cookie里,客户端发请求是无状态的但是带上了cookie。这样就实现了无论客户端访问哪个微服务,都会带上cookie的信息。
但是通过读cookie会窃取cookie的信息,可以去伪造信息,发送请求。但是我们可以在客户端采用jwt的验证。但是jwt又很容易解密。我们可以在验签的时候在加上设备号,这样也可以达到保密的效果。
在验证的时候,用户发任何请求都会带上秘钥的值,然后微服务都要做简单的校验就能够得到用户是否登录,登录了做登录的事情,未登录做为登录的事情。理论上说有n个请求和n个服务是不是都要做n个校验,和登录了做登录的事情,未登录做为登录的事情。这个时候我们就可以统一处理一下,服务器判断登录无非有三种需求,1.未登录也可以执行的操作2.可登录也可不登录可以执行的操作.他们的区别就比如说爱奇艺的vip有VIP和没有vip都可以看视频,但是没vip我当你是游客给你放广告,3.必须登录才能执行操作(1) @IsLogin,比如支付,积分。在可登录也可不登录也可以执行的操作我自定义一个注解,在注解里面可以调用一个方法实现默认值的设置,一旦被打上这个注解就会判断有没有登录。在写了自定义注解的方法里面获得当前用户的信息,只要在这里做一个判断,没有登录做没有登录的逻辑,登录了做登录的逻辑。如果你要实现强制登录就在自定义的注解你把他属性就设置为true。一旦没有登录方法就会强制你调到登录页面。那在判断有没有登录是用户服务发了请求发给哪个服务(城市服务)就在这个城市服务做判断做aop的拦截,(2)LoginAop 。但是在业务代码是会用到业务信息的,比不只是单纯的知道有没有登录,还要知道谁登录,在aop里面的user是知道谁登录的,但是并没有用,还要让开发者知道是谁登录这个时候我们在创建一个(3)UserUtil 类,写静态变量,里面放user对象给一个get和set方法,并在aop里面调用目标方法的之前设置登录的信息,但是这样也有一个问题,业务代码是在controller里面假如有多个同时请求,可能会出现线程的互抢,这个我们可以在类里面加一个ThreadLocal他的作用是哪个线程设置的东西只有在同一个线程才能拿出来
注解的作用仅仅只是标识位的作用,但是可以在注解里面设置一个方法mustLogin为true这个告诉框架这个方法必须要登录的,具体登录,登录有没有成功还是靠spring框架去实现。

(1). @IsLogin 自定义的注解


/**
 * javadoc他可以把你源码写的注释生成api文档
 * @Documented,在生成javadoc文档的时候这个注解要不要被记录,没什么太大意义
 * @Inherited,一旦IsLogin加上这个注解之后你的IsLogin就有了继承性
 * @Target,当前注解的作用范围
 * ElementType.CONSTRUCTOR -只能够标注在构造方法上
 * ElementType.FIELD -能够标注在属性(全局变量)上
 * ElementType.LOCAL_VARIABLE -能够标注在局部变量上(很少用)
 * ElementType.METHOD -能够标注在方法上
 * ElementType.PACKAGE -能够标注在方法参数上
 * ElementType.TYPE  -作用在类,接口,内部类上
 * @Retention -当前注解有效范围
 * RetentionPolicy.SOURCE -表示当前注解在源码中有效,一旦编译成class文件,注解会丢失
 * RetentionPolicy.CLASS - 表示当前注解在源码、class文件中有效,一旦运行时,就会丢失
 * RetentionPolicy.RUNTIME - 表示当前注解运行时有效,如果需要配合反射使用,必须是Runtime范围因为反射是运行时动态解析你的类
 *注解里的方法语法: 返回值类型 方法名() [default 默认值];
 */
@Documented
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface IsLogin {
    boolean mustLogin() default false;

}

(2).aop切面实现环绕增强

/**
 * 切面类
 * @Aspect表示当前类是切面类
 * @Component你的切面类一定要被当前类给扫到
 */
@Aspect
@Component
public class LoginAop {
    /**
     * 环绕增强 必须要这个参数ProceedingJoinPoint
     *  @Around("@annotation(IsLogin)")表示写了@IsLogin这个注解会被增强
     *  拦截器的底层就是靠Aop实现的,但是Aop比拦截器更加灵活,拦截器只能拦截Controller,aop理论上说可以增强spring里面的所有东西包括service,dao
     * @param joinPoint
     * @return
     */
    @Around("@annotation(IsLogin)")
    public Object isLogin(ProceedingJoinPoint joinPoint){

        //前置增强
        //通过请求获得jwtToken和devId类似对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        //通过参数获取jwtToken和devId
        String jwtToken=request.getParameter("jwtToken");
        String devId = request.getParameter("devId");

        User user=null;
        //判断
        if (jwtToken!=null && devId !=null){
            //有可能登录
            User toke = Jwtutil.isToke(jwtToken, devId);
        }

        if (user==null){
            //未登录
            //获取方法上的IsLogin注解,判断mustLogin方法的返回值
               //方法签名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //拦截的方法
            Method method = signature.getMethod();
            //拿到注解,注解也是对象
            IsLogin isLogin = method.getAnnotation(IsLogin.class);

            boolean flag = isLogin.mustLogin();
            if (flag){
                //强制登录
                //通知前端
                return new ResultData().setCode(ResultData.Code.TOLOGIN);
            }
        }
        //设置登录的信息

        Object result = null;
        try {
            //目标方法的调用
           result= joinPoint.proceed();
            //后置增强
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            //异常增强
        }finally {
            //后置完成增强
        }
        return result;
    }
}

(3).UserUtil 实现Aop里面知道了谁登录的,这里要告诉业务代码是谁登录的


/**
 * Aop里面知道了谁登录的,这里要告诉业务代码是谁登录的
 */
public class UserUtil {

    private static ThreadLocal<User> user=new ThreadLocal<>();

    public static User getUser() {
        return UserUtil.user.get();
    }

    public static void setUser(User user) {
        UserUtil.user.set(user);
    }

    /**
     * 当controllwe的代码调这里,有可能会同时两个请求他们会抢线程
     * 哪个线程的设置的值,只有在当前线程才能拿出来,干扰也不行
     * @param args
     */
    public static void main(String[] args){

        ThreadLocal<String> threadLocal = new ThreadLocal<>();
        threadLocal.set("Hello");

        new Thread(){
            @Override
            public void run() {
                threadLocal.set("World!");
                System.out.println("子线程:" + threadLocal.get());
            }
        }.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        String s = threadLocal.get();
        System.out.println(s);

    }

}

3.在es中城市服务是内嵌于酒店服务如果我们要对城市服务的新增客房信息和新增客房价格每日信息要同步es,但是城市服务是依附于酒店服务新增城市服务其实是在修改酒店服务,对于内嵌es只能修改脚步完成操作
1.监听客房信息
在这里插入图片描述
2.新增客房价格每日信息

 @Override
    public boolean insertRoomPrice(Integer hid,List<RoomPrice> roomPrices) {
       List<UpdateQuery> updateQueries=new ArrayList<>();

        //循环价格集合 ->map集合
        roomPrices.stream().forEach(roomPrice -> {
            //将RoomRices ->Map集合
            Map<String , Object> priceMap=new HashMap<>();
            priceMap.put("id",roomPrice.getId());
            priceMap.put("rid",roomPrice.getRid());
            priceMap.put("date",new SimpleDateFormat("yyyy-MM-dd").format(roomPrice.getDate()));
            priceMap.put("hasnumber",roomPrice.getHasNumber());
            priceMap.put("number",roomPrice.getNumber());
            priceMap.put("price",roomPrice.getPrice().doubleValue());


            //脚步参数集合
            HashMap<String, Object> params = new HashMap<>();
            params.put("rid",roomPrice.getId());
            params.put("priceInfo",priceMap);

            UpdateQuery build = UpdateQuery.builder(hid + "")
                    .withScript("for(r in ctx._source.rooms){if(r.id == params.id){r.prices.add(params.priceInfo);}}")
                    .withParams(params)
                    .build();

            updateQueries.add(build);
        });
        //批量修改
       restTemplate.bulkUpdate(updateQueries, IndexCoordinates.of("hotal_index"));
        return true;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用Spring Cloud搭建微服务登录,你可以按照以下步骤进行操作: 1. 创建认证服务:首先,你需要创建一个认证服务,用于处理用户的登录和身份验证。你可以使用Spring Security来实现用户认证和授权功能。在认证服务中,你可以定义用户账号、密码以及角色等信息。 2. 配置认证服务:在认证服务中,你需要配置Spring Security来定义登录接口、认证规则和权限控制等。可以使用基于用户名密码的登录方式,也可以使用其他方式,如OAuth2.0等。确保你的认证服务能够正确验证用户的身份,并返回相应的访问令牌。 3. 创建其他微服务:除了认证服务外,你还需要创建其他的微服务,用于提供不同的业务功能。这些微服务可以是独立的应用程序,通过Spring Cloud注册到服务注册中心,并与认证服务进行通信。 4. 集成认证服务:在其他微服务中,你需要集成认证服务,以便验证用户的访问权限。可以通过在请求头中携带访问令牌,并在微服务中进行校验来实现。使用Spring Security OAuth2或者JWT等技术来实现令牌的生成与验证。 5. 配置路由和网关:为了统一管理和保护微服务,你可以使用Spring Cloud Gateway或Zuul等网关技术来配置路由和访问控制规则。通过网关,你可以对外暴露统一的登录接口,并在用户登录成功后将请求转发到相应的微服务。 6. 前端集成:最后,你需要在前端应用中集成登录功能。前端应用可以使用Spring Boot、React、Angular或Vue等框架进行开发。通过调用登录接口获取访问令牌,并在后续的请求中携带令牌进行访问控制。 总结来说,使用Spring Cloud搭建微服务登录需要创建认证服务、配置认证规则和权限控制、集成认证服务到其他微服务、配置路由和网关以及前端集成等步骤。这样可以实现用户的登录和访问权限控制。希望以上信息对你有所帮助!如果有任何问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值