我正在使用Angular 2並試圖在get方法上發送頭部參數。我有下面的代碼:Spring Boot + Angular 2 + JWT
let tokenUrl2 = "http://localhost:8080/users";
let headers = new Headers();
headers.append('abc', token);
let options = new RequestOptions({ headers: headers });
return this.http.get(tokenUrl2, options);
我得到這個錯誤:
Response for preflight is invalid (redirect)
我還添加了這些參數,但我得到了同樣的錯誤:
headers.append('Content-Type', 'application/json');
headers.append('Authorization':'Bearer ' + token);
誰能告訴我什麼是正確的方式發送標題參數。非常感謝你:)
編輯1
的URL 「http://localhost:8080/users」 是從春天啓動的Web應用程序(這是一個REST服務)。我試圖與春季啓動應用程序溝通角應用程序。我的想法是將其從另一個REST服務獲得的標記發送給它。在第一個REST服務中,我得到了一個令牌。這是POST的REST服務,它可以工作。然後,我通過GET方法將此令牌發送給第二個REST服務(http://localhost:8080/users)。第二部分不起作用。我嘗試將GET方法更改爲POST,因爲使用POST方法的第一部分可以正常工作,但這種新更改不起作用。我仍然收到相同的消息:預檢的響應無效(重定向)。
我有以下問題:
如果我的第一個REST服務(含郵政設立)的作品,爲什麼第二個不?這是因爲我的請求(我的角應用程序)沒有實現CORS?
我希望有這個細節,你可以幫我解決我的問題。
謝謝!
EDIT 2
起初,我以爲從角應用發送頭參數REST服務時,我只有一個錯誤。但是,我調查了一下,發現我的問題涉及更多組件。我告訴我的組件:
我有一個角度的應用程序,需要從Spring啓動應用程序使用REST服務。每個REST服務都需要身份驗證,因此我使用JWT。
首先。我的角度應用程序使用認證REST服務。如果這樣做。 REST服務返回一個令牌。
二。有了這個令牌,角度應用程序可以使用Spring Security保護的另一個REST服務。
我的錯誤發生在第二步。我無法使用其他服務。我有一個自定義過濾器,從OncePerRequestFilter延伸,甚至沒有被調用。在角應用,我感到我之前報道的消息:
預檢響應無效(重定向)
正如我在以前的編輯說。我不理解,因爲第一個REST服務被調用,但第二個沒有。我也不明白爲什麼我的自定義過濾器沒有被調用。我認爲我從角度應用程序調用錯誤。
我的代碼:
自定義過濾器:
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
private final Log logger = LogFactory.getLog(this.getClass());
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Value("${jwt.header}")
private String tokenHeader;
static final String ORIGIN = "Origin";
@Override
//@CrossOrigin(origins = "*")
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// TODO Auto-generated method stub
logger.info("checking authentication für user ");
String authToken = request.getHeader(this.tokenHeader);
// authToken.startsWith("Bearer ")
// String authToken = header.substring(7);
String username = jwtTokenUtil.getUsernameFromToken(authToken);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// It is not compelling necessary to load the use details from the database. You could also store the information
// in the token and read it from it. It's up to you ;)
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
// For simple validation it is completely sufficient to just check the token integrity. You don't have to call
// the database compellingly. Again it's up to you ;)
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
logger.info("authenticated user " + username + ", setting security context");
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(request, response);
}
}
角控制器和服務:
import { Component, OnInit } from '@angular/core';
import { LoginService } from './login.service';
interface TokenJson {
token: string;
}
@Component({
selector: 'login',
templateUrl: 'login.component.html',
styleUrls: ['login.scss'],
providers: [LoginService]
})
export class LoginComponent implements OnInit {
private model = {'username':'****', 'password':'****'};
private currentToken:string ;
private tokenJson: TokenJson;
// constructor
constructor(private _loginService: LoginService) {
}
// on-init
ngOnInit() {
debugger;
this._loginService.sendCredential(this.model).subscribe(
data => {
debugger;
//localStorage.setItem("token", JSON.parse(JSON.stringify(data)).token);
// this.currentToken = JSON.parse(JSON.stringify(data))._body;
this.tokenJson = JSON.parse(JSON.stringify(data))._body;
this.currentToken = JSON.parse(JSON.parse(JSON.stringify(data))._body).token;
localStorage.setItem("token", this.currentToken);
this._loginService.sendToken(localStorage.getItem("token")).subscribe(
data => {
//this.currentUserName=this.model.username;
//localStorage.setItem("currentUserName", this.model.username);
debugger;
this.model.username='';
this.model.password='';
},
error => {
debugger;
console.log(error)
}
);
},
error => {
debugger;
console.log(error)
}
);
}
}
import {Injectable} from "@angular/core";
import {Http, Headers, Response, RequestOptions} from '@angular/http';
import {Observable} from 'rxjs/Observable';
@Injectable()
export class LoginService {
token: string;
constructor (private http: Http) {}
sendCredential(model) {
debugger;
let tokenUrl1 = "http://localhost:8080/auth";
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post(tokenUrl1, JSON.stringify(model), {headers: headers});
}
sendToken(token) {
debugger;
let tokenUrl2 = "http://localhost:8080/users";
console.log('Bearer '+token);
let getHeaders2 = new Headers();
getHeaders2.append('Authorization', token);
let headers = new Headers();
headers.append('authorization', token);
return this.http.post(tokenUrl2, {}, options);
}
}
SOLUTION
我發現這個問題。該錯誤消息得到了OPTIONS類型的請求。我只能避免這種類型的請求。我添加下面的配置到安全性配置類:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
//
}
PD:我從here
我用命令「npm start」運行我的應用程序。你認爲這是問題嗎? –
更可能,您正面臨CORS問題。基本上,您正在從一臺服務器提供瀏覽器應用程序,但試圖從該應用程序向另一臺服務器發出http請求。瀏覽器不允許出於安全原因,除非其他服務器通過在其響應中設置適當的標頭明確允許它。 Google的「CORS」可以稍微閱讀一下。我假設你有控制其他服務器來配置CORS。如果你沒有這種控制,那麼你將不得不調查在你的「npm start」服務器上設置一個代理 – snorkpete
我忘記告訴我的角度應用程序消耗一個春季啓動應用程序。 URL是我的春季啓動應用程序的get方法。我改爲開機自檢,但它不起作用。我在第一篇文章中解釋mot詳細 –