首页 > 解决方案 > 禁用CORS错误时Spring安全默认登录不起作用

问题描述

我在 spring boot 和 angualar9 上构建了一个应用程序。我得到了没有'Access-Control-Allow-Origin' header is present on the requested resource错误。所以,我修复了这个错误,但是,现在当我停止 spring boot 应用程序并再次运行以测试任何 api 或任何其他页面时,我没有得到默认登录屏幕来输入由提供的用户名和密码弹簧安全。所以,这使我的弹簧安全不起作用。我认为当我禁用 CORS 策略时存在一些问题。

我的春季安全配置是:

Webconfig.java

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

}

网络安全配置.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>

标签: javaspringspring-bootspring-security

解决方案


您应该为登录的数据和路径添加登录页面的配置方法规范,使用.autenticated(). permitAll()告诉春天你不在乎用户是否登录。如果您愿意,还可以添加自定义登录路径.loginPage("custom_url")

编辑 如果您使用角度,我建议使用过滤器作为流动我将使用 JWT 身份验证,但您可以使用其他方式。

JWt fliter:负责验证登录用户的身份验证。

@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);
}
}

configure那么您应该使用该方法定义需要身份验证的 url

    @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();
}

像你已经完成的那样添加 cors 配置。

@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");
}
}

希望我没有忘记任何东西,它会为你工作。


推荐阅读