java - 使用 Java 和 Angular2 进行 Spring Security 登录

标签 java spring angular spring-security ionic2

在我的 Web 应用程序中集成 Spring Security(即登录部分)时遇到了一些问题。我的后端在 localhost:8080 上运行,而前端(Ionic 2 和 AngularJS 2)在 localhost:8100 上运行。我设法登录(至少我是这么认为的),但其余请求不可用,并且我在 Chrome 开发者控制台中收到以下错误:

XMLHttpRequest cannot load http://localhost:8080/company/getAll. Response for preflight is invalid (redirect)

当使用 Postman 进行测试时,它似乎工作正常,我登录,然后可以在 http://localhost:8080/company/getAll 上执行 POST 请求。一切都按预期工作。

大概我错过了一些东西(比如 token ),但不知道是什么。我是 Ionic 和 Spring Security 的新手,所以如果这是微不足道的,请原谅我。我尝试在谷歌上搜索各种教程,但找不到任何东西(其中大多数都使用 JSP)。

我怎样才能让它工作?我的前端请求应该是什么样子?

这是我从后端 Controller 登录的方法:

@RequestMapping(value = "/login", method = RequestMethod.GET)
    @CrossOrigin(origins = "*")
    public ResponseEntity<GeneralResponse> login(Model model, String error, String logout) {
        System.out.println("LOGIN"+model.toString());

        if (error != null) {
            System.out.println("1.IF");
            model.addAttribute("error", "Your username and password is invalid.");
        }

        if (logout != null) {
            System.out.println("2.IF");
            model.addAttribute("message", "You have been logged out successfully.");
        }

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new GeneralResponse(true, "FAILURE: Error"));
    }

这是我的 WebSecurityConfig:

@Configuration
@EnableWebSecurity
@ComponentScan("com.SAB.service")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/resources/**", "/registration").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/user/login")
            .permitAll()
            .and()
            .logout()
            .permitAll();
        http
            .csrf().disable();
        http.formLogin().defaultSuccessUrl("http://localhost:8100/", true);
        //.and().exceptionHandling().accessDeniedPage("/403")
        //.and().sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true);
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }
}

最后是我负责登录的前端代码:

  login(){
    var body = 'username='+this.loginForm.controls['username'].value+'&password='+this.loginForm.controls['password'].value;
    var headers = new Headers();
    headers.append('Content-Type', 'application/x-www-form-urlencoded');
    //headers.append("Access-Control-Allow-Origin", "*");

    this.http
      .post('http://localhost:8080/user/login',
        body, {
          headers: headers
        })
      .subscribe(data => {
        console.log('ok');
        console.log(data)
      }, error => {
        console.log(JSON.stringify(error.json()));
      });
  }

如果您需要任何其他详细信息,请告诉我,我会提供。

提前致谢!

我没有收到 Access-CONtroll-Origin 错误,但我还是尝试根据评论更改它,现在我收到“无效的 CORS 请求”

postman 登录的请求和响应 header : enter image description here

编辑: 这是 Spring Security 日志。然而 Spring 只注册一个 OPTIONS 请求,没有 POST,即使 FrontEnd 正在调用 POST。

************************************************************

Request received for OPTIONS '/login':

org.apache.catalina.connector.RequestFacade@18859793

servletPath:/login
pathInfo:null
headers: 
host: localhost:8080
connection: keep-alive
access-control-request-method: POST
origin: http://localhost:8100
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36
access-control-request-headers: access-control-allow-origin
accept: */*
referer: http://localhost:8100/
accept-encoding: gzip, deflate, sdch, br
accept-language: en-US,en;q=0.8


Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  CorsFilter
  LogoutFilter
  UsernamePasswordAuthenticationFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]


************************************************************
2017-05-12 19:18:28.527 DEBUG 16500 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /login at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2017-05-12 19:18:28.527 DEBUG 16500 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /login at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2017-05-12 19:18:28.527 DEBUG 16500 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2017-05-12 19:18:28.527 DEBUG 16500 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2017-05-12 19:18:28.529 DEBUG 16500 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /login at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2017-05-12 19:18:28.529 DEBUG 16500 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /login at position 4 of 12 in additional filter chain; firing Filter: 'CorsFilter'
2017-05-12 19:18:28.541 DEBUG 16500 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5baaaa2b
2017-05-12 19:18:28.541 DEBUG 16500 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2017-05-12 19:18:28.541 DEBUG 16500 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

更新: 因此,在接受的答案中添加建议的 CORSFilter 后,我还必须在前端修改我的请求,以便在每个请求上发送带有 JSESSIONID 的 cookie。基本上我必须将以下内容添加到我的所有请求中: let options = new RequestOptions({ headers: headers, withCredentials: true });

最佳答案

这似乎是与 CORS 配置相关的问题。浏览器确实会在您的实际 GET 调用之前发出 OPTION 预检请求。我在这方面的知识不多,但是您可以尝试将下面的过滤器添加到 Spring 后端。

public class CORSFilter extends GenericFilterBean {

    public void doFilter(ServletRequest request, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse response = (HttpServletResponse) res;
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.addHeader("Access-Control-Max-Age", "3600");
        response.addHeader("Access-Control-Allow-Headers", "X-Requested-With, X-Auth-Token");
        response.addHeader("Access-Control-Allow-Credentials", "true");

        if(req.getMethod().equalsIgnoreCase("options")){
             return;
        }
        chain.doFilter(request, response);
    }
}

并在您的 WebSecurityConfig 的 configure 方法中添加以下行。

.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class);

关于java - 使用 Java 和 Angular2 进行 Spring Security 登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43875137/

相关文章:

java - 我可以在它死后重新启动一个线程吗?

Spring 安全 : How to get the initial target url

spring - 如何保证Spring @Autowired注入(inject)在构造函数中可以访问

java - 错误:java package xxx does not exist despite IDEA being aware of them

java - 这个spring类BatchPreparedStatementSetter有什么用呢?

java - 单击按钮时如何在 Java 中定义选项卡的操作

java - Eclipse PDT 插件给我带来了麻烦

angular - 如何创建自定义命令(在终端上运行)以在 angular2 中创建所需的组件(包含所需的内容)?

javascript - 更改检测在 Firefox 中无法正常运行

asp.net-mvc - 使用 .net mvc 在 IIS angular 2 应用程序上发布