wer*_*erw 5 java spring spring-security reactjs axios
我正在尝试编写一个具有独立后端(使用 Spring Boot 和 Spring Security 进行登录)和前端(ReactJS)的应用程序。现在,我正在努力在成功登录后访问安全端点。
我想要实现的目标:对安全端点进行 GET,例如“/books/all”。如果用户未登录,则返回 401。如果前端收到 401,则对 '/login' 进行 POST。然后我想要成功登录并能够成功获取到“/books/all”。
什么不起作用:最后一部分。我正在向 '/login' 发送 POST 并收到 200 GET。然后我再次调用“/books/all”并收到 GET 401。此外,我不再收到让我担心的 JSESSIONID cookie。
我的问题:如何解决这种行为?我相信它已连接到 JSESSIONID(服务器不发送有关用户成功登录的信息?)。
在前端,我使用 axios。
axios.get('http://localhost:8080/rest/book/anna/all')
.then(response => {
console.log('response rebuild');
console.log(response);
if (response.status === 401 && response.request.responseURL === 'http://localhost:8080/login') {
axios.post('http://localhost:8080/login', 'username=c&password=d')
.then(response => {
console.log('response 2');
console.log(response);
})
.catch(error => {
console.log('error');
console.log(error);
})
}
})
.catch(error => {
console.log('error 2');
console.log(error);
axios.post('http://localhost:8080/login', 'username=c&password=d')
.then(response => {
console.log('response 2');
console.log(response);
axios.get('http://localhost:8080/rest/book/anna/all')
.then(response => {
console.log('response 3');
console.log(response);
})
.catch(error => {
console.log('error 3');
console.log(error);
})
})
.catch(error => {
console.log('error');
console.log(error);
})
});
Run Code Online (Sandbox Code Playgroud)
请注意,我知道这段代码质量很低;检查登录后重定向是否有效只是暂时的。
安全配置文件
package com.shareabook.security;
import com.shareabook.repository.UsersRepository;
import com.shareabook.service.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@EnableJpaRepositories(basePackageClasses = UsersRepository.class)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private RESTAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
private RESTAuthenticationSuccessHandler restAuthenticationSuccessHandler;
@Autowired
private RESTAuthenticationFailureHandler restAuthenticationFailureHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(getPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers("**/anna/**").authenticated()
.anyRequest().permitAll();
http.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint);
http.formLogin().successHandler(restAuthenticationSuccessHandler);
http.formLogin().failureHandler(restAuthenticationFailureHandler);
// .and()
// .formLogin().permitAll();
http
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/rest/author/all");
}
private PasswordEncoder getPasswordEncoder() {
return new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return true;
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
RESTAuthenticationEntryPoint.java
@Component
public class RESTAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
Run Code Online (Sandbox Code Playgroud)
RESTAuthenticationFailureHandler.java
@Component
public class RESTAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException,
ServletException {
super.onAuthenticationFailure(request, response, exception);
}
}
Run Code Online (Sandbox Code Playgroud)
RESTAuthenticationSuccessfulHandler.java
@Component
public class RESTAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
// clearAuthenticationAttributes(request);
HttpSession session = request.getSession();
session.setAttribute("username", "c");
response.setStatus(HttpServletResponse.SC_OK);
}
}
Run Code Online (Sandbox Code Playgroud)
图书控制器.java
@RestController
@RequestMapping("/rest/book")
public class BookController {
@CrossOrigin(origins = "http://localhost:8888")
@PreAuthorize("hasAnyRole('ROLE_ADMIN')")
@RequestMapping(value = "/anna/all", method = RequestMethod.GET)
public List<String> securedHello() {
List<String> word = new ArrayList<>();
word.add("all");
System.out.print(word);
return word;
}
}
Run Code Online (Sandbox Code Playgroud)
小智 7
您已在应用程序上启用表单身份验证。当您将帖子发送到登录页面时,Spring 会对您的请求进行身份验证,并默认在用户会话上缓存身份验证。
稍后您可以将请求发送到绑定到同一会话的服务器,而无需额外的身份验证信息。但您需要根据您的请求提供会话信息。通常这是通过在您的下一个请求中提供JSESSIONIDcookie 来完成的。浏览器会自动为您执行此操作,但仅在页面重新加载后才执行。如果您停留在同一页面,则只有最初为该页面加载的 cookie 才会被发送回服务器。
对于 SPA 应用程序,我建议使用基于令牌的身份验证而不是表单。您必须首先登录并收到响应的令牌。接下来,您必须Authorization为每个请求提供标头,提供令牌作为身份验证信息(通常采用 form Bearer <token>)
| 归档时间: |
|
| 查看次数: |
12384 次 |
| 最近记录: |