1、背景
因为启动新项目,用到了spring security的架构。新项目是一个前后端分离的项目,但是整合进来以后,登录没有问题,但是只要401,就会弹出spring security的默认登录页。如下图
排查过程
试过很多方式,比方:禁用formLogin(),禁用httpBasic都没有用,包括在@SpringBootApplication注解上加(exclude = {SecurityAutoConfiguration.class})也不行。谷歌百度的方法大多都试过了,找不到合适的解决办法。
后来突然想到项目中的security引入是借鉴的码云的一个大佬的项目,就想试试看别人的项目会不会也这样,结果跑起来发现并不会。这样就找到解决的方向了,一定是配置出现了什么问题。所以就在一切在401可能访问到的过滤器上打断点,然后和自己项目对比,终于发现了区别。是自定义继承HttpBasicServerAuthenticationEntryPoint的类有区别
码云大佬地址:https://gitee.com/AloneH/spring-security_springcloud-gateway.git
package com.vdpub.auth.security.webflux.handler;
import com.vdpub.auth.security.webflux.utils.ResponseUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.server.authentication.HttpBasicServerAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @description: 自定义token验证失败处理逻辑
* * 1、token验证失败的处理逻辑(token为空,或者过期时)
* * 2、设置响应头
* * 3、写入响应内容
* @author: Max
* @create: 2021-03-05 17:53
**/
@Component
public class CustomHttpBasicServerAuthenticationEntryPoint extends HttpBasicServerAuthenticationEntryPoint /* implements ServerAuthenticationEntryPoint */{
/**新的定义*/
private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
private static final String DEFAULT_REALM = "Realm";
private static final String WWW_AUTHENTICATE_FORMAT = "Basic %s"; // 区别所在
/**原定义***/
// private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
// private static final String DEFAULT_REALM = "Realm";
// private static String WWW_AUTHENTICATE_FORMAT = "Basic realm=\"%s\""; // 区别所在
private final String headerValue = createHeaderValue(DEFAULT_REALM);
public CustomHttpBasicServerAuthenticationEntryPoint() {
}
/**
* 创建错误响应头中的Authenticate
* @param realm
* @return
*/
private static String createHeaderValue(String realm) {
Assert.notNull(realm, "realm cannot be null");
return String.format(WWW_AUTHENTICATE_FORMAT, realm);
}
@Override
public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException e) {
ServerHttpResponse response = exchange.getResponse();
// 设置响应头
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().set(WWW_AUTHENTICATE, this.headerValue);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
// 三设置 验证异常返回信息
String responseBodyString = ResponseUtil.getResponse(e.getMessage(), HttpStatus.UNAUTHORIZED);
byte[] responseBodyBytes = responseBodyString.getBytes();
// 写入信息
return response.writeWith(Mono.just(response.bufferFactory().wrap(responseBodyBytes)));
}
}
解决办法
既然发现了是这里的区别,就直接进行了替换,将上述贴的代码中注释中的原定义内容换成新定义的内容即可。
主要是请求头的问题,换完以后,请求头由图一变为图二
图一:
图二:
至此问题解决,欢迎大家有问题一起讨论。不对地方也请大家指出、
转载请注明出处