当前位置:网站首页>20000 words will take you from 0 to 1 to build an enterprise level microservice security framework
20000 words will take you from 0 to 1 to build an enterprise level microservice security framework
2022-07-26 06:42:00 【Bulst】
《 Core technology of microservice 》 Column included , Welcome to subscribe to
List of articles
Based on the above Spring Security The study of dozens of chapters , You must be right Spring Security The framework has a certain understanding .
Then we start to build a security framework for microservices from scratch , I hope some of these ideas can give you some inspiration .
Technology stack
- spiring security
- jwt
- redis
- nacos registry
- spring cloud gateway
- sentinel
- nacos config
- seata
- mybatis
- mybatis-plus
- xxl-job
- rocketmq
Data interaction and implementation
When it comes to security, it involves authentication and authorization , So what kind of certification , Authorization for what , So the following tables are drawn .
- User table
- Role table
- Permissions on the table
This is also typical of RBAC Model .
All data sheets and project source codes can be searched for official numbers 【 Brest 】 reply 「1024」 You can get .

With the data sheet , Let's improve the specific code implementation .
Implementation of data interaction

Part of the code :
package com.ossa.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ossa.common.api.bean.User;
import org.springframework.stereotype.Component;
@Component
public interface UserMapper extends BaseMapper<User> {
}
package com.ossa.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ossa.common.api.bean.User;
public interface UserService extends IService<User> {
}
package com.ossa.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ossa.common.api.bean.User;
import com.ossa.system.mapper.UserMapper;
import com.ossa.system.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
Certification design
Complete authentication through login , First, the login request should be spared in the configuration class , I implement an anonymous annotation here , The code and analysis will be given later .
The overall design idea : Complete authentication through user name and password , Confirm that the user is trusted , Get according to user information token, Every time you ask, bring token, Complete the verification .
- Get the user information of parameter transmission , user name 、 Password etc. .
String password = authUser.getPassword(); - Put the user name 、 password 、 Encapsulated into UsernamePasswordAuthenticationToken object
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(authUser.getUsername(), password); - Get the authentication manager
AuthenticationManager authenticationManager = authenticationManagerBuilder.getObject(); - authentication
Authentication authentication = authenticationManager.authenticate(authenticationToken); - rewrite
UserDetailsService, Getting user information from a database , To complete the certification process . - After successful certification , Generate according to the authentication information token
- Can be token As key Deposit in redis, use redis The expiration time of jwt Of token Expiration time of token
- Get user identity information
- take token Information and user information return .
Code implementation :
@PostMapping("/login")
@AnonymousAccess
public ResponseEntity<Object> login(@Validated @RequestBody AuthUserDto authUser){
// Password decryption
// String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword());
String password = authUser.getPassword();
// Put the user name 、 password 、 Encapsulated into UsernamePasswordAuthenticationToken object
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(authUser.getUsername(), password);
// Get the authentication manager
AuthenticationManager authenticationManager = authenticationManagerBuilder.getObject();
// Certification core method
Authentication authentication = authenticationManager.authenticate(authenticationToken);
// // After successful certification , Save the authentication information to SecurityContext in
// SecurityContextHolder.getContext().setAuthentication(authentication);
// Generate according to the authentication information token
String token = tokenProvider.createToken(authentication);
// Get user identity information
User one = userService.getOne(new QueryWrapper<User>().eq("username", authUser.getUsername()));
UserDto userDto = new UserDto();
BeanUtils.copyProperties(one,userDto);
stringRedisTemplate.opsForValue().set(properties.getOnlineKey() + token, JSONUtil.toJsonStr(userDto), properties.getTokenValidityInSeconds()/1000, TimeUnit.SECONDS);
// return token And User information
Map<String, Object> authInfo = new HashMap<String, Object>(2) {
{
put("token", properties.getTokenStartWith() + token);
put("user", userDto);
}};
return ResponseEntity.ok(authInfo);
}
package com.ossa.system.filter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ossa.common.api.bean.Privilege;
import com.ossa.common.api.bean.Role;
import com.ossa.common.api.bean.User;
import com.ossa.system.mapper.PrivilegeMapper;
import com.ossa.system.mapper.RoleMapper;
import com.ossa.system.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.persistence.EntityNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserService userService;
private final RoleMapper roleMapper;
private final PrivilegeMapper privilegeMapper ;
@Override
public UserDetails loadUserByUsername(String username) {
User user;
org.springframework.security.core.userdetails.User userDetails;
try {
user = userService.getOne(new QueryWrapper<User>().eq("username", username));
} catch (EntityNotFoundException e) {
// SpringSecurity It will automatically switch UsernameNotFoundException by BadCredentialsException
throw new UsernameNotFoundException("", e);
}
if (user == null) {
throw new UsernameNotFoundException("");
} else {
List<Role> roles = roleMapper.listByUserId(user.getId());
ArrayList<Privilege> privileges = new ArrayList<>();
roles.forEach(role -> privileges.addAll(privilegeMapper.listByRoleId(role.getId())));
ArrayList<String> tag = new ArrayList<>();
privileges.forEach(p -> tag.add(p.getTag()));
List<SimpleGrantedAuthority> collect = tag.stream().map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
userDetails = new org.springframework.security.core.userdetails.User(username, user.getPassword(), collect);
}
return userDetails;
}
}
package com.ossa.system.filter;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.ossa.common.bean.SecurityProperties;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class TokenProvider implements InitializingBean {
private final SecurityProperties properties;
private final StringRedisTemplate stringRedisTemplate;
public static final String AUTHORITIES_KEY = "user";
private JwtParser jwtParser;
private JwtBuilder jwtBuilder;
public TokenProvider(SecurityProperties properties, StringRedisTemplate stringRedisTemplate) {
this.properties = properties;
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public void afterPropertiesSet() {
byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret());
Key key = Keys.hmacShaKeyFor(keyBytes);
jwtParser = Jwts.parserBuilder()
.setSigningKey(key)
.build();
jwtBuilder = Jwts.builder()
.signWith(key, SignatureAlgorithm.HS512);
}
/** * establish Token Settings never expire , * Token The time validity of goes to Redis maintain * * @param authentication / * @return / */
public String createToken(Authentication authentication) {
return jwtBuilder
// Join in ID Make sure that the generated Token It's not consistent
.setId(IdUtil.simpleUUID())
.claim(AUTHORITIES_KEY, authentication.getName())
.setSubject(authentication.getName())
.compact();
}
/** * basis Token Obtain authentication information * * @param token / * @return / */
Authentication getAuthentication(String token) {
Claims claims = getClaims(token);
User principal = new User(claims.getSubject(), "******", new ArrayList<>());
return new UsernamePasswordAuthenticationToken(principal, token, new ArrayList<>());
}
public Claims getClaims(String token) {
return jwtParser
.parseClaimsJws(token)
.getBody();
}
/** * @param token What needs to be checked token */
public void checkRenewal(String token) {
// Determine whether to renew token, Calculation token The expiration time of
Long expire = stringRedisTemplate.getExpire(properties.getOnlineKey() + token, TimeUnit.SECONDS);
long time = expire == null ? 0 : expire * 1000;
Date expireDate = DateUtil.offset(new Date(), DateField.MILLISECOND, (int) time);
// Judge the time difference between the current time and the expiration time
long differ = expireDate.getTime() - System.currentTimeMillis();
// If it is within the scope of renewal inspection , Then it will be renewed
if (differ <= properties.getDetect()) {
long renew = time + properties.getRenew();
stringRedisTemplate.expire(properties.getOnlineKey() + token, renew, TimeUnit.MILLISECONDS);
}
}
public String getToken(HttpServletRequest request) {
final String requestHeader = request.getHeader(properties.getHeader());
if (requestHeader != null && requestHeader.startsWith(properties.getTokenStartWith())) {
return requestHeader.substring(7);
}
return null;
}
}
Authorized design
- Design yourself filter, Intercept our generated token, If token legal , Will token Parse and encapsulate into
UsernamePasswordAuthenticationToken, Save in the security context - To ensure the success of authorization , We need to filter Put it in
UsernamePasswordAuthenticationFilterPre execution
package com.ossa.system.filter;
import cn.hutool.core.util.StrUtil;
import com.ossa.common.bean.SecurityProperties;
import io.jsonwebtoken.ExpiredJwtException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class OssaTokenFilter extends GenericFilterBean {
private static final Logger log = LoggerFactory.getLogger(OssaTokenFilter.class);
private final StringRedisTemplate stringRedisTemplate;
private final TokenProvider tokenProvider;
private final SecurityProperties properties;
/** * @param tokenProvider Token * @param properties JWT */
public OssaTokenFilter(TokenProvider tokenProvider, SecurityProperties properties, StringRedisTemplate stringRedisTemplate) {
this.properties = properties;
this.tokenProvider = tokenProvider;
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String token = resolveToken(httpServletRequest);
// about Token If it is empty, you don't need to check Redis
if (StrUtil.isNotBlank(token)) {
String s = null;
try {
s = stringRedisTemplate.opsForValue().get(properties.getOnlineKey() + token);
} catch (ExpiredJwtException e) {
log.error(e.getMessage());
}
if (s != null && StringUtils.hasText(token)) {
Authentication authentication = tokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
// Token Renewal
tokenProvider.checkRenewal(token);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
/** * Preliminary test Token * * @param request / * @return / */
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(properties.getHeader());
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(properties.getTokenStartWith())) {
// Remove the token prefix
return bearerToken.replace(properties.getTokenStartWith(), "");
} else {
log.debug(" illegal Token:{}", bearerToken);
}
return null;
}
}
The core configuration
package com.ossa.common.security.core.config;
import com.ossa.common.api.anno.AnonymousAccess;
import com.ossa.common.api.bean.SecurityProperties;
import com.ossa.common.api.enums.RequestMethodEnum;
import com.ossa.common.security.core.filter.OssaTokenFilter;
import com.ossa.common.security.core.filter.TokenProvider;
import com.ossa.common.security.core.handler.JwtAccessDeniedHandler;
import com.ossa.common.security.core.handler.JwtAuthenticationEntryPoint;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.util.*;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class OssaSecurityConfigurer extends WebSecurityConfigurerAdapter {
private final TokenProvider tokenProvider;
private final SecurityProperties properties;
private final ApplicationContext applicationContext;
private final JwtAuthenticationEntryPoint authenticationErrorHandler;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
private final StringRedisTemplate stringRedisTemplate;
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
// Remove ROLE_ Prefix
return new GrantedAuthorityDefaults("");
}
@Bean
public PasswordEncoder passwordEncoder() {
// Password encryption
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
OssaTokenFilter customFilter = new OssaTokenFilter(tokenProvider, properties,stringRedisTemplate);
// Search for anonymous tags url: @AnonymousAccess
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping");
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
// Get anonymous tags
Map<String, Set<String>> anonymousUrls = getAnonymousUrl(handlerMethodMap);
httpSecurity
// Ban CSRF
.csrf().disable()
.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class)
// Authorization exception
.exceptionHandling()
.authenticationEntryPoint(authenticationErrorHandler)
.accessDeniedHandler(jwtAccessDeniedHandler)
// prevent iframe Create cross domain
.and()
.headers()
.frameOptions()
.disable()
// Do not create session
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// Static resources and so on
.antMatchers(
HttpMethod.GET,
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/webSocket/**"
).permitAll()
// swagger file
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").permitAll()
// file
.antMatchers("/avatar/**").permitAll()
.antMatchers("/file/**").permitAll()
// Alibaba druid
.antMatchers("/druid/**").permitAll()
// release OPTIONS request
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// Customize anonymous access to all url release : Allow anonymity and band Token visit , Delicacy to every Request type
// GET
.antMatchers(HttpMethod.GET, anonymousUrls.get(RequestMethodEnum.GET.getType()).toArray(new String[0])).permitAll()
// POST
.antMatchers(HttpMethod.POST, anonymousUrls.get(RequestMethodEnum.POST.getType()).toArray(new String[0])).permitAll()
// PUT
.antMatchers(HttpMethod.PUT, anonymousUrls.get(RequestMethodEnum.PUT.getType()).toArray(new String[0])).permitAll()
// PATCH
.antMatchers(HttpMethod.PATCH, anonymousUrls.get(RequestMethodEnum.PATCH.getType()).toArray(new String[0])).permitAll()
// DELETE
.antMatchers(HttpMethod.DELETE, anonymousUrls.get(RequestMethodEnum.DELETE.getType()).toArray(new String[0])).permitAll()
// All types of interfaces are released
.antMatchers(anonymousUrls.get(RequestMethodEnum.ALL.getType()).toArray(new String[0])).permitAll()
// All requests require authentication
.anyRequest().authenticated();
}
private Map<String, Set<String>> getAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) {
Map<String, Set<String>> anonymousUrls = new HashMap<>(6);
Set<String> get = new HashSet<>();
Set<String> post = new HashSet<>();
Set<String> put = new HashSet<>();
Set<String> patch = new HashSet<>();
Set<String> delete = new HashSet<>();
Set<String> all = new HashSet<>();
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
HandlerMethod handlerMethod = infoEntry.getValue();
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
if (null != anonymousAccess) {
List<RequestMethod> requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods());
RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name());
switch (Objects.requireNonNull(request)) {
case GET:
get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case POST:
post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case PUT:
put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case PATCH:
patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
case DELETE:
delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
default:
all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
break;
}
}
}
anonymousUrls.put(RequestMethodEnum.GET.getType(), get);
anonymousUrls.put(RequestMethodEnum.POST.getType(), post);
anonymousUrls.put(RequestMethodEnum.PUT.getType(), put);
anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch);
anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete);
anonymousUrls.put(RequestMethodEnum.ALL.getType(), all);
return anonymousUrls;
}
}
Custom permission annotation
package com.ossa.common.security.core.config;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Service(value = "pc")
public class PermissionConfig {
public Boolean check(String... permissions) {
// Get all permissions of the current user
List<String> permission = SecurityContextHolder.getContext()
.getAuthentication()
.getAuthorities()
.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors
.toList());
// Judge whether all permissions of the current user include the permissions defined on the interface
return permission.contains("ADMIN") || permission.contains("INNER") || permission.contains("OFFICEIT") || Arrays.stream(permissions).anyMatch(permission::contains);
}
}
Permission exception handling
package com.ossa.common.security.core.handler;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
// When a user accesses protected without authorization REST Resource time , This method will be called to send 403 Forbidden Respond to
response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
}
}
package com.ossa.common.security.core.handler;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
// When users try to access secure REST Resources without providing any credentials , This method will be called to send 401 Respond to
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException == null ? "Unauthorized" : authException.getMessage());
}
}
Gateway processing
The gateway only needs to forward token To specific services
Before writing this article , I have upgraded this part to UAA Certification Authority Center , Therefore, there is no relevant code here .
Internal flow processing
In the design process of internal flow , We don't need gateway distribution token, Therefore, in this design , I only in feign Of api Uniformly add permission identification at the interface , And after simple encryption .
And let go of the logo at the above customized permission annotation , Do not verify permissions .
package com.ossa.feign.config;
import com.ossa.feign.util.EncryptUtil;
import feign.Logger;
import feign.Request;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/** * @author issavior * * ================================= * ** * * Modify the contract configuration , Support Feign Original notes * * @return return new Contract.Default() * * * @Bean * public Contract feignContract(){ * return new Contract.Default(); * } * ==================================== */
@Configuration
public class FeignClientConfig implements RequestInterceptor {
/** * Timeout configuration * * @return Request.Options */
@Bean
public Request.Options options() {
return new Request.Options(5, TimeUnit.SECONDS,
5, TimeUnit.SECONDS, true);
}
/** * feign Log level of * * @return The level of logging */
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
/** * Rewrite request interceptor apply Method , Loop request header * * @param requestTemplate Request template */
@Override
public void apply(RequestTemplate requestTemplate) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (Objects.isNull(requestAttributes)) {
return;
}
HttpServletRequest request = ((ServletRequestAttributes) (requestAttributes)).getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
requestTemplate.header(name, values);
}
}
Enumeration<String> bodyNames = request.getParameterNames();
// body.append("token").append("=").append(EncryptUtil.encodeUTF8StringBase64("INNER")).append("&");
if (bodyNames != null) {
while (bodyNames.hasMoreElements()) {
String name = bodyNames.nextElement();
String values = request.getParameter(name);
requestTemplate.header(name,values);
}
}
requestTemplate.header("inner",EncryptUtil.encodeUTF8StringBase64("INNER"));
}
// /**
// * Modify the contract configuration , Support Feign Original notes
// * @return return new Contract.Default()
// */
// @Bean
// public Contract feignContract(){
// return new Contract.Default();
// }
}
Hot column Welcome to subscribe to
边栏推荐
- MySQL optimized index and index invalidation
- 【图像去噪】基于双立方插值和稀疏表示实现图像去噪matlab源码
- 『牛客|每日一题』逆波兰表达式
- 数据库中varchar和Nvarchar区别与联系
- Quick sort
- Children's programming electronic society graphical programming level examination scratch level 1 real problem analysis (multiple choice) June 2022
- 『牛客|每日一题』有效括号序列
- 服装行业如何实现数字化生产模式
- Tiktok web s_ v_ web_ Analysis and implementation of ID parameter generation
- Do it yourself smart home: intelligent air conditioning control
猜你喜欢

