我有一个受Spring安全保护的Spring Boot应用服务器。首次登录时,将使用用户名和密码对用户进行身份验证。如果我使用Spring MVC(相同来源),则不必在每次调用API时都重新登录。但是,当我从Angular应用程序(跨域)调用API时,每次刷新页面时都必须提供授权。
是否可以在每次刷新页面时保持登录会话而不必发送身份验证?我需要某种HTTP拦截器服务来手动检查来自Spring服务器的响应吗?
我尝试调用的REST API
@CrossOrigin(origins = "http://localhost:4200")
@RestController
public class TestControllers {
private final AtomicLong counter = new AtomicLong();
@GetMapping("/greeting")
public MessageModel greeting (@RequestParam(value = "name", defaultValue = "World") String name) {
return new MessageModel(counter.incrementAndGet(),"Hello, " + name + "!");
}
private class MessageModel{
private long id;
private String content;
//Constructor, getter & setter
}
}
Auth controller
@RestController
@RequestMapping("/api/v1")
public class BasicAuthController {
@GetMapping(path = "/basicauth")
public AuthenticationModel basicauth() {
return new AuthenticationModel("You are authenticated");
}
class AuthenticationModel {
private String message;
//Constructor, getter & setter
}
}
安全配置
@Configuration
@EnableWebSecurity(debug = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = new BCryptPasswordEncoder();
auth.inMemoryAuthentication()
.passwordEncoder(encoder)
.withUser("user")
.password(encoder.encode("asdasd"))
.roles("USER");
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Angular身份验证服务
authenticationService(username: string, password: string) {
return this.http.get('http://localhost:8080/api/v1/basicauth',
{ headers: { authorization: this.createBasicAuthToken(username, password) } }).pipe(map((res) => {
this.username = username;
this.password = password;
this.registerSuccessfulLogin(username, password);
}));
}
您需要为Angular客户端提供拦截器,因此请像下面这样创建一个新的可注入对象:
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthenticationService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const username = this.authenticationService.username; //get your credentials from wherever you saved them after authentification
const password = this.authenticationService.password;
if (username && password) {
request = request.clone({
setHeaders: {
Authorization: this.createBasicAuthToken(username, password),
}
});
}
return next.handle(request);
}
}
并将其添加到位于providers
中的app.module.ts
:
{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true},
这会将身份验证数据添加到每个请求中,因此您不必每次都登录。