首页 > 解决方案 > Spring 安全跨域

问题描述

我开发了一个 REST API。一切正常,除了安全性(登录,获取登录用户等......)当我登录用户然后尝试通过/getWhoAmI端点获取它时,我无法获取它(它返回HttpStatus.NOT_FOUND因为那里是没有认证)。在邮递员中,它工作得很好!

我做了以下场景:登录用户,然后通过 /getWhoAmI 获取它。在邮递员中,它可以工作并返回登录的用户,但在我的 javascript 应用程序中,它返回 HttpStatus.NOT_FOUND。

另外,我尝试调试它,并且在getWhoAmI中,身份验证为仅当我在 JavaScript 中调用它时,在邮递员中它包含经过身份验证的用户)

这是/getWhoAmI端点

@GetMapping(path = "/getWhoAmI")
public ResponseEntity<UserModel> getWhoAmI(Authentication authentication) {

    // if there is no authenticated user
    if(authentication == null) {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }

    String loggedUsername = SecurityContextHolder.getContext().getAuthentication().getName();
    UserModel loggedUser = userRepo.findByUsername(loggedUsername);

    return new ResponseEntity<>(loggedUser, HttpStatus.OK);
}

这是我的SecurityConfig

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    private ApplicationUserDetailsService userDetailsService;

    public SecurityConfig(ApplicationUserDetailsService userDetailService) {
        this.userDetailsService = userDetailService;
    }

    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/**").permitAll()
        .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
        .and().logout().logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK))) // return HttpStatus.OK after successfull logout
        .and().csrf().disable();
        http.headers().frameOptions().disable();
    }

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
        auth.userDetailsService(userDetailsService);
    }

}

登录端点:

@PostMapping(path = "/login")
public ResponseEntity<UserModel> login(
        @RequestParam(value = "username") String username, 
        @RequestParam(value = "password") String password) {

    UserModel user = userRepo.findUserByUsernameAndPassword(username, password);

    if(user != null) {
        UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUsername());

        if(userDetails != null) {
            Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            System.out.println(authentication);
        }

        return new ResponseEntity<>(user, HttpStatus.OK);
    }

    return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}

我的前端 JavaScript:

$.ajax({
    method: "GET",
    url: SERVER_URL + "/getWhoAmI",
    complete: function(data) {
        console.log(data.responseJSON);
    }
});

标签: javaspringspring-bootsecurity

解决方案


根据交换意见:

因为来自前端的调用是跨域请求 (CORS),所以ajax调用没有发送会话标识符 cookie (JSESSIONID)。

XMLHttpRequest.withCredentials标志必须设置为跨站点请求以包含凭据,true例如 cookie 和授权标头。

对于 JQuery 的ajax功能,可以用xhrFields: { withCredentials: true }. axios 有类似的withCredentials标志。


推荐阅读