spring boot + spring security + jwt + React 不工作
Posted
技术标签:
【中文标题】spring boot + spring security + jwt + React 不工作【英文标题】:spring boot + spring security + jwt + React not working 【发布时间】:2021-07-28 12:56:46 【问题描述】:我正在使用 Spring boot 2.4 + spring security + jwt + React 构建一个新项目。我们在 react 中创建了一个登录页面,并且 react 构建位于静态文件夹中。 请找到以下代码: 我的security.java
@Configuration
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter
@Autowired
UserDetailServiceImpl userDetails;
@Autowired
JWTAuthenticationFilter jwtRequestFilter;
@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userDetails);
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
httpSecurity.cors().and().csrf().disable().authorizeRequests()
.antMatchers("/login/**, /resources/**").permitAll()
.antMatchers("/authenticate/**").permitAll()
.anyRequest().authenticated()
.and().exceptionHandling()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Bean
public PasswordEncoder getPasswordEncoder()
return NoOpPasswordEncoder.getInstance();
在 UserDetailServiceImpl 中,我们从 mysql db 中获取用户 loadUserByUsername(字符串用户名)
JWTAuthenticationFilter.java
@Component
public class JWTAuthenticationFilter extends OncePerRequestFilter
@Autowired
private UserDetailServiceImpl userDetailService;
@Autowired
private JwtTokenUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer "))
jwt = authorizationHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null)
UserDetails userDetails = this.userDetailService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails))
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
filterChain.doFilter(request, response);
JwtTokenUtil.java
@Component
public class JwtTokenUtil implements Serializable
private static final long serialVersionUID = -3301605591108950415L;
static final String CLAIM_KEY_USERNAME = "sub";
static final String CLAIM_KEY_AUDIENCE = "aud";
static final String CLAIM_KEY_CREATED = "iat";
static final String AUDIENCE_UNKNOWN = "unknown";
static final String AUDIENCE_WEB = "web";
static final String AUDIENCE_MOBILE = "mobile";
static final String AUDIENCE_TABLET = "tablet";
//@Value("$jwt.secret")
private String secret="ThisIsASecret";
//@Value("$jwt.expiration")
private Long expiration=604800L;
public String extractUsername(String token)
return extractClaim(token, Claims::getSubject);
public Date extractExpiration(String token)
return extractClaim(token, Claims::getExpiration);
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver)
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
private Claims extractAllClaims(String token)
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
private Boolean isTokenExpired(String token)
return extractExpiration(token).before(new Date());
public String generateToken(UserDetails userDetails)
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
private String createToken(Map<String, Object> claims, String subject)
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
.signWith(SignatureAlgorithm.HS256, secret).compact();
public Boolean validateToken(String token, UserDetails userDetails)
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
我的控制器:
@RestController
public class LoginController
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserDetailServiceImpl userDetailsService;
@GetMapping(value = "/welcome" )
public String welcome(HttpServletRequest request) throws Exception
return "login sucess";
@PostMapping(value = "/authenticate")
public ResponseEntity<?> createAuthenticationToken(@RequestBody AccountCredentials authenticationRequest) throws Exception
try
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())
);
catch (BadCredentialsException e)
throw new Exception("Incorrect username or password", e);
final UserDetails userDetails = userDetailsService
.loadUserByUsername(authenticationRequest.getUsername());
final String jwt = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new AuthenticationResponse(jwt));
/authenticate 是禁止的,经过邮递员测试。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.cmp</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>project</name>
<description>Project boot react</description>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
我们正在寻找登录页面出现并生成 jwt + 通过所有安全性。它说禁止来自邮递员的 /authenticate api 并且 /login 未找到(登录页面是在反应中创建的,并且构建在资源/静态文件夹中)。注意:我们在单服务器上运行,即tomcat 9 + java 11。控制台没有异常。
【问题讨论】:
请提出任何建议,请让我知道您的想法? 【参考方案1】:我想通了。代码改动很少。
类 JWTAuthenticationFilter -> 改变 UsernamePasswordAuthenticationToken 参数 userDetails 到 userDetails.getUserName();
class WebSecurity -> 添加了 passwordEncoder(getPasswordEncoder());
如果有人需要帮助来实施它,请发表评论。谢谢
【讨论】:
以上是关于spring boot + spring security + jwt + React 不工作的主要内容,如果未能解决你的问题,请参考以下文章
UnsatisfiedDependencyException:创建名为“securityConfig”的 bean 时出错