angularspring-bootspring-securitycorshttp-status-code-401

How to handle a 401 error in spring security + angular?


I am following a tutorial on how to do a login authentication using spring security and angular but whenever I'm running the angular program and try to login I get a 401 error. I feel like it's a cors issue and created a cors filter class which was a solution to a similar question but i'm still getting the same error. The login details are correct as I use the same credentials to login to localhost:8080 for the backend but when I try to login using the front-end I get the following error in the index.

Error:

Request URL: http://localhost:8080/login

Request Method: GET

Status Code: 401

Remote Address: [::1]:8080

Referrer Policy: no-referrer-when-downgrade

Access-Control-Allow-Headers: access_token, authorization, content-type

Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS, DELETE

Access-Control-Allow-Origin: *

Access-Control-Max-Age: 4200

Cache-Control: no-cache, no-store, max-age=0, must-revalidate

Connection: keep-alive

Content-Length: 0

Date: Tue, 28 Jul 2020 07:47:34 GMT

Expires: 0

Keep-Alive: timeout=60

Pragma: no-cache

Vary: Origin

Vary: Access-Control-Request-Method

Vary: Access-Control-Request-Headers

WWW-Authenticate: Basic realm="Realm"

WWW-Authenticate: Basic realm="Realm"

X-Content-Type-Options: nosniff

X-Frame-Options: DENY

X-XSS-Protection: 1; mode=block

Accept: application/json, text/plain, /

Accept-Encoding: gzip, deflate, br

Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

Authorization: Basiccml6YW5hOmp0MTQz

Connection: keep-alive

Host: localhost:8080

Origin: http://localhost:4200

Referer: http://localhost:4200/login

Sec-Fetch-Dest: empty

Sec-Fetch-Mode: cors

Sec-Fetch-Site: same-site

User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N)

AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Mobile Safari/537.36

I've tried:

Angular 2 Spring Boot Login CORS Problems

Tutorial:

https://www.youtube.com/watch?v=QV7ke4a7Lvc

spring security config

@Configuration
public class SpringConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private CORSFilter myCorsFilter;


//CORS


    @Override
    protected void configure(HttpSecurity http) throws Exception {
     /*   http.cors().and().csrf().
                disable()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**")
                .permitAll()
                .anyRequest()
                .fullyAuthenticated()
                .and()
                .httpBasic();*/

        http.addFilterBefore(myCorsFilter, ChannelProcessingFilter .class);


        http.cors();
        http.csrf().disable();
        http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and()
                .httpBasic();
    }



    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.inMemoryAuthentication()
                .withUser("java")
                .password("{noop}jt143").roles("USER");


    }
}


Corsfilter class


@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {

    /**
     * CORS filter for http-request and response
     */
    public CORSFilter() {
    }

    /**
     * Do Filter on every http-request.
     */

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "4200");
        response.setHeader("Access-Control-Allow-Headers", "access_token, authorization, content-type");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    /**
     * Destroy method
     */
    @Override
    public void destroy() {
    }

    /**
     * Initialize CORS filter
     */
    @Override
    public void init(FilterConfig arg0) throws ServletException {
    }
}

@RestController
@CrossOrigin(origins = "*")
public class CashierController {



        @Autowired
        private CashierRepo repository;

        @GetMapping("/login")
        public String login(){
            return "authenticated";
        }


        @PostMapping("/addUser")
        public String saveCashier(@RequestBody Cashier cashier) {
            repository.save(cashier);
            return "Added user with user id : " + cashier.getUserId();

        }

Solution

  • Seems like you didn't excluded your login API from Spring security. Whenever, we enable spring security, we have to configure the list of URLs for which security should not be imposed. Example - login api, html files, js files etc. You can do this by adding below method to your SpringConfig class

    @Override
        public void configure(WebSecurity web) throws Exception 
        {
            // Allow Login API to be accessed without authentication
            web.ignoring().antMatchers("/login").antMatchers(HttpMethod.OPTIONS, "/**"); // Request type options should be allowed.
        }