こんにちは皆私のアプリのセキュリティソリューションをセットアップする際に問題があります! 私はhttp://localhost:51030で実行され、Spring Frameworkで開発されたREST APIバックエンドを持っています。フロント側には、http://localhost:4200で動作するAngular 2アプリケーション(最新バージョンA.K.A. Angular 4)があります。下図のように 私はバックエンドでCORS構成を設定している:角2春のセキュリティCSRFトークン
public class CORSFilter implements Filter
{
// The list of domains allowed to access the server
private final List<String> allowedOrigins = Arrays.asList("http://localhost:4200", "http://127.0.0.1:4200");
public void destroy()
{
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
{
// Lets make sure that we are working with HTTP (that is, against HttpServletRequest and HttpServletResponse objects)
if (req instanceof HttpServletRequest && res instanceof HttpServletResponse)
{
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// Access-Control-Allow-Origin
String origin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : "");
response.setHeader("Vary", "Origin");
// Access-Control-Max-Age
response.setHeader("Access-Control-Max-Age", "3600");
// Access-Control-Allow-Credentials
response.setHeader("Access-Control-Allow-Credentials", "true");
// Access-Control-Allow-Methods
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
// Access-Control-Allow-Headers
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, " + CSRF.REQUEST_HEADER_NAME); // + CSRF.REQUEST_HEADER_NAME
}
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig)
{
}
}
を、この設定を使用するだけで正常に動作し、私は戻って春に角度アプリからの要求を実行し、応答を取得し、何を行うことができます。 しかし、私はCSRFセキュリティソリューションを設定しようとすると何も動作しません。
public class CSRF
{
/**
* The name of the cookie with the CSRF token sent by the server as a response.
*/
public static final String RESPONSE_COOKIE_NAME = "XSRF-TOKEN"; //CSRF-TOKEN
/**
* The name of the header carrying the CSRF token, expected in CSRF-protected requests to the server.
*/
public static final String REQUEST_HEADER_NAME = "X-XSRF-TOKEN"; //X-CSRF-TOKEN
// In Angular the CookieXSRFStrategy looks for a cookie called XSRF-TOKEN
// and sets a header named X-XSRF-TOKEN with the value of that cookie.
// The server must do its part by setting the initial XSRF-TOKEN cookie
// and confirming that each subsequent state-modifying request includes
// a matching XSRF-TOKEN cookie and X-XSRF-TOKEN header.
}
public class CSRFTokenResponseCookieBindingFilter extends OncePerRequestFilter
{
protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException
{
CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);
Cookie cookie = new Cookie(CSRF.RESPONSE_COOKIE_NAME, token.getToken());
cookie.setPath("/");
response.addCookie(cookie);
filterChain.doFilter(request, response);
}
}
@Configuration
public class Conf extends WebMvcConfigurerAdapter
{
@Bean
public CORSFilter corsFilter()
{
return new CORSFilter();
}
@Override
public void addViewControllers(ViewControllerRegistry registry)
{
registry.addViewController("/login");
registry.addViewController("/logout");
}
}
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
@Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private RESTAuthenticationFailureHandler authenticationFailureHandler;
@Autowired
private RESTAuthenticationSuccessHandler authenticationSuccessHandler;
@Autowired
private RESTLogoutSuccessHandler logoutSuccessHandler;
@Resource
private CORSFilter corsFilter;
@Autowired
private DataSource dataSource;
@Autowired
public void globalConfig(AuthenticationManagerBuilder auth) throws Exception
{
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select login as principal, password as credentials, true from user where login = ?")
.authoritiesByUsernameQuery("select login as principal, profile as role from user where login = ?")
.rolePrefix("ROLE_");
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
//csrf is disabled for the moment
//http.csrf().disable();
//authorized requests
http.authorizeRequests()
.antMatchers("/api/users/**").permitAll()
.antMatchers(HttpMethod.OPTIONS , "/*/**").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated();
//handling authentication exceptions
http.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint);
//login configuration
http.formLogin()
.loginProcessingUrl("/login")
.successHandler(authenticationSuccessHandler);
http.formLogin()
.failureHandler(authenticationFailureHandler);
//logout configuration
http.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(logoutSuccessHandler);
//CORS configuration
http.addFilterBefore(corsFilter, ChannelProcessingFilter.class);
//CSRF configuration
http.csrf().requireCsrfProtectionMatcher(
new AndRequestMatcher(
// Apply CSRF protection to all paths that do NOT match the ones below
// We disable CSRF at login/logout, but only for OPTIONS methods to enable the browser preflight
new NegatedRequestMatcher(new AntPathRequestMatcher("/login*/**", HttpMethod.OPTIONS.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/logout*/**", HttpMethod.OPTIONS.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.GET.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.HEAD.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.OPTIONS.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.TRACE.toString()))
)
);
// CSRF tokens handling
http.addFilterAfter(new CSRFTokenResponseCookieBindingFilter(), CsrfFilter.class);
}
}
問題が前面にある: これは、バックエンドでアップsetted CSRFとセキュリティの設定ですAngle 4の設定では、CSRFのドキュメントは非常に貧しく、CSRF実装の完全な例はインターネットにはありません。そこで、以下の は私のログインサービスである:
@Injectable()
export class LoginService {
private loginUrl = 'http://localhost:51030/login';
constructor(private http: Http) {}
preFlight() {
return this.http.options(this.loginUrl);
}
login(username: string , password: string) {
let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
let options = new RequestOptions({headers: headers});
let body = "username="+username+"&password="+password;
return this.http.post(this.loginUrl , body , options);
}
}
そして、私はngOnInitライフサイクルフックにオプション要求を実行し、ログインコンポーネントで:
@Component({
templateUrl: './login-layout.component.html'
})
export class LoginLayoutComponent implements OnInit {
credentials = {username: '' , password: ''};
constructor(private loginService: LoginService){}
ngOnInit() {
this.loginService.preFlight()
.subscribe();
}
login() {
this.loginService.login(this.credentials.username , this.credentials.password)
.subscribe(
response=>{
console.log(response) ;
},error=>{
console.log(error);
}
);
}
}
プリフライトはうまくいくと私は、オプション要求と一時的なJSEEIONIDとXSRF-TOKEN Cookieに200 OKステータスを取得します。
角度ドキュメントに言って私のアプリモジュールで、私はこれを追加しました:
{
provide: XSRFStrategy,
useValue: new CookieXSRFStrategy('XSRF-TOKEN', 'X-XSRF-TOKEN')
},
しかし、私は資格情報または私は403を禁じてしまったバックへの要求とPOSTリクエストを実行してみてください: "あなたのセッションが見つからないため、提供されたCSRFトークンを検証できませんでした。"
私はこれをどのように解決することができますか、私はこの仕事をする方法の手がかりを持っていない原因を右の方向に私をポイントすることができます! ありがとうございます!