6. 架构中的细节干货(待补充)

1.gateway使用断言都要干啥

1.1限制应用端时访问,每个端都有标识,否则不予响应

/

/// 1.需要补充内容 ///

/

2.gateway使用过滤器要干啥
2.1 鉴权
2.1.1 非过滤地址忽略

在实际应用场景中,会碰到一些接口,不需要登录,也不需要任何标识就能访问,比如一般新闻相关,还有商品信息等,这时候我们希望网关必要对访问进行额外的处理,我们就需要在网关做一些配置

注意:实际开发中需要登录才可访问的接口远远大于不需要登录的接口,因此一般都是配置不需要登录的接口

创建在resource文件下创建manage.properties文件

#1.第一种书写方式
manage.excludes[0] = ^/user/v2/api-docs$
manage.excludes[1] = ^/user/hello$
manage.excludes[2] = ^/user/cp$

#1.第二种书写方式,用“,”分隔,方便维护,建议采用第二种
manage.excludes2 = ^/user/v2/api-docs$,\
  ^/user/hello$,\
  ^/user/cp$

创建一个ManageExcludeConfig.java

package com.threeking.gateway.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.PropertySourceFactory;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.regex.Pattern;

/**
 * 排查参数
 * @Author: A.H
 * @Date: 2020/10/28 17:22
 */
@Data
@AllArgsConstructor
@Component
@PropertySource(value = {"classpath:conf/manage.properties"})
@ConfigurationProperties(prefix = "manage")
public class ManageExcludeConfig {
    //排除列表
    private List<String> excludes;

    /**
     * 验证是否排除
     * @return
     */
    public boolean isExclude(String uri) {
        return urlFilter(excludes, uri);
    }

    /**
     * 验证是否过滤
     * @param patternStrs
     * @param uri
     * @return
     */
    private boolean urlFilter(List<String> patternStrs, String uri) {
        for (String str : patternStrs) {
            if (Pattern.compile(str).matcher(uri).find()) {
                return true;
            }
        }

        return false;

    }
}

创建一个全局的过滤器

@Slf4j
@Component
public class DomainGlobalFilter implements GlobalFilter, Ordered {

    @Autowired
    ManageExcludeConfig manageExcludeConfig;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        HttpMethod method = request.getMethod();

        String url = request.getURI().getPath();
        if(manageExcludeConfig.isExclude(url)){
            log.info("非过滤地址,直接跳过.....");
            return chain.filter(exchange);
        }
		// TODO: 其他判断

        return null;
    }
    
    @Override
    public int getOrder() {
        return 1;
    }
}

当然,也可以用yml文件,或者直接用项目配置文件,这个单独拎出来只是为了方便管理

2.1.2 用户登录认证

使用全局过滤器,通过验证token,或者别的标识,和redis中做对比,完成鉴权,修改上一个过滤器GlobalFilter

@Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        HttpMethod method = request.getMethod();
        
        String url = request.getURI().getPath();
        if(manageExcludeConfig.isExclude(url)){
            log.info("非过滤地址,直接跳过.....");
            return chain.filter(exchange);
        }
        // 模拟从前端获取到的用户标识,可以是token,session,或者其他约定的参数
        
        String token = exchange.getRequest().getHeaders().getFirst("token");
        if(StringUtils.isEmpty(token)){
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        String strInfo = authService.getQueryUserInfo(token);
        if(StringUtils.isEmpty(strInfo)){
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        
        return chain.filter(exchange);
    }

创建一个AuthService.java服务类

@Slf4j
@Service
public class AuthService {

    /**
     * 根据前端标识获取用户信息,可以是从redis,db等中获取
     * @param code
     * @return
     */
    public String getQueryUserInfo(String code){

       try {
            //根据code从redis或者数据库中获取用户信息
            String userId = stringRedisTemplate.opsForValue().get(code);
            assert userId != null;
            String loginSessionKey = "str"+RED_USER_LOGIN_SESSION + userId;
            String session = stringRedisTemplate.opsForValue().get(loginSessionKey);
            assert session != null;
            UserInfo user = JacksonUtils.toObj(session, UserInfo.class);

            log.info(user.toString());
            return user.toQuery();

        }catch (Exception e){
            log.error("获取用户信息时出错:"+e.getMessage());
            return null;
        }

    }


    @Data
    @NoArgsConstructor
    public static class UserInfo{

        @JsonProperty(value = "id")
        private String userId;

        @JsonProperty(value = "nikeName")
        private String userName;

        /**
         * 重写一下toString方案,使其返回&参数拼接的字符串,方便使用
         * @return
         */
        public String toQuery(){

            StringBuilder query = new StringBuilder();
            // 注意一定要使用URLEncoder.encode转码,否则传值会有编码问题
            for(Field field : this.getClass().getDeclaredFields()){
                query.append(field.getName());
                query.append('=');
                query.append(URLEncoder.encode((String) field.get(this), StandardCharsets.UTF_8));
                query.append('&');
            }
            return query.deleteCharAt(query.length()-1).toString();
        }
    }

}
2.2 参数传递
用户封装在gateway实现转发,前端不需用传用的的id,code等主键信息,所有的以登录信息为准,接上一个GlobalFilter,修改filter,添加一下代码
		// 从身份类里面获取用户信息
        query.append(strInfo);

        try {
            URI newUri = UriComponentsBuilder.fromUri(uri).replaceQuery(query.toString()).encode(StandardCharsets.UTF_8).build(true).toUri();
            ServerHttpRequest newRequest = exchange.getRequest().mutate().uri(newUri).build();
            return chain.filter(exchange.mutate().request(newRequest).build());
        } catch (RuntimeException var9) {
            var9.printStackTrace();
            throw new IllegalStateException("Invalid URI query: \"" + query.toString() + "\"");
        }

在底层服务里面写一个接口

	@PostMapping("/ccp")
    public String ccp(UserVo userVo)
    {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        assert requestAttributes != null;
        HttpServletRequest request = requestAttributes.getRequest();

        System.out.println(request.getQueryString());

        return userVo.toString();
    }

在这里插入图片描述

GET方法同样可以获得想要传递的参数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值