【发布时间】:2021-11-18 23:00:32
【问题描述】:
我通过使用承载令牌实现了对 SpringBoot API 的授权,当登录成功时,它被添加到响应的“授权”标头中,然后需要通过我的 React 项目的登录获取方法读取这个令牌并添加到随后的请求“授权”标头。
不幸的是,尽管有人告诉我这是不可能使用 Fetch 的,所以我现在正在尝试重构我的登录功能,以便它在响应正文中返回令牌,而不是在标头中。
我不知道该怎么做,目前没有返回 JSON 正文对象,只有标题,我将不得不更改很多我的 AuthorizationFilter 和 AuthenticationFilter 类。如果有人能指出我正确的方向或建议我改变什么,我将不胜感激。
谢谢。
授权过滤器:
public class AuthorizationFilter extends BasicAuthenticationFilter {
public AuthorizationFilter(AuthenticationManager authenticationManager) { super(authenticationManager);}
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
String header = request.getHeader("Authorization");
if(header == null || !header.startsWith("Bearer")) {
filterChain.doFilter(request,response);
return;
}
UsernamePasswordAuthenticationToken authenticationToken = getAuthentication(request);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request,response);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
String token = request.getHeader("Authorization");
if(token != null) {
String user = Jwts.parser().setSigningKey("SecretKeyToGenJWTs".getBytes())
.parseClaimsJws(token.replace("Bearer",""))
.getBody()
.getSubject();
if(user != null) {
return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
}
return null;
}
return null;
}
}
身份验证过滤器:
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public AuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
setFilterProcessesUrl("/login");
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
com.example.gambit2.domain.User creds = new ObjectMapper().readValue(request.getInputStream(), com.example.gambit2.domain.User.class);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(creds.getUsername(), creds.getPassword(),new ArrayList<>()));
}
catch(IOException e) {
throw new RuntimeException("Could not read request" + e);
}
}
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain, Authentication authentication)
{
String token = Jwts.builder()
.setSubject(((User) authentication.getPrincipal()).getUsername())
.setExpiration(new Date(System.currentTimeMillis() + 864_000_000))
.signWith(SignatureAlgorithm.HS512, "SecretKeyToGenJWTs".getBytes())
.compact();
response.addHeader("Authorization","Bearer " + token);
}
}
UserController的注册方法:
@PostMapping("/signup")
public void signUp(@RequestBody User user) {
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
userRepository.save(user);
System.out.println(user.getUsername() + " SAVED SUCCESSFULLY");
}
反应 Home.js:
const SIGNUP_URL = 'http://localhost:8080/users/signup';
const LOGIN_URL = 'http://localhost:8080/login';
class Home extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated:false,
resData: ''
};
}
componentDidMount() {
const payload = {
"username": "hikaru",
"password": "JohnSmith72-"
};
fetch(SIGNUP_URL, {
method: 'POST',
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
})
.then(response => response.json())
.then((data) => {
console.log(data);
});
fetch(LOGIN_URL, {
method: 'POST',
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
})
.then(response =>
console.log(response.headers.get("Authorization")
);
}
在上面的 fetch 调用中,/signup 成功,服务器输出“Tim 已成功保存”,登录也成功,但令牌作为响应发送,“console.log(response.headers.get ("Authorization")) 返回 'null'。
我知道 CORS fetch 不适用于 auth 标头,因为它只能用于类似 4 个标头,对吗?
我尝试添加一个方法,循环遍历每个条目并打印它们,然后在 .then() 中调用它:
.then(response => this.iterateThroughEntries(response)
);
但这只打印了默认标题,而不是 auth 标题。
谢谢
【问题讨论】:
标签: java reactjs spring spring-boot fetch