Design principle of infrared circuit of single chip microcomputer

Children's programming electronic society graphical programming level examination scratch level 1 real problem analysis (multiple choice) June 2022

"Harmonyos" explore harmonyos applications

@ConstructorProperties注解理解以及其对应使用方式

Proxyman, a native high-performance packet capturing tool, is for you who love learning

MySQL基础篇(二)-- MySQL 基础

『牛客|每日一题』 栈的压入、弹出序列

IP day 10 notes - BGP

CONDA virtual environment envs directory is empty

Force buckle - 4. Find the median of two positive arrays
随机推荐
Database and the future of open source
供应链的多目标协同决策
带你搞透IO多路复用原理(select、poll和epoll)
【C语言】文件操作
Multi target detection
Uitoolkit tool template project
Overview of image classification of vision transformer must read series
Go 的切片与数组
Use scanner to get multiple data types from the keyboard
7. Reverse Integer整数反转
原生高性能抓包工具Proxyman,送给爱学习的你
C language file operation
Conda 虚拟环境envs目录为空
"Niuke | daily question" template stack
Map dictionary and constraints of go
数据库性能测试(mysql)
Design principle of infrared circuit of single chip microcomputer
打开服务器上的 IncludeExceptionDetailInFaults (从 ServiceBehaviorAttribute 或从 &lt;serviceDebug&gt; 配置行为)以便将异常信息发送回
What are the main reasons for server crash
Tiktok web s_ v_ web_ Analysis and implementation of ID parameter generation