在做项目的时候,用户身份认证最开始用的是web拦截器来实现的,原理很简单,可以参考这篇文章:springboot拦截器配置_酷乐丶是只猫的博客-CSDN博客
使用Eureka后可以将用户身份认证功能单独从项目中抽取出来,成为一个独立的模块,降低了项目的耦合性,同时也方便其他项目访问该功能。
搭建Eureka项目首先需要搭建一个服务中心,服务中心相当于一个中转站,其中包含了各种服务,服务之间可以相互访问。
首先新建一个spring项目
服务器中心的pom.xml依赖如下(注意spring cloud与springboot的版本对应关系,如果springboot版本过高或者过低,都需要调整spring cloud的版本,这里用的springboot的版本是2.6.1,对应的spring cloud版本是2021.0.0):
1.8
2021.0.0
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
接着再配置一下yml文件。
eureka.client.registerWithEureka 表示是否将自己注册到Eureka服务中心,因为其本身就是个服务中心,因此设为false。
eureka.client.fetchRegistry 表示是否从Eureka服务中心获取注册信息,同样也是设为false。
eureka.client.serviceUrl.defaultZone :设置与Eureka服务中心交互地址,查询服务和注册服务都需要依赖这个地址。
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
然后配置下spring启动类,添加一个@EnableEurekaServer注解即可:
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
部署完服务中心后,需要将网关服务注册进服务中心,这里用到的是spring cloud gateway。
同样先新建一个spring项目。
pom.xml依赖如下
org.projectlombok
lombok
provided
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-gateway
org.apache.commons
commons-lang3
io.jsonwebtoken
jjwt-api
${jwt.version}
io.jsonwebtoken
jjwt-impl
${jwt.version}
runtime
io.jsonwebtoken
jjwt-jackson
${jwt.version}
runtime
com.alibaba
fastjson
1.2.60
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
接着配置yml文件,这里配置了gateway的属性,discovery开启服务注册中心服务发现,routes为网关路由配置,当通过网关认证时,页面会跳转到url中的路径;predicates则会对匹配的请求进行过滤验证;filters为过滤器配置,JwtAuthorization为过滤器名字:
server:
port: 8877
spring:
application:
name: microservice-eureka-user
cloud:
gateway:
discovery:
locator:
enabled: true #开启 Gateway 服务注册中心服务发现
lower-case-service-id: true
routes:
- id: api
uri: http://localhost:8888
predicates:
- Path=/api/**
filters:
- StripPrefix=0
- JwtAuthorization
eureka:
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${server.port}
ip-address: ${spring.cloud.client.ip-address}
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
healthcheck:
enabled: true
filter工厂配置:
@Component
public class JwtAuthorizationGatewayFilterFactory extends AbstractGatewayFilterFactory
filter配置:
@Component
public class JwtAuthorizationFilter implements GatewayFilter, Ordered {
List ignoreList = Arrays.asList("/api/loginPage/login");
/**
* 该值要和auth-server中配置的签名相同
*
* com.kdyzm.spring.security.auth.center.config.TokenConfig#SIGNING_KEY
*/
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
boolean access = true;
ServerHttpRequest serverReques = exchange.getRequest();
// 将Payload数据放到header
ServerHttpRequest.Builder builder = serverReques.mutate();
if(!access){
return unAuthorized(exchange,"认证不通过",null);
}
// 继续执行
return chain.filter(exchange.mutate().request(builder.build()).build());
}
private Mono unAuthorized(ServerWebExchange exchange, String msg,Integer status) {
try {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
//这里需要指定响应头部信息,否则会中文乱码
exchange.getResponse().getHeaders().add("Content-Type", "application/json;charset=UTF-8");
JSONObject ret=new JSONObject();
if(Objects.isNull(status)) {
ret.put("code", 401);
ret.put("message", msg);
ret.put("data",null);
}else{
ret.put("code", status);
ret.put("message", msg);
ret.put("data",null);
}
String s = objectMapper.writeValueAsString(ret);
DataBuffer buffer = exchange
.getResponse()
.bufferFactory()
.wrap(s.getBytes(StandardCharsets.UTF_8));
return exchange.getResponse().writeWith(Flux.just(buffer));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将该过滤器的优先级设置为最高,因为只要认证不通过,就不能做任何事情
*
* @return
*/
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
当请求进行过滤时会先进入filter方法,该方法可以设置一些请求认证的功能,当请求通过认证时,返回chain.filter继续执行,否则返回unAuthorized方法拒绝通过网关。