第十六章 认证与拦截
前言
认证拦截还是跟之前单机版的一样,代码没多少不一样的地方,唯一有点区别的就是引入了 feign 来查询用户信息。
一、远程服务调用 Feign
- auth/pom.xm 引入依赖
yml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 定义远程服务调用接口
java
@FeignClient(contextId = "feignUpmsService", value = ServiceNameConstants.UMPS_API_SERVICE)
public interface FeignUpmsService {
/**
* 通过用户名查询用户、角色信息
* @param username 用户名
* @return R
*/
@GetMapping(value = "/user/getInfo/{username}")
Result<JwtUserDTO> getInfo(@PathVariable("username") String username);
}
- 开启 Fegin
java
@SpringBootApplication
@EnableFeignClients("com.ailot.cloud.auth.feign")
public class ServiceAuthApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceAuthApplication.class, args);
}
}
二、配置普通服务的拦截规则
之前我们讲过我们的权限拦截是放到每个服务的,所以还需要配置一个针对每个服务的安全配置类,这个安全配置类跟 service-auth 服务的大同小异,只不过只有会话拦截的功能。
在不配置的情况下访问第三方服务接口,会重定向到此界面
配置后访问第三方服务接口
第三方接口加白名单后访问
安全配置代码
java
/**
* 普通服务的安全配置
*/
@Configuration
@EnableConfigurationProperties({PermitUrlProperties.class})
public class SpringSecurityServiceConfigurer {
private final PermitUrlProperties permitUrlProperties;
public SpringSecurityServiceConfigurer(PermitUrlProperties permitUrlProperties) {
this.permitUrlProperties = permitUrlProperties;
}
/**
* Configuration using lambdas
*
* @param http
* @return
* @throws Exception
*/
@Bean
@ConditionalOnMissingBean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();
permitUrlProperties.getUrls()
.forEach(url -> registry.antMatchers(url).permitAll());
registry.anyRequest().authenticated();
http
//禁用表单登录
.formLogin().disable()
// 关闭csrf
.csrf((csrf) -> csrf.disable())
//禁用session,JWT校验不需要session
.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.exceptionHandling((exception) -> exception
// 未授权异常处理
.accessDeniedHandler(new JwtAccessDeniedHandler()));
http.addFilterAfter(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
return new JwtAuthenticationTokenFilter(permitUrlProperties);
}
三、配置 Fegin 调用免认证
前面的远程服务调用是通过加白名单来放行的,但是内部服务之间调用应该是免认证,所以还需要配置一个内部服务调用的标记,用来放行服务间的调用。 具体思路就是在 feign 调用的时候,在其请求的 headr 中添加一个标记;每次请求的时候先通过 gateway 清洗掉这个标记(fegin 调用不通过 gateway,清洗的目是为了防止非法请求),然后在具体服务里面拦截这个请求,验证是否为内部服务调用,部分代码如下:
yml
# feign 配置
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: FULL
# 内部调用的header标记
defaultRequestHeaders:
X-FROM-INTERNAL-XXX: WOW
java
// 清洗请求头中的内部调用标记,防止非法请求
ServerHttpRequest request = exchange.getRequest().mutate()
.headers(httpHeaders -> httpHeaders.remove(SecurityConstant.FROM))
.build();
java
/**
* 判断是否内部调用
* @param request
* @return
*/
public boolean isInner(HttpServletRequest request) {
return request.getHeader(SecurityConstant.FROM) != null
&& request.getHeader(SecurityConstant.FROM).equalsIgnoreCase(SecurityConstant.FROM_IN);
}
将这个方法加到权限拦截和 token 验证的两个类中,就可以实现内部服务免认证访问了。
测试可以发现直接访问服务接口会提示未登录,但通过 feign 访问则可以正常返回数据。
当前版本 tag:2.0.1 代码仓库
四、 体验地址
后台数据库只给了部分权限,报错属于正常!
想学的老铁给点点关注吧!!!
欢迎留言交流!!!
我是阿咕噜,一个从互联网慢慢上岸的程序员,如果喜欢我的文章,记得帮忙点个赞哟,谢谢!