乐优商城项目总结day(17)

乐优商城项目总结day(17)

授权中心

cookie设置问题

认证与授权采用jwt无状态的方式,使用私钥生成token后将token写回cookie。但是设置cookie是在授权微服务进行写回的,会经过nginx与zuul的反向代理,在两次反向代理的过程中request的host和url均发生了变化。

// 将token写入cookie
CookieUtils.newBuilder(response).httpOnly().request(request).build(cookieName, token);

写入cookie时需要对cookie的Domain进行设置,Domain为此次cookie设置的作用域,需要从request的路径信息中获取。

/**
         * 得到cookie的域名
         */
        private String getDomainName(HttpServletRequest request) {
            String domainName = null;

            String serverName = request.getRequestURL().toString();
            if (serverName == null || serverName.equals("")) {
                domainName = "";
            } else {
                serverName = serverName.toLowerCase();
                serverName = serverName.substring(7);
                final int end = serverName.indexOf("/");
                serverName = serverName.substring(0, end);
                final String[] domains = serverName.split("\\.");
                int len = domains.length;
                if (len > 3) {
                    // www.xxx.com.cn
                    domainName = domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
                } else if (len <= 3 && len > 1) {
                    // xxx.com or xxx.cn
                    domainName = domains[len - 2] + "." + domains[len - 1];
                } else {
                    domainName = serverName;
                }
            }

            if (domainName != null && domainName.indexOf(":") > 0) {
                String[] ary = domainName.split("\\:");
                domainName = ary[0];
            }
            return domainName;
        }

例如http://api.leyou.com/api/XXX截取后就为leyou.com,设置为Domain后就作用于所有以leyou.com为二级域名的子域名,如:www.leyou.comapi.leyou.com。但是经过nginx以及zuul的反向代理之后,request的url路径就发生了变化,授权微服务得到的Domain也不是一开始前端请求的路径。

nginx的解决方法如下:

proxy_set_header Host $host;

加上后进行反向代理时request中的Host还是反向代理之前的,并不会因为请求的转发而改变。这样子zuul网关就能拿到一开始请求的路径,但是zuul也会进行一次反向代理,因此在代理时需要将host同时带上。

zuul的解决方法如下:

zuul:
	add-host-header: true

注意:这里我用的zuul的版本是2.0.1,里面存在一个bug导致host永远无法添加到header上并转发,所以降了一个版本后解决了。

 		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-netflix-zuul</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-zuul</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>

加上后zuul就会将原来的host继续转发下去,授权微服务就能拿到一开始的host。但是因为zuul里面存在敏感头的设置,会将一些头信息进行过滤,其默认设置为:

private Set<String> sensitiveHeaders = new LinkedHashSet(Arrays.asList("Cookie", "Set-Cookie", "Authorization"));

可以看到cookie有关的操作都被禁用了,解决方法如下:

zuul:
	sensitive-headers:

将敏感头设置为空,最后cookie设置成功。

网关登录拦截

在zuul中对用户进行统一拦截,对用户的token进行校验,如果发现未登录或token错误,则进行拦截。
在zuul中实现拦截添加一个Filter即可:

@Component
@EnableConfigurationProperties({JwtProperties.class, FilterProperties.class})
public class AuthFilter extends ZuulFilter {

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private FilterProperties filterProperties;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        // 获取上下文
        RequestContext context = RequestContext.getCurrentContext();
        // 获取request
        HttpServletRequest request = context.getRequest();
        // 获取请求的路径
        String path = request.getRequestURI();
        return !isAllowPath(path);
    }

    private boolean isAllowPath(String path) {
        List<String> allowPaths = filterProperties.getAllowPaths();
        for (String allowPath : allowPaths) {
            if(path.startsWith(allowPath)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Object run() throws ZuulException {
        // 获取上下文
        RequestContext context = RequestContext.getCurrentContext();
        // 获取request
        HttpServletRequest request = context.getRequest();
        // 获取cookie中的token
        String token = CookieUtils.getCookieValue(request, jwtProperties.getCookieName());
        try {
            // 解析token
            UserInfo userInfo = JwtUtils.getUserInfo(jwtProperties.getPublicKey(), token);
            // TODO 校验权限
        } catch (Exception e) {
            // 解析token失败,拦截
            context.setSendZuulResponse(false);
            // 返回状态码
            context.setResponseStatusCode(403);
        }
        return null;
    }
}

拦截中可以对部分请求比如登录、注册进行放行,相关逻辑可以在ZuulFilter中的shouldFilter方法里重写来设置是否拦截。

发布了11 篇原创文章 · 获赞 5 · 访问量 2696
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览