当我使用 JWT TOKEN(“授权”)从 js 向 Spring Boot 响应发送登录请求时 JWT 令牌出现在“网络”选项卡中,但响应授权标头在 JavaScript 中保持为空
Javascript 获取 api
import { SIGN_IN, SIGN_UP } from "./ActionType";
export const signinAction = (data) => async (dispatch) => {
try {
const res = await fetch("http://localhost:5050/signin", {
method: "GET",
headers: {
Authorization: "Basic " + btoa(data.email + ":" + data.password),
},
});
console.log(res);
const user = await res.json();
console.log("signin user: ", user);
const token = res.headers.get("Authorization");
localStorage.setItem("token", token);
dispatch({ type: SIGN_IN, payload: token });
console.log("signin token: ", token);
} catch (error) {
console.log(error);
}
};
export const signupAction = (data) => async (dispatch) => {
try {
const res = await fetch("http://localhost:5050/signup", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: data.email,
name: data.name,
userName: data.userName,
password: data.password,
}),
});
const user = await res.json();
console.log("signup user: ", user);
dispatch({ type: SIGN_UP, payload: user });
} catch (error) {
console.log(error);
}
};
休息控制器/登录
package com.vinitpk.instagramapi.instagram.controller;
import com.vinitpk.instagramapi.instagram.exception.UserException;
import com.vinitpk.instagramapi.instagram.model.User;
import com.vinitpk.instagramapi.instagram.repository.UserRepository;
import com.vinitpk.instagramapi.instagram.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
@RestController
public class AuthController {
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@PostMapping("/signup")
public ResponseEntity<User> registerUserHandler(@RequestBody User user) throws UserException {
User createdUser = userService.registerUser(user);
System.out.println(createdUser.getUserName());
return new ResponseEntity<User>(createdUser, HttpStatus.OK);
}
@GetMapping("/signin")
public ResponseEntity<User> signinUserHandler(Authentication authentication ) throws BadCredentialsException {
Optional<User> optionalUser = userRepository.findByEmail(authentication.getName());
System.out.println(optionalUser.get());
if(optionalUser.isPresent()){
return new ResponseEntity<User>(optionalUser.get(),HttpStatus.OK);
}
throw new BadCredentialsException("Invalid User name or password");
}
}
JWT 令牌生成器
package com.vinitpk.instagramapi.instagram.configuration;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.crypto.SecretKey;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
@Component
public class JwtTokenGeneratorFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException
{
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication != null){
SecretKey key = Keys.hmacShaKeyFor(SecurityContext.JWT_KEY.getBytes());
String jwt = Jwts.builder()
.issuer("instagram")
.issuedAt(new Date())
.claim("authorities", populateAuthorities(authentication.getAuthorities()))
.claim("userName", authentication.getName())
.expiration(new Date(new Date().getTime() + (10 * 60 * 60 * 1000)))
.signWith(key).compact();
response.setHeader(SecurityContext.Header, jwt);
System.out.println(jwt);
}
filterChain.doFilter(request, response);
}
public String populateAuthorities(Collection<? extends GrantedAuthority> collection){
Set<String> authorities = new HashSet<>();
for(GrantedAuthority authority : collection){
authorities.add(authority.getAuthority());
}
return String.join(",", authorities);
}
protected boolean shouldNotFilter(HttpServletRequest httpServletRequest) throws ServletException{
return !httpServletRequest.getServletPath().equals("/signin");
}
}
Jwt 令牌验证器
package com.vinitpk.instagramapi.instagram.configuration;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.crypto.SecretKey;
import java.io.IOException;
import java.util.List;
/**
* @author: Vinit Kelginmane
* @project: instagram-api-springboot
* @Date: 12-02-2024
*/
@Component
public class JwtTokenValidationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException
{
String jwt = request.getHeader(SecurityContext.Header);
System.out.println(jwt);
if(jwt != null){
try{
jwt = jwt.substring(7);
SecretKey key = Keys.hmacShaKeyFor(SecurityContext.JWT_KEY.getBytes());
Claims claims = Jwts.parser().verifyWith(key).build().parseSignedClaims(jwt).getPayload();
String userName = String.valueOf(claims.get("userName"));
String authorities = (String)claims.get("authorities");
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList(authorities);
Authentication token = new UsernamePasswordAuthenticationToken(userName, null, auths);
SecurityContextHolder.getContext().setAuthentication(token);
}
catch (Exception e){
throw new BadCredentialsException("Invalid Token");
}
}
filterChain.doFilter(request, response);
}
protected boolean shouldNotFilter(HttpServletRequest httpServletRequest) throws ServletException{
return httpServletRequest.getServletPath().equals("/signin");
}
}
但是响应头为空
在
CorsConfiguration
中添加了
SecurityFilterChain
.cors(c-> c.configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST","DELETE","PUT"));
corsConfiguration.setAllowedMethods(Collections.singletonList("*"));
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setAllowedHeaders(Collections.singletonList("*"));
corsConfiguration.setExposedHeaders(Arrays.asList("Authorization"));
return corsConfiguration;
}
}))