简体   繁体   中英

Spring security default login not working when disabling CORS error

I have an application building on spring boot and angualar9. I got the No 'Access-Control-Allow-Origin' header is present on the requested resource error.So,I fixed this error but,now when I stop the spring boot application and again run to test any api or any other pages then,I don't get default login screen to enter username and password provided by spring security.So,this made my spring security not working.I think there is some problem when i disabled CORS policy.

My spring secutiry config is:

Webconfig.java

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    
       @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
        }

}

WebSecutiryConfig.java

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, proxyTargetClass = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Autowired
    private UserDetailsService customUserDetailsService;
 
 
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
 
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
         .userDetailsService(customUserDetailsService)
         .passwordEncoder(passwordEncoder());
    }
 

    
    @Bean
    protected CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http.cors()
               .and().authorizeRequests()
               .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers("/books").permitAll()
           .antMatchers("/api/v1/**").permitAll()
           .antMatchers("/admin/**").hasRole("ADMIN")
               .and().csrf().disable();
        

    }
 
}

BasicAuthController.java

  @RequestMapping("/api/v1")
    @RestController
    @CrossOrigin(origins ="http://localhost:4200")
    public class BasicAuthController {
    
        @GetMapping(path = "/basicauth")
        public AuthenticationBean basicauth() {
            System.out.println("hitted here");
            return new AuthenticationBean("You are authenticated");
        }
        
      
    }

pom.xml

  <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.15.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>in.ashwin</groupId>
        <artifactId>onlinebookstore</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>onlinebookstore</name>
        <description>Angular 8 and spring boot fullstack</description>
    
        <properties>
            <java.version>1.8</java.version>
            <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-rest</artifactId>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
             <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>

You should add to your configure method specification of login page for the logged in data and paths with .autenticated() . permitAll() is telling spring you dont care if the user is logged in or not. You can also add a custom login path if you would like with .loginPage("custom_url")

Edit if you are using angular i would suggest using a filter as flowing i will use JWT authentication but you can use every other way.

JWt fliter: responsible for validating logged in users authentication.

@Component
public class JwtFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
private final UserService userService;

@Autowired
public JwtFilter( JwtUtil jwtUtil, UserService userService) {
    this.jwtUtil = jwtUtil;
    this.userService = userService;
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
        throws ServletException, IOException {
    final String requestTokenHeader = request.getHeader("Authorization");
 /// user data should be some unique identifier. may be encrypted
    String userData = null;
    String jwtToken = null;
// JWT Token is in the form "Bearer token". Remove Bearer word and get
// only the Token
    if (requestTokenHeader != null) {
        if (requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);
            try {
                userData= jwtTokenUtil.getDataFromToken(jwtToken);
            } catch (Exception e) {
                logger.error("JwtRequestFilter.doFilterInternal Unable to get JWT Token", e);
            }
    }
// Once we get the token validate it.
    if (userData!= null) {
        Optional<User> optionalUserObject = userService.findByData(userData);
        if (optionalUser.isEmpty()){
            throw new UsernameNotFoundException("User not found.");
        }
        User actualUser = optionalUserObject.get();
    
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                    actualUser,null,actualUser.getRoles());
            usernamePasswordAuthenticationToken
                    .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// After setting the Authentication in the context, we specify
// that the current user is authenticated. So it passes the
// Spring Security Configurations successfully.
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        }
    }
    chain.doFilter(request, response);
}
}

then you should define the urls that requires authentication with the configure method

    @Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    // We don't need CSRF for this example
    httpSecurity.csrf().disable()
            // dont authenticate this particular request
            .authorizeRequests().antMatchers("/login", "/register").permitAll().
            // all other requests need to be authenticated
                    anyRequest().authenticated().and()                        exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and();

    // Add a filter to validate the tokens with every request
    httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    httpSecurity.cors();
}

add cors configuration as you already done.

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, 
Serializable {
private static final long serialVersionUID = -7078141869840704968L;

@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
                     AuthenticationException authException) throws IOException {
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}

hope i didn't forgot any Thing and it will work for you.

Replace @CrossOrigin(origins ="http://localhost:4200") to @CrossOrigin("*") Restart service and test

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM