I've been developing an Spring Boot Project and I'm using JwtToken for authourization
@Slf4j
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
public JwtAuthenticationFilter(
JwtService jwtService,
UserDetailsService userDetailsService,
HandlerExceptionResolver handlerExceptionResolver
) {
this.jwtService = jwtService;
this.userDetailsService = userDetailsService;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String token = resolveToken(request);
log.debug("Token of " + request.getRequestURI() + " : " + token);
if (token != null && jwtService.isTokenValid(token)) {
String username = jwtService.extractUsername(token);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(token, userDetails)) {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
// add token to header
response.addHeader("Authorization", "Bearer " + token);
}
filterChain.doFilter(request, response);
}
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
private String extractTokenFromCookies(Cookie[] cookies) {
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("jwtToken".equals(cookie.getName())) {
return cookie.getValue();
}
}
}
return null;
}
}
Now I want to be able to direct to any request after login and having a token in localStorage by searching this request on the google search bar,such as : http://localhost:8080/profile or other secured endpoints.
I've tried using cookies to store the token to setHeader in the filter function but it doesn't work and I got stuck at this problem without no idea. Could someone help me?? Edit : At first I used fetching to send token to request ,for example:
document.getElementById('profileButton').addEventListener('click', function () {
console.log('Button clicked'); // Kiểm tra xem event click có hoạt động không
fetch('${pageContext.request.contextPath}/profile', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + token // Thêm token vào header
}
})
.then(response => {
if (response.ok) {
return response.text(); // Lấy dữ liệu dưới dạng HTML (text)
} else {
throw new Error('Network response was not ok.');
}
})
.then(html => {
console.log('Success:', html);
// Hiển thị HTML hoặc chuyển hướng trang
document.open(); // Mở tài liệu mới
document.write(html); // Ghi nội dung HTML vào
document.close(); // Đóng tài liệu để hoàn tất việc render
})
.catch(error => {
console.error('Fetch error:', error);
});
});
Now I wanna know how I can auto-send token from localStorage to the header of the request, so that I can access an secured request by searching in google search bar after login successfully, like http://localhost:8080/profile
For security, you need to store the JWT in session storage to protect it, see this SO question; What's the best way to store JWTs on the client
For debugging, Open your browser Inspector and the network tab. Grab the request to ${pageContext.request.contextPath}/profile
and check in your JWT is in the authorization header or not. Or paste it in your question of you need help. Theoretically what you show above should work. Same think ig you try with cookies, analyze the network traffic and ensure that your JWT is sent in the cookie-header.
For scalability, you can create a method that intercepts ALL outgoing requests from your frontend application, adding your authorization header. Make sure you are only sending it to your API though, else you may spread the JWT to all kind of services on the Internet. :-) This is a piece of code I use that you may find inspirational. It replaces the original fetch function with a version that injects the JWT.
window.fetch = async function (
input: RequestInfo | URL,
init?: RequestInit
): Promise<Response> {
const request = new Request(input, init); // Create a new Request object
// Check Domain to not send the JWT to any external actors.
if (!request.url.startsWith(apiUrl)) {
// Call the original fetch method with the provided Request object
return window.originalFetch(request);
}
try {
const token = await getAccessToken();
if (!token) {
return Promise.reject(new Error("Failed to get access token"));
}
// Add the "Authorization" header with the access token to the fetch options
if (!request.headers.get("Authorization")) {
request.headers.append("Authorization", "Bearer " + token);
}
} catch (e) {
log.debug("Exception:" + e);
}
// Call the original fetch method with the modified Request object
return window.originalFetch(request);
};