Я хочу вернуть JWT в исходное состояние, когда я нажимаю '/ login'.Но я что-то упускаю и не могу понять.
Ниже приведен мой код:
SecurytiApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@EnableJpaRepositories
@ComponentScan(basePackages = "com.example.securyti")
@EntityScan(basePackages = "com.example.securyti")
@SpringBootApplication
public class SecurytiApplication {
public static void main(String[] args) {
SpringApplication.run(SecurytiApplication.class, args);
}
}
SecurityConfig.java
package com.example.securyti.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.example.securyti.security.UserAccountService;
import com.example.securyti.security.jwt.JwtAuthenticationFilter;
import com.example.securyti.security.jwt.JwtAuthorizationFilter;
import com.example.securyti.security.jwt.JwtTokenService;
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
protected JwtAuthenticationFilter jwtAuthenticationFilter;
protected JwtAuthorizationFilter JwtAuthorizationFilter;
@Autowired
protected UserAccountService userAccountService;
@Autowired
protected JwtTokenService jwtTokenService;
@Autowired
protected ConfigurationService configService;
@Override
protected void configure(HttpSecurity http) throws Exception {
final AuthenticationManager authenticationManager = authenticationManager();
jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager,
jwtTokenService, (BCryptPasswordEncoder) passwordEncoder(), userAccountService);
JwtAuthorizationFilter = new JwtAuthorizationFilter(authenticationManager,
configService, jwtTokenService);
http
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/register")
.permitAll()
.anyRequest().authenticated().and().addFilter(jwtAuthenticationFilter).addFilter(JwtAuthorizationFilter);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(final AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userAccountService).passwordEncoder(passwordEncoder());
}
}
JwtAuthenticationFilter.java
package com.example.securyti.security.jwt;
import java.io.IOException;
import java.util.Collections;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.StringUtils;
import com.example.securyti.security.UserAccount;
import com.example.securyti.security.UserAccountService;
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
private final AuthenticationManager authenticationManager;
private final JwtTokenService jwtTokenService;
private final BCryptPasswordEncoder passwordEncoder;
private final UserAccountService userAccountService;
public JwtAuthenticationFilter(
final AuthenticationManager authenticationManager,
final JwtTokenService jwtTokenService,
final BCryptPasswordEncoder passwordEncoder,
final UserAccountService userAccountService) {
this.authenticationManager = authenticationManager;
this.jwtTokenService = jwtTokenService;
this.passwordEncoder = passwordEncoder;
this.userAccountService = userAccountService;
}
@Override
public Authentication attemptAuthentication(final HttpServletRequest req,
final HttpServletResponse res) {
String jwt = jwtTokenService.getTokenFromRequest(req);
UserAccount userAccount = null;
if (StringUtils.hasText(jwt) && jwtTokenService.validateToken(jwt)) {
userAccount = (UserAccount) userAccountService.loadUserByUsername(jwtTokenService.getUsernameFromJWT(jwt));
}
if(userAccount == null){
throw new BadCredentialsException("Bad credentials");
}
AbstractAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userAccount.getUsername(),
userAccount.getPassword(), Collections.emptyList());
Authentication auth = authenticationManager.authenticate(authToken);
return auth;
}
private String getUsername(final UserAccount creds) {
if (creds != null) {
return creds.getUsername();
}
return null;
}
@Override
protected void successfulAuthentication(final HttpServletRequest req,
final HttpServletResponse res, final FilterChain chain,
final Authentication auth) throws IOException, ServletException {
final UserAccount account = (UserAccount) auth.getPrincipal();
jwtTokenService.addTokenToResponse(account, res);
super.successfulAuthentication(req, res, chain, auth);
}
}
JwtAuthorizationFilter.java
package com.example.securyti.security.jwt;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import com.example.securyti.config.ConfigurationService;
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
private ConfigurationService configService;
private JwtTokenService jwtTokenService;
public JwtAuthorizationFilter(AuthenticationManager authManager, ConfigurationService configService,
final JwtTokenService jwtTokenService) {
super(authManager);
this.configService = configService;
this.jwtTokenService = jwtTokenService;
}
@Override
protected void doFilterInternal(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain) throws IOException, ServletException {
String header = req.getHeader(configService.getHeaderField());
if (header == null || !header.startsWith(configService.getTokenPrefix())) {
chain.doFilter(req, res);
return;
}
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
String token = request.getHeader(configService.getHeaderField());
if (token != null) {
// parse the token.
String user = jwtTokenService.getUsernameFromJWT(token);
if (user != null) {
return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
}
return null;
}
return null;
}
}
JwtTokenService.java (это просто класс помощника)
package com.example.securyti.security.jwt;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.example.securyti.config.ConfigurationService;
import com.example.securyti.security.UserAccount;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
@Service
public class JwtTokenService {
private static final Logger logger = LoggerFactory.getLogger(JwtTokenService.class);
private ConfigurationService configurationService;
public JwtTokenService(final ConfigurationService configurationService) {
super();
this.configurationService = configurationService;
}
String getTokenFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader(configurationService.getHeaderField());
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(configurationService.getTokenPrefix())) {
return bearerToken.substring(7, bearerToken.length());
}
return null;
}
public void addTokenToResponse(UserAccount account, HttpServletResponse res) {
LocalDateTime expiry = LocalDateTime.now().plusSeconds(configurationService.getJwtExpirationInSec());
String token = Jwts.builder()
.setSubject(account.getUsername())
.setIssuedAt(new Date())
.setExpiration(Date.from(expiry.atZone(ZoneId.systemDefault()).toInstant()))
.signWith(SignatureAlgorithm.HS512, configurationService.getJwtSecret())
.compact();
res.addHeader(configurationService.getHeaderField(), configurationService.getTokenPrefix() + token);
}
public String getUsernameFromJWT(String token) {
Claims claims = Jwts.parser()
.setSigningKey(configurationService.getJwtSecret())
.parseClaimsJws(token)
.getBody();
return claims.getSubject();
}
public boolean validateToken(String authToken) {
try {
Jwts.parser().setSigningKey(configurationService.getJwtSecret()).parseClaimsJws(authToken);
return true;
} catch (SignatureException ex) {
logger.error("Invalid JWT signature");
} catch (MalformedJwtException ex) {
logger.error("Invalid JWT token");
} catch (ExpiredJwtException ex) {
logger.error("Expired JWT token");
} catch (UnsupportedJwtException ex) {
logger.error("Unsupported JWT token");
} catch (IllegalArgumentException ex) {
logger.error("JWT claims string is empty.");
}
return false;
}
}
application.properties
spring.datasource.url= jdbc:mysql://localhost:3306/mydb
spring.datasource.username= root
spring.datasource.password= root
spring.jpa.hibernate.ddl-auto = update
#TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
logging.level.root=DEBUG
## JWT
jwt.secret= JWTSuperSecretKey
jwt.expirationInSec = 10
jwt.tokenPrefix = Bearer
jwt.headerField = Authorization
Нет обработчикаметод '\ login' в контроллере.В настоящее время, когда я нажимаю '/ login' с действительными именем пользователя и паролем, я получаю 403 со следующим сообщением на консоли:
Bad credentials
at com.example.securyti.security.jwt.JwtAuthenticationFilter.attemptAuthentication(JwtAuthenticationFilter.java:58)
Чего мне не хватает.Пожалуйста, поправьте меня, если мое понимание где-то не так.Заранее спасибо.