我的应用程序从我的数据库(端点“/server/list”)发送一个json服务器列表。它没有所有的身份验证的东西工作正常。我把这个Tutorial中的所有东西都实现到了我的应用程序中,当我发送一个 Postman 请求时,我可以毫无问题地注册一个用户:
http://localhost:8080/auth/register
{
"firstname": "Mary",
"lastname": "Hyne",
"email": "maryhyne@google.com",
"password": "asdf"
}
生成一个JWT令牌,我在另一个请求的Authorization头中使用它们:
http://localhost:8080/server/list(授权->承载令牌)
但我总是得到一个403禁止的答案。也没有什么有用的例外。只有消息“Mapped to org.springframework. Boot .autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)"。所以我不知道什么是错的。因为我甚至不能理解错误可能是什么,我发布了最重要的代码。我将省去服务器存储库的东西,因为它可以工作:
API.ServerController
package com.socie.backend.api;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.socie.backend.model.Response;
import com.socie.backend.service.implementation.ServerServiceImpl;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/server")
@RequiredArgsConstructor
public class ServerController {
private final ServerServiceImpl serverService;
@GetMapping("/list")
public ResponseEntity<Response> getServers() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
return ResponseEntity.ok(
Response.builder()
.timestamp(LocalDateTime.now())
.data(Map.of("servers", serverService.list(30)))
.message("Servers retrieved")
.status(HttpStatus.OK)
.statusCode(HttpStatus.OK.value())
.build()
);
}
}
API. Authentication Controller
package com.socie.backend.api;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.socie.backend.model.AuthenticationRequest;
import com.socie.backend.model.AuthenticationResponse;
import com.socie.backend.model.RegisterRequest;
import com.socie.backend.service.AuthenticationService;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthenticationController {
private final AuthenticationService authService;
@PostMapping("/register")
public ResponseEntity<AuthenticationResponse> register(@RequestBody RegisterRequest request) {
return ResponseEntity.ok(authService.register(request));
}
@PostMapping("/authenticate")
public ResponseEntity<AuthenticationResponse> register(@RequestBody AuthenticationRequest request) {
return ResponseEntity.ok(authService.authenticate(request));
}}
service.AuthenticationService
package com.socie.backend.service;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import com.socie.backend.config.JwtService;
import com.socie.backend.model.AuthenticationRequest;
import com.socie.backend.model.AuthenticationResponse;
import com.socie.backend.model.RegisterRequest;
import com.socie.backend.model.Role;
import com.socie.backend.model.User;
import com.socie.backend.repo.UserRepo;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class AuthenticationService {
private final UserRepo userRepo;
private final PasswordEncoder passwordEncoder;
private final JwtService jwtService;
private final AuthenticationManager authenticationManager;
public AuthenticationResponse register(RegisterRequest request) {
var user = User.builder()
.firstname(request.getFirstname())
.lastname(request.getLastname())
.email(request.getEmail())
.password(passwordEncoder.encode(request.getPassword()))
.role(Role.USER)
.build();
userRepo.save(user);
var jwtToken = jwtService.generateToken(user);
return AuthenticationResponse.builder()
.token(jwtToken)
.build();
}
public AuthenticationResponse authenticate(AuthenticationRequest request) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
request.getEmail(),
request.getPassword()
)
);
var user = userRepo.findByEmail(request.getEmail())
.orElseThrow();
var jwtToken = jwtService.generateToken(user);
return AuthenticationResponse.builder()
.token(jwtToken)
.build();
}
}
config.ApplicationConfig
package com.socie.backend.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.socie.backend.repo.UserRepo;
import lombok.RequiredArgsConstructor;
@Configuration
@RequiredArgsConstructor
public class ApplicationConfig {
private final UserRepo userRepo;
@Bean
public UserDetailsService userDetailsService() {
return username -> userRepo.findByEmail(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
config.JwtAuthenticationFilter
package com.socie.backend.config;
import java.io.IOException;
import org.springframework.lang.NonNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
@NonNull FilterChain filterChain) throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
final String jwt;
final String userEmail;
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
;
return;
}
jwt = authHeader.substring(7);
userEmail = jwtService.extractUsername(jwt);
if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail);
if (jwtService.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails,
null,
userDetails.getAuthorities()
);
authToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
}
config.JwtService
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
@Service
public class JwtService {
private static final String SECRET_KEY = "ec9d2d0f7dd840b43cb0e52c189eb4c06c3b0307c2abf4c5aeef0d689ad12f19";
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
public String generateToken(
Map<String, Object> extraClaims,
UserDetails userDetails)
{
return Jwts
.builder()
.setClaims(extraClaims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 24))
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
.compact();
}
public boolean isTokenValid(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails) && !isTokenExpired(token));
}
private boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
private Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
public String generateToken(UserDetails userDetails) {
return generateToken(new HashMap<>(), userDetails);
}
public Claims extractAllClaims(String token) {
return Jwts.
parserBuilder()
.setSigningKey(getSignInKey())
.build()
.parseClaimsJws(token)
.getBody();
}
private Key getSignInKey() {
byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
return Keys.hmacShaKeyFor(keyBytes);
}
}
config.SecurityConfiguration
package com.socie.backend.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import lombok.RequiredArgsConstructor;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {
private final AuthenticationProvider authenticationProvider;
private final JwtAuthenticationFilter jwtAuthFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeHttpRequests()
.requestMatchers("/auth/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
1条答案
按热度按时间mgdq6dx11#
在JWTService中,您将执行以下操作
应该改为“return username.equals(userDetails. getName())....”或类似的。
目前isTokenValid()总是返回false,因为username是String,userDetails是UserDetails类型的对象。这将导致使用此方法确认的所有端点返回403。