我的Spring boot(Spring Security)应用程序尝试使用http://localhost:4200/login登录时返回401错误
我似乎无法弄清楚为什么会出现401错误。我在网上看到的一些示例中,类似的配置似乎也起作用。
以下是请求结果:
Request URL: http://localhost:8080/account/login
Request Method: GET
Status Code: 401
Remote Address: [::1]:8080
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Origin: http://localhost:4200
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Date: Wed, 24 Apr 2019 08:05:37 GMT
Expires: 0
Pragma: no-cache
Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
WWW-Authenticate: Basic realm="Realm", Basic realm="Realm"
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Provisional headers are shown
Accept: application/json
Authorization: Basic Y2pAaG90bWFpbC5jb206Y2hyaXMx
Origin: http://localhost:4200
Referer: http://localhost:4200/login
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36
在春季,WebConfig.java类似于:
package com.neha.jobportal.jobportalbackend.configurations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.neha.jobportal.jobportalbackend.services.AppUserDetailsService;
@Configurable
@EnableWebSecurity(debug = true)
// Modifying or overriding the default spring boot security.
public class WebConfig extends WebSecurityConfigurerAdapter {
@Autowired
AppUserDetailsService appUserDetailsService;
// This method is for overriding the default AuthenticationManagerBuilder.
// We can specify how the user details are kept in the application. It may
// be in a database, LDAP or in memory.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(appUserDetailsService);
}
// this configuration allow the client app to access the this api
// all the domain that consume this api must be included in the allowed o'rings
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:4200");
}
};
}
// This method is for overriding some configuration of the WebSecurity
// If you want to ignore some request or request patterns then you can
// specify that inside this method
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
/*
* web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui",
* "/swagger-resources", "/configuration/security", "/swagger-ui.html/**",
* "/webjars/**", "/swagger-resources/configuration/ui",
* "/swagger-resources/configuration/security");
*/
}
// This method is used for override HttpSecurity of the web Application.
// We can specify our authorization criteria inside this method.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
// starts authorizing configurations
.authorizeRequests()
// ignoring the guest's urls "
.antMatchers("/account/register", "/account/login", "/logout", "/v2/api-docs", "/v2/api-docs",
"/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html/**",
"/webjars/**", "/swagger-resources/configuration/ui",
"/swagger-resources/configuration/security", "/swagger-ui.html#/**",
"/swagger-ui.html#/job-portal-controller/**")
.permitAll()
// authenticate all remaining URLS
.anyRequest().fullyAuthenticated().and()
/*
* "/logout" will log the user out by invalidating the HTTP Session, cleaning up
* any {link rememberMe()} authentication that was configured,
*/
.logout().permitAll().logoutRequestMatcher(new AntPathRequestMatcher("/logout", "POST")).and()
// enabling the basic authentication
.httpBasic().and()
// configuring the session on the server
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and()
// disabling the CSRF - Cross Site Request Forgery
.csrf().disable();
}
}
我的Spring AccountController.java看起来像这样:
package com.neha.jobportal.jobportalbackend.controllers;
import java.security.Principal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.neha.jobportal.jobportalbackend.entities.User;
import com.neha.jobportal.jobportalbackend.services.UserService;
import com.neha.jobportal.jobportalbackend.utils.CustomErrorType;
@RestController
@CrossOrigin
@RequestMapping("account")
public class AccountController {
@Autowired
private UserService userService;
// request method to create a new account by Job Seeker
@CrossOrigin
@PostMapping(value = "/register")
public ResponseEntity<?> createUser(@RequestBody User newUser) {
System.out.println("/register called with " + newUser.toString());
// check email to only allow unregistered emails
if (userService.findUserByUsername(newUser.getUsername()) != null) {
System.out.println("username already exists " + newUser.getUsername());
return new ResponseEntity(
new CustomErrorType("User with username " + newUser.getUsername() + "already exists "),
HttpStatus.CONFLICT);
}
newUser.setRole("Job Seeker");
return new ResponseEntity<User>(userService.save(newUser), HttpStatus.CREATED);
}
// request method to create a new account by a Recruiter
@CrossOrigin
@PostMapping(value = "/registerAsRecruiter")
public ResponseEntity<?> createRecruiter(@RequestBody User newUser) {
if (userService.findUserByUsername(newUser.getUsername()) != null) {
System.out.println("username already exists " + newUser.getUsername());
return new ResponseEntity(
new CustomErrorType("User with username " + newUser.getUsername() + "already exists "),
HttpStatus.CONFLICT);
}
newUser.setRole("Recruiter");
return new ResponseEntity<User>(userService.save(newUser), HttpStatus.CREATED);
}
// this is the login api/service
@CrossOrigin
@RequestMapping("/login")
public Principal user(Principal principal) {
System.out.println("user logged "+principal);
return principal;
}
}
我还有一个CORS过滤器MyCORSFilter.java在另一个路径(/ api / *)上工作
package com.neha.jobportal.jobportalbackend.configurations;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
//@Order(Ordered.HIGHEST_PRECEDENCE)
@WebFilter(urlPatterns = "/api/*")
public class MyCORSFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
还有一个用于Swagger的SwaggerConfig.java
package com.neha.jobportal.jobportalbackend.configurations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfig{
@Bean
public Docket produceApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.neha.jobportal.jobportalbackend.controllers"))
.build();
}
// Describe your apis
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Job Portal Rest APIs")
.description("This page lists all the rest apis exposed by the Job Portal Backend.")
.version("1.0-SNAPSHOT")
.build();
}
}