分布式shiro单点登录跨域、请求等相关问题

先讲一下此次项目的基本架构 使用springcloudalibaba 做的分布式项目shiro实现单点登录,前后端分离,前端使用vue。

使用shiro结合redis存储session信息登录之后返回token字符串,前端请求携带在header里以Authorization携带到后台。

1跨域问题

在gateway进行统一配置

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration cfg = new CorsConfiguration();
        cfg.setAllowCredentials(true);
        cfg.addAllowedOrigin("*");
        cfg.addAllowedMethod("*");
        cfg.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", cfg);
        return new CorsWebFilter(source);
    }
}

另外在yml配置

routes:
  - id: com-lepu-his-adapter
    uri: lb://com-lepu-his-adapter
    predicates:
      - Path=/his/**
    filters:
      - StripPrefix=1
      - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

主要是最后DedupeResponseHeader 意思是去除响应头中重复的值。

2 前后端分离之后需要放过OPTIONS请求

在gateway中配置

@Component
public class LoginFilter implements GlobalFilter, Ordered {
    @Override
    public int getOrder() {
        return -1;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        if (CorsUtils.isCorsRequest(request)) {
            HttpHeaders requestHeaders = request.getHeaders();
            HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
            HttpHeaders headers = response.getHeaders();
            //放过OPTIONS请求
            if (request.getMethod() == HttpMethod.OPTIONS) {
                response.setStatusCode(HttpStatus.OK);
                return Mono.empty();
            }
        }

        boolean containsKey = exchange.getRequest().getHeaders().containsKey("Authorization");
       
        if(!containsKey){
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            DataBuffer wrap = response.bufferFactory().wrap("token22 can not be null".getBytes());
            return response.writeWith(Mono.just(wrap));
        }
        return chain.filter(exchange);
    }
}

一方面是配置放过OPTIONS请求,另外一方面在gateway只做了认证请求头不能为空的限制。

3 前后端分离之后shiro等未登录、未授权等问题不能通过配置重定向页面来解决。

3.1未登录问题 继承FormAuthenticationFilter

@Slf4j
public class ShiroFormAuthenticationFilter extends FormAuthenticationFilter {

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {

        if (this.isLoginRequest(request, response)) {
            if (this.isLoginSubmission(request, response)) {
                if (log.isTraceEnabled()) {
                    log.trace("Login submission detected.  Attempting to execute login.");
                }

                return this.executeLogin(request, response);
            } else {
                if (log.isTraceEnabled()) {
                    log.trace("Login page view.");
                }
                return true;
            }
        } else {
            HttpServletRequest req = (HttpServletRequest)request;
            HttpServletResponse resp = (HttpServletResponse)response;
            if (req.getMethod().equals(RequestMethod.OPTIONS.name())) {
                resp.setStatus(HttpStatus.OK.value());
                return true;
            } else {
                if (log.isTraceEnabled()) {
                    log.trace("Attempting to access a path which requires authentication.  Forwarding to the Authentication url [{}]" ,this.getLoginUrl());
                }
                /**
                 * 在这里实现自己想返回的信息,其他地方和源码一样就可以了
                 */
                resp.setHeader("Access-Control-Allow-Credentials", "true");
                resp.setContentType("application/json; charset=utf-8");
                resp.setCharacterEncoding("UTF-8");
                PrintWriter out = resp.getWriter();
                out.println(JSON.toJSONString(ResultBean.reponse(Constant.ERROR_401)));
                out.flush();
                out.close();
                return false;
            }
        }
    }

}

3.2未授权问题

@Slf4j
@ControllerAdvice
public class BaseExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResultBean error(HttpServletRequest request, HttpServletResponse response, Exception e) {
        log.error("系统错误", e);
        return ResultBean.reponse(Constant.ERROR_500);
    }

    @ExceptionHandler(value = AuthorizationException.class)
    @ResponseBody
    public ResultBean error(HttpServletRequest request, HttpServletResponse response, AuthorizationException e) {
        return ResultBean.reponse(Constant.ERROR_402);
    }
}

在公共异常里面配置未授权异常的捕获类

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值