我是 Spring Boot 的新手。我有三个微服务,一个用于用户注册(身份验证)和登录(授权),另外两个需要从第一个开始授权。
目前,第一个微服务作为身份验证和授权点,因为没有用户可以访问其他两个服务,而无需通过第一个。
显然,我在其他两个服务中检索请求标头,以便能够从数据库中获取唯一的用户详细信息并返回唯一的资源。
@PostMapping("/clients")
public ResponseEntity<ResponseModel> addClient(@Valid @RequestBody Client client, @RequestHeader("Authorization") String auth) {
ClientRequest clientCreated = clientService.addClient(client, auth);
return handleSuccessResponseEntity("Client added successfully", HttpStatus.CREATED, clientCreated);
}
并且还有身份验证过滤器和身份验证入口点来验证所有三个服务中的请求。我不确定这是否是一个好的实现。
@Component
@Slf4j
public class JwtFilter extends OncePerRequestFilter {
@Autowired
private JWTUtility jwtUtility;
@Autowired
private ClientService clientService;
public static String token = null;
public static String userName = null;
public static Long userId = 0L;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authorization = request.getHeader("Authorization");
try{
if (null != authorization && authorization.startsWith("Bearer ")) {
token = authorization.substring(7);
userName = jwtUtility.getEmailAddressFromToken(token);
userId = jwtUtility.getIdFromToken(token);
}
else{
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
ErrorResponse error = new ErrorResponse(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.toString(), "You are not authorized");
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), error);
}
}
catch (Exception e){
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
ErrorResponse error = new ErrorResponse(HttpStatus.FORBIDDEN.value(), HttpStatus.FORBIDDEN.toString(), e.getMessage());
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), error);
}
try{
if (0 != userId && null != userName && SecurityContextHolder.getContext().getAuthentication() == null) {
log.info("token "+token + "\n" + "userId " + userId);
UserDetails userDetails = clientService.getUserById(Long.valueOf(userId), token);
log.info("UserDTO {}", userDetails);
if (jwtUtility.validateTokenTwo(token)) {
log.info("token is valid");
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities()
);
usernamePasswordAuthenticationToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
);
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(request, response);
}
catch (HttpClientErrorException e){
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(e.getRawStatusCode());
ErrorResponse error = new ErrorResponse(e.getRawStatusCode(), String.valueOf(e.getRawStatusCode()), e.getStatusCode());
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), error);
}
}
}
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
logger.error("Responding with unauthorized error. Message - {}", e.getMessage());
httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
ErrorResponse error = new ErrorResponse(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.toString(), "You are not authorized");
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(httpServletResponse.getOutputStream(), error);
}
}
然而,如果可能的话,我想做的是一个专门的服务来处理身份验证,我可以从那里解码令牌,而不必从头中检索它。简而言之,不必从标头中检索令牌。
这可能吗,或者我可以采取什么其他方式作为标准?