Enum Constant Details
-
CONTINUE
100 Continue
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.2.1
-
SWITCHING_PROTOCOLS
public static final HttpStatus SWITCHING_PROTOCOLS
101 Switching Protocols
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.2.2
-
PROCESSING
public static final HttpStatus PROCESSING
102 Processing
.- See Also:
-
- WebDAV
-
CHECKPOINT
public static final HttpStatus CHECKPOINT
103 Checkpoint
.- See Also:
-
- A proposal for supporting
resumable POST/PUT HTTP requests in HTTP/1.0
- A proposal for supporting
-
OK
200 OK
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.3.1
-
CREATED
201 Created
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.3.2
-
ACCEPTED
202 Accepted
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.3.3
-
NON_AUTHORITATIVE_INFORMATION
public static final HttpStatus NON_AUTHORITATIVE_INFORMATION
203 Non-Authoritative Information
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.3.4
-
NO_CONTENT
public static final HttpStatus NO_CONTENT
204 No Content
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.3.5
-
RESET_CONTENT
public static final HttpStatus RESET_CONTENT
205 Reset Content
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.3.6
-
PARTIAL_CONTENT
public static final HttpStatus PARTIAL_CONTENT
206 Partial Content
.- See Also:
-
- HTTP/1.1: Range Requests, section 4.1
-
MULTI_STATUS
public static final HttpStatus MULTI_STATUS
207 Multi-Status
.- See Also:
-
- WebDAV
-
ALREADY_REPORTED
public static final HttpStatus ALREADY_REPORTED
208 Already Reported
.- See Also:
-
- WebDAV Binding Extensions
-
IM_USED
226 IM Used
.- See Also:
-
- Delta encoding in HTTP
-
MULTIPLE_CHOICES
public static final HttpStatus MULTIPLE_CHOICES
300 Multiple Choices
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.4.1
-
MOVED_PERMANENTLY
public static final HttpStatus MOVED_PERMANENTLY
301 Moved Permanently
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.4.2
-
FOUND
302 Found
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.4.3
-
MOVED_TEMPORARILY
302 Moved Temporarily
.- See Also:
-
- HTTP/1.0, section 9.3
-
SEE_OTHER
303 See Other
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.4.4
-
NOT_MODIFIED
public static final HttpStatus NOT_MODIFIED
304 Not Modified
.- See Also:
-
- HTTP/1.1: Conditional Requests, section 4.1
-
USE_PROXY
305 Use Proxy
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.4.5
-
TEMPORARY_REDIRECT
public static final HttpStatus TEMPORARY_REDIRECT
307 Temporary Redirect
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.4.7
-
PERMANENT_REDIRECT
public static final HttpStatus PERMANENT_REDIRECT
308 Permanent Redirect
.- See Also:
-
- RFC 7238
-
BAD_REQUEST
public static final HttpStatus BAD_REQUEST
400 Bad Request
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.1
-
UNAUTHORIZED
public static final HttpStatus UNAUTHORIZED
401 Unauthorized
.- See Also:
-
- HTTP/1.1: Authentication, section 3.1
-
PAYMENT_REQUIRED
public static final HttpStatus PAYMENT_REQUIRED
402 Payment Required
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.2
-
FORBIDDEN
403 Forbidden
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.3
-
NOT_FOUND
404 Not Found
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.4
-
METHOD_NOT_ALLOWED
public static final HttpStatus METHOD_NOT_ALLOWED
405 Method Not Allowed
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.5
-
NOT_ACCEPTABLE
public static final HttpStatus NOT_ACCEPTABLE
406 Not Acceptable
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.6
-
PROXY_AUTHENTICATION_REQUIRED
public static final HttpStatus PROXY_AUTHENTICATION_REQUIRED
407 Proxy Authentication Required
.- See Also:
-
- HTTP/1.1: Authentication, section 3.2
-
REQUEST_TIMEOUT
public static final HttpStatus REQUEST_TIMEOUT
408 Request Timeout
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.7
-
CONFLICT
409 Conflict
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.8
-
GONE
410 Gone
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.9
-
LENGTH_REQUIRED
public static final HttpStatus LENGTH_REQUIRED
411 Length Required
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.10
-
PRECONDITION_FAILED
public static final HttpStatus PRECONDITION_FAILED
412 Precondition failed
.- See Also:
-
- HTTP/1.1: Conditional Requests, section 4.2
-
PAYLOAD_TOO_LARGE
public static final HttpStatus PAYLOAD_TOO_LARGE
413 Payload Too Large
.- Since:
- 4.1
- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.11
-
REQUEST_ENTITY_TOO_LARGE
413 Request Entity Too Large
.- See Also:
-
- HTTP/1.1, section 10.4.14
-
URI_TOO_LONG
public static final HttpStatus URI_TOO_LONG
414 URI Too Long
.- Since:
- 4.1
- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.12
-
REQUEST_URI_TOO_LONG
414 Request-URI Too Long
.- See Also:
-
- HTTP/1.1, section 10.4.15
-
UNSUPPORTED_MEDIA_TYPE
public static final HttpStatus UNSUPPORTED_MEDIA_TYPE
415 Unsupported Media Type
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.13
-
REQUESTED_RANGE_NOT_SATISFIABLE
public static final HttpStatus REQUESTED_RANGE_NOT_SATISFIABLE
416 Requested Range Not Satisfiable
.- See Also:
-
- HTTP/1.1: Range Requests, section 4.4
-
EXPECTATION_FAILED
public static final HttpStatus EXPECTATION_FAILED
417 Expectation Failed
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.5.14
-
I_AM_A_TEAPOT
public static final HttpStatus I_AM_A_TEAPOT
418 I'm a teapot
.- See Also:
-
- HTCPCP/1.0
-
INSUFFICIENT_SPACE_ON_RESOURCE
-
METHOD_FAILURE
-
DESTINATION_LOCKED
-
UNPROCESSABLE_ENTITY
public static final HttpStatus UNPROCESSABLE_ENTITY
422 Unprocessable Entity
.- See Also:
-
- WebDAV
-
LOCKED
423 Locked
.- See Also:
-
- WebDAV
-
FAILED_DEPENDENCY
public static final HttpStatus FAILED_DEPENDENCY
424 Failed Dependency
.- See Also:
-
- WebDAV
-
TOO_EARLY
425 Too Early
.- Since:
- 5.2
- See Also:
-
- RFC 8470
-
UPGRADE_REQUIRED
public static final HttpStatus UPGRADE_REQUIRED
426 Upgrade Required
.- See Also:
-
- Upgrading to TLS Within HTTP/1.1
-
PRECONDITION_REQUIRED
public static final HttpStatus PRECONDITION_REQUIRED
428 Precondition Required
.- See Also:
-
- Additional HTTP Status Codes
-
TOO_MANY_REQUESTS
public static final HttpStatus TOO_MANY_REQUESTS
429 Too Many Requests
.- See Also:
-
- Additional HTTP Status Codes
-
UNAVAILABLE_FOR_LEGAL_REASONS
public static final HttpStatus UNAVAILABLE_FOR_LEGAL_REASONS
451 Unavailable For Legal Reasons
.- Since:
- 4.3
- See Also:
-
- An HTTP Status Code to Report Legal Obstacles
-
INTERNAL_SERVER_ERROR
public static final HttpStatus INTERNAL_SERVER_ERROR
500 Internal Server Error
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.6.1
-
NOT_IMPLEMENTED
public static final HttpStatus NOT_IMPLEMENTED
501 Not Implemented
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.6.2
-
BAD_GATEWAY
public static final HttpStatus BAD_GATEWAY
502 Bad Gateway
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.6.3
-
SERVICE_UNAVAILABLE
public static final HttpStatus SERVICE_UNAVAILABLE
503 Service Unavailable
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.6.4
-
GATEWAY_TIMEOUT
public static final HttpStatus GATEWAY_TIMEOUT
504 Gateway Timeout
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.6.5
-
HTTP_VERSION_NOT_SUPPORTED
public static final HttpStatus HTTP_VERSION_NOT_SUPPORTED
505 HTTP Version Not Supported
.- See Also:
-
- HTTP/1.1: Semantics and Content, section 6.6.6
-
VARIANT_ALSO_NEGOTIATES
public static final HttpStatus VARIANT_ALSO_NEGOTIATES
506 Variant Also Negotiates
- See Also:
-
- Transparent Content Negotiation
-
INSUFFICIENT_STORAGE
public static final HttpStatus INSUFFICIENT_STORAGE
507 Insufficient Storage
- See Also:
-
- WebDAV
-
LOOP_DETECTED
public static final HttpStatus LOOP_DETECTED
508 Loop Detected
- See Also:
-
- WebDAV Binding Extensions
-
BANDWIDTH_LIMIT_EXCEEDED
public static final HttpStatus BANDWIDTH_LIMIT_EXCEEDED
509 Bandwidth Limit Exceeded
-
NOT_EXTENDED
public static final HttpStatus NOT_EXTENDED
510 Not Extended
- See Also:
-
- HTTP Extension Framework
-
NETWORK_AUTHENTICATION_REQUIRED
public static final HttpStatus NETWORK_AUTHENTICATION_REQUIRED
511 Network Authentication Required
.- See Also:
-
- Additional HTTP Status Codes
Method Details
-
values
Returns an array containing the constants of this enum class, in
the order they are declared.- Returns:
- an array containing the constants of this enum class, in the order they are declared
-
valueOf
Returns the enum constant of this class with the specified name.
The string must match exactly an identifier used to declare an
enum constant in this class. (Extraneous whitespace characters are
not permitted.)- Parameters:
name
— the name of the enum constant to be returned.- Returns:
- the enum constant with the specified name
- Throws:
IllegalArgumentException
— if this enum class has no constant with the specified nameNullPointerException
— if the argument is null
-
value
public int value()
Return the integer value of this status code.
- Specified by:
value
in interfaceHttpStatusCode
-
series
Return the HTTP status series of this status code.
- See Also:
-
HttpStatus.Series
-
getReasonPhrase
public String getReasonPhrase()
Return the reason phrase of this status code.
-
is1xxInformational
public boolean is1xxInformational()
Whether this status code is in the Informational class (
1xx
).- Specified by:
is1xxInformational
in interfaceHttpStatusCode
- See Also:
-
- RFC 2616
-
is2xxSuccessful
public boolean is2xxSuccessful()
Whether this status code is in the Successful class (
2xx
).- Specified by:
is2xxSuccessful
in interfaceHttpStatusCode
- See Also:
-
- RFC 2616
-
is3xxRedirection
public boolean is3xxRedirection()
Whether this status code is in the Redirection class (
3xx
).- Specified by:
is3xxRedirection
in interfaceHttpStatusCode
- See Also:
-
- RFC 2616
-
is4xxClientError
public boolean is4xxClientError()
Whether this status code is in the Client Error class (
4xx
).- Specified by:
is4xxClientError
in interfaceHttpStatusCode
- See Also:
-
- RFC 2616
-
is5xxServerError
public boolean is5xxServerError()
Whether this status code is in the Server Error class (
5xx
).- Specified by:
is5xxServerError
in interfaceHttpStatusCode
- See Also:
-
- RFC 2616
-
isError
public boolean isError()
Whether this status code is in the Client or Server Error class
- Specified by:
isError
in interfaceHttpStatusCode
- See Also:
-
- RFC 2616
- RFC 2616
(4xx
or5xx
). HttpStatusCode.is4xxClientError()
HttpStatusCode.is5xxServerError()
-
toString
Return a string representation of this status code.
- Overrides:
toString
in classEnum<HttpStatus>
-
valueOf
public static HttpStatus valueOf(int statusCode)
Return the
HttpStatus
enum constant with the specified numeric value.- Parameters:
statusCode
— the numeric value of the enum to be returned- Returns:
- the enum constant with the specified numeric value
- Throws:
IllegalArgumentException
— if this enum has no constant for the specified numeric value
-
resolve
Resolve the given status code to an
HttpStatus
, if possible.- Parameters:
statusCode
— the HTTP status code (potentially non-standard)- Returns:
- the corresponding
HttpStatus
, ornull
if not found - Since:
- 5.0
Issue
I am trying to test my web api thats secured using the standard Spring Security API. I have implemented my own User authentication service by implementing UserDetailService. However whenever I login to my application the /login api keeps returning a 302 redirect. I verified that my login page is working correctly by manually testing both good credentials and bad credentials and it did properly authenticate correctly to the homepage depending on whether the credentials were good, however it still returned a 302 for /login. Im wondering why Spring/Thymeleaf is returning a 302 redirect when performing the /login request. This is preventing my ability to test any of my guarded endpoints when locked down with spring security.
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public JwtTokenFilter jwtTokenFilter() {
return new JwtTokenFilter();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.cors()
.and()
.authorizeRequests().antMatchers("/profiles/**","/img/**","/resources","/v2/**","/users", "/login", "/error/**", "/keepalive", "/register").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/")
.permitAll()
.and()
.logout();
http.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(asList("*"));
configuration.setAllowedMethods(asList("HEAD",
"GET", "POST", "PUT", "DELETE", "PATCH"));
// setAllowCredentials(true) is important, otherwise:
// The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
configuration.setAllowCredentials(true);
// setAllowedHeaders is important! Without it, OPTIONS preflight request
// will fail with 403 Invalid CORS request
configuration.setAllowedHeaders(asList("Authorization", "Cache-Control", "Content-Type"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
Login.html Page
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
>
<head>
<title>Login</title>
<div th:replace="fragments/header :: header-css"/>
</head>
<body class="white-bg">
<div th:replace="fragments/header :: header"/>
<div class="middle-box text-center loginscreen">
<div>
<div>
<h1 class="logo-name"></h1>
</div>
<h3>Welcome to </h3>
<p>Login in. To see it in action.</p>
<form th:action="@{/login}" method="post">
<fieldset>
<div th:if="${param.error}">
<div class="alert alert-danger">
Invalid username and password.
</div>
</div>
<div th:if="${param.logout}">
<div class="alert alert-info">
You have been logged out.
</div>
</div>
<div class="form-group">
<input type="text" name="username" id="username" class="form-control"
placeholder="UserName" required="true" autofocus="true"/>
</div>
<div class="form-group">
<input type="password" name="password" id="password" class="form-control"
placeholder="Password" required="true"/>
</div>
<input type="submit" class="btn btn-lg btn-primary btn-block" value="Sign In"/>
<a href="#"><small>Forgot password?</small></a>
<p class="text-muted text-center"><small>Do not have an account?</small></p>
<a class="btn btn-sm btn-white btn-block" href="register.html">Create an account</a>
</fieldset>
</form>
<p class="m-t"> <small>DigiProof Company © 2017</small> </p>
</div>
</div>
BaseController.java for routing
@Controller
public class BaseController {
@Autowired
private UserService userService;
@GetMapping("/")
public String homeMain() {
return "home";
}
@GetMapping("/home")
public String home() {
return "home";
}
@GetMapping("/login")
public String login(Principal principal) {
if (principal!=null && ((Authentication)principal).isAuthenticated())
return "redirect:/home";
else
return "login";
}
@RequestMapping(value="/registration", method = RequestMethod.GET)
public ModelAndView registration(){
ModelAndView modelAndView = new ModelAndView();
User user = new User();
modelAndView.addObject("user", user);
modelAndView.setViewName("register");
return modelAndView;
}
@RequestMapping(value = "/registration", method = RequestMethod.POST)
public ModelAndView createNewUser(@Valid User user, BindingResult bindingResult) {
ModelAndView modelAndView = new ModelAndView();
User userByEmailExists = userService.findUserByEmail(user.getEmail());
if (userByEmailExists != null) {
bindingResult
.rejectValue("email", "error.user",
"There is already a user registered with the email provided");
}
if (bindingResult.hasErrors()) {
modelAndView.setViewName("register");
} else {
userService.save(user);
modelAndView.addObject("successMessage", "User has been registered successfully");
modelAndView.addObject("user", new User());
modelAndView.setViewName("register");
}
return modelAndView;
}
@GetMapping("/profile")
public String profile() {
return "profile";
}
@GetMapping("/activity")
public String activity() {
return "activity";
}
@GetMapping("/teams")
public String teams() {
return "teams";
}
@GetMapping("/404")
public String error404() {
return "/error/403";
}
@GetMapping("/403")
public String error403() {
return "/error/403";
}
@GetMapping("/500")
public String error500() {
return "/error/500";
}
@GetMapping("/error")
public String error() {
return "/error/500";
}
}
Solution
spring security formLogin default intercept the «/login» request, i find that your login page url is «/login» which is conflict with this filter. you can define your login page url like this:
.formLogin()
.loginPage("/page/login.html").permitAll()
and change then controller mapping from login —> /page/login
Answered By — Persia
Answer Checked By — Gilberto Lyons (JavaFixing Admin)
I use Spring 4 to create a simple application. Recently, I’m adding Spring Security 3 to the project but always get the Error Code 302 ( so it redirect to home page always ).
Here is my SecurityConfig:
@Configuration
@EnableWebMvcSecurity
@ComponentScan(basePackages = { "com.moon.repository" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("hello").password("world").roles("USER");
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring().antMatchers("/resources/**", "/views/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/home")
.loginProcessingUrl("/acct/signin")
.and()
.logout()
.permitAll();
}
}
I have a Controller called AccountController:
@Controller
@RequestMapping(value = "/acct")
public class AccountController {
private final Logger logger = LoggerFactory.getLogger(AccountController.class);
@RequestMapping(value = "/signin", method = RequestMethod.POST)
public String signin(@RequestParam("username") String username,
@RequestParam("password") String password) {
logger.info("======== [username:{0}][password:{1}] ========", username, password);
if ("[email protected]".equalsIgnoreCase(username)) {
return "error";
} else {
return "demo";
}
}
}
My WEB-INF structure:
WEB-INF
----views
--------home.jsp
--------demo.jsp
--------error.jsp
The flow is like:
- User access the web site with
http://mylocal:8080/moon
=> it shows home.jsp - User press the button SignIn and it pops a sub-window asked for username and password => still in home.jsp
- User press Submit button => I assume it will go /acct/signin and return to /demo, but I see Error 302 in Google Chrome and then it goes to /home again
Any ideas ? I’m stuck in 2 full days and now i’m almost in despair…
thank you very much every one to take a look at my problem
=================================== 1st Update ===================================
Update: The form in home.jsp
<form:form role="form" method="POST" action="acct/signin"
class="form-signin">
<div class="row">
<div class="col-lg-5">
<input name="username" size="20" type="email"
class="form-control" placeholder="Email address" required
autofocus>
<input name="password" type="password"
class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</div>
</div>
</form:form>
=================================== 2nd Update ===================================
I tried to implement UserDetailsService(not to use in-memory auth) but still… the same problem — Error 302
AppUserDetailsServiceImpl.java
@Component
public class AppUserDetailsServiceImpl implements UserDetailsService {
private final Logger logger = LoggerFactory.getLogger(AppUserDetailsServiceImpl.class);
@Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
logger.info("loadUserByUsername username=" + username);
logger.info("======== {} ========",SecurityContextHolder.getContext().getAuthentication());
if (!username.equals("hello")) {
throw new UsernameNotFoundException(username + " not found");
}
// creating dummy user details
return new UserDetails() {
private static final long serialVersionUID = 2059202961588104658L;
@Override
public boolean isEnabled() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return "world";
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> auths = new java.util.ArrayList<SimpleGrantedAuthority>();
auths.add(new SimpleGrantedAuthority("USER"));
return auths;
}
};
}
The log shows:
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](24) loadUserByUsername username=hello
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](25) ======== org.springframew[email protected]f1e4f742: Principal: [email protected]; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]12afc: RemoteIpAddress: 127.0.0.1; SessionId: 023BC9A8B997ECBD826DD7C33AF55FC7; Granted Authorities: USER ========
Issue
I have a problem with FeignClient. I am deployed Spring Boot applications, I get an error in a call to a specific feign client, the error comes up when I use a registration microservice when wanting to communicate with a specific method of a user microservice, with other methods the problem does not occur, I also have a Eureka server for discovery and a gateway with Spring Cloud Gateway, configured with the configuration for permissions. I have @EnableEurekaClient and @EnableFeignClients in applications and they can be seen on the Eureka server, and implements CircuitBreaker with resilience4j.
For testing I use postman.
for a request:
Without CircuitBreaker I get this error
feign.FeignException: [302] during [GET] to [http://app-usuarios/users/usuarioExisteDatos/?username=admin&email=admin%40udea.edu.co&cellPhone=3128211358] [UsersFeignClient#preguntarUsuarioExiste(String,String,String)]: true
at feign.FeignException.errorStatus(FeignException.java:182) ~[feign-core-10.12.jar:na]
at feign.FeignException.errorStatus(FeignException.java:169) ~[feign-core-10.12.jar:na]
at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:92) ~[feign-core-10.12.jar:na]
at feign.AsyncResponseHandler.handleResponse(AsyncResponseHandler.java:96) ~[feign-core-10.12.jar:na]
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:138) ~[feign-core-10.12.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89) ~[feign-core-10.12.jar:na]
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100) ~[feign-core-10.12.jar:na]
at jdk.proxy11/jdk.proxy11.$Proxy250.preguntarUsuarioExiste(Unknown Source) ~[na:na]
at com.app.registro.controllers.RegistroController.crearNuevo(RegistroController.java:28) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.13.jar:5.3.13]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.13.jar:5.3.13]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.13.jar:5.3.13]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.13.jar:5.3.13]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.13.jar:5.3.13]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.13.jar:5.3.13]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) ~[spring-webmvc-5.3.13.jar:5.3.13]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.13.jar:5.3.13]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.13.jar:5.3.13]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.13.jar:5.3.13]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.55.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.13.jar:5.3.13]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.55.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.55.jar:9.0.55]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.13.jar:5.3.13]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.13.jar:5.3.13]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.13.jar:5.3.13]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.13.jar:5.3.13]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.13.jar:5.3.13]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.13.jar:5.3.13]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.55.jar:9.0.55]
at java.base/java.lang.Thread.run(Thread.java:831) ~[na:na]
With CircuitBreaker:
[302] during [GET] to [http://app-usuarios/users/usuarioExisteDatos/?username=admin&email=admin%40udea.edu.co&cellPhone=3128211358] [UsersFeignClient#preguntarUsuarioExiste(String,String,String)]: [true]
for my registro microservice:
Model:
@Document(collection = "registro")
public class Registro {
@Id
private String id;
@NotBlank(message = "Username cannot be null")
@Size(max = 20)
@Indexed(unique = true)
@Pattern(regexp = "[A-Za-z0-9_.-]+", message = "Solo se permite:'_' o '.' o '-'")
private String username;
@NotBlank(message = "Password cannot be null")
@Pattern(regexp = "[^ ]*+", message = "Caracter: ' ' (Espacio en blanco) invalido")
@Size(min = 6, max = 20, message = "About Me must be between 6 and 20 characters")
private String password;
@NotBlank(message = "Cell phone cannot be null")
@Pattern(regexp = "[0-9]+", message = "Solo numeros")
@Size(max = 50)
@Indexed(unique = true)
private String cellPhone;
@NotBlank(message = "Email cannot be null")
@Size(max = 50)
@Pattern(regexp = "[^ ]*+", message = "Caracter: ' ' (Espacio en blanco) invalido")
@Email(message = "Email should be valid")
@Indexed(unique = true)
private String email;
private String codigo;
private List<String> roles;
** Constructors, setters and getters
}
My Client:
@FeignClient(name = "app-usuarios")
public interface UsersFeignClient {
@GetMapping("/users/usuarioExisteDatos")
public Boolean preguntarUsuarioExiste(@RequestParam(value = "username") String username,
@RequestParam(value = "email") String email, @RequestParam(value = "cellPhone") String cellPhone);
@GetMapping("/users/listar")
public List<Usuario> listarUsuarios();
}
My controller:
@RestController
public class RegistroController {
private final Logger logger = LoggerFactory.getLogger(RegistroController.class);
@SuppressWarnings("rawtypes")
@Autowired
private CircuitBreakerFactory cbFactory;
@Autowired
UsersFeignClient uClient;
@GetMapping("/registro/listarUsuarios")
public List<Usuario> verUsuarios() {
return uClient.listarUsuarios();
}
@PostMapping("/registro/crearNuevo")
@ResponseStatus(code = HttpStatus.CREATED)
public Boolean crearNuevo(@RequestBody @Validated Registro registro) {
// return uClient.preguntarUsuarioExiste(registro.getUsername(),
// registro.getEmail(), registro.getCellPhone());
return (Boolean) cbFactory.create("usuarios").run(() -> uClient.preguntarUsuarioExiste(registro.getUsername(),
registro.getEmail(), registro.getCellPhone()), e -> preguntarUsuarioExiste2(registro.getUsername(), e));
}
private Object preguntarUsuarioExiste2(String username, Throwable e) {
logger.info(e.getMessage());
return false;
}
}
my application properties:
#-------APP-------
spring.application.name=app-registro
server.port=${PORT:0}
#-----MongoDb------
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.authentication-database=admin
spring.data.mongodb.username=user
spring.data.mongodb.password=user
spring.data.mongodb.database=usuariosApp
spring.data.mongodb.auto-index-creation: true
#-----Eureka-------
eureka.instance.metadataMap.instanceId=${spring.application.name}:${spring.application.instance_id:${random.value}}
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
#-----Feign-------
feign.client.config.default.connect-timeout=10000
feign.client.config.default.read-timeout=10000
feign.client.config.default.logger-level=full
My 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.5.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.app.registro</groupId>
<artifactId>App-Registro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>App-Registro</name>
<description>Registro for App</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.0.4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
My method in microservice usuarios:
@GetMapping("/users/usuarioExisteDatos")
@ResponseStatus(HttpStatus.FOUND)
public Boolean preguntarUsuarioExiste(@RequestParam(value = "username") String username,
@RequestParam(value = "email") String email, @RequestParam(value = "cellPhone") String cellPhone)
throws InterruptedException {
return uRepository.existsByUsernameOrEmailOrCellPhone(username, email, cellPhone);
}
It should be noted that you are making a call to a MongoRepository interface
If I call the other client method, listUsers, the feign client works fine:
My method in microservicie usuarios for this is:
@GetMapping("/users/listar")
@ResponseStatus(code = HttpStatus.CREATED)
public List<Usuario> listarUsuarios() {
return uRepository.findAll();
}
I don’t understand why this happens
Solution
You have a few options here but let me clarify why this happens. Feign is an HTTP binder for your APIs. In normal cases when you communicate backend-backend, the de-facto accepted HTTP status codes are 2xx
to indicate that everything worked as expected. When an API reponds with a 3xx
(302
in your case), that indicates a redirect which is usually used to instruct the browser to redirect the user to another page upon doing something.
Anyway, now that we’ve cleared why this could happen, let’s see why your Feign client behaves this way. All Feign clients have a configuration parameter called follow-redirects
. This controls whether upon receiving a 3xx
HTTP response, the Feign client should automatically try to call the API specified in the response’s Location
header.
By default this parameter is set to true, meaning that redirects will be followed and it will be transparent for you, as a client user. From the exception, I think you somehow disabled it or you might use an HTTP client for which you disabled the redirect following manually.
Although I can clearly see from your implementation in the preguntarUsuarioExiste
method that you’re trying to decide whether a user exists in the system or not. In this case the 302 HTTP Found
status doesn’t make sense even though I understand why you’d want to use that (cause the term reflects that the user exists).
In this case, I’d simply remove the fixed 302
status with the @ResponseStatus
annotation and change the API to return a ResponseEntity
instead to resolve the status code dynamically. Something like this:
@GetMapping("/users/usuarioExisteDatos")
public ResponseEntity<?> preguntarUsuarioExiste(@RequestParam(value = "username") String username, @RequestParam(value = "email") String email, @RequestParam(value = "cellPhone") String cellPhone) throws InterruptedException {
boolean exists = uRepository.existsByUsernameOrEmailOrCellPhone(username, email, cellPhone);
if (exists) {
return ResponseEntity.ok().build();
} else {
return ResponseEntity.notFound().build();
}
}
This way when you invoke the API from the Feign client, you can simply handle the 404 case as a user is not found. Or even better, you could simply create an object as a response for your API which has the boolean value whether or not the user exists, something like:
{
"exists": false
}
Then you can map this object in your Feign client and deal with pure booleans.
As last, if you want to stick with the 302 status code, you can change your Feign client definition to return a feign.Response
class instead of a Boolean
.
That way, it will not fail with an exception but you’ll be in full control of what should happen with the response. You can access the status code, the body, everything what you need.
I strongly suggest to learn a bit more about Feign, there are many more culprits you can fall into especially when you’re combining it with service resiliency tools like Eureka and Resilience4J. And I’m not trying to advertise here but I really believe you need some guidance.
Check out my blog for articles on Feign: arnoldgalovics.com Feign articles
And also, check out my course for Feign, Spring Cloud OpenFeign and Resilience4J integration. I’m pretty much covering all what you’ll need: Mastering microservice communication with Spring Cloud Feign
Answered By – Arnold Galovics
This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0
Я использую Spring 4 для создания простого приложения. В последнее время я добавляю Spring Security 3 в проект, но всегда получаю код ошибки 302 (поэтому он всегда перенаправляется на страницу home).
Вот мой SecurityConfig:
@Configuration
@EnableWebMvcSecurity
@ComponentScan(basePackages = { "com.moon.repository" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("hello").password("world").roles("USER");
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring().antMatchers("/resources/**", "/views/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/home")
.loginProcessingUrl("/acct/signin")
.and()
.logout()
.permitAll();
}
}
У меня есть контроллер, называемый AccountController:
@Controller
@RequestMapping(value = "/acct")
public class AccountController {
private final Logger logger = LoggerFactory.getLogger(AccountController.class);
@RequestMapping(value = "/signin", method = RequestMethod.POST)
public String signin(@RequestParam("username") String username,
@RequestParam("password") String password) {
logger.info("======== [username:{0}][password:{1}] ========", username, password);
if ("[email protected]".equalsIgnoreCase(username)) {
return "error";
} else {
return "demo";
}
}
}
Моя структура WEB-INF:
WEB-INF
----views
--------home.jsp
--------demo.jsp
--------error.jsp
Поток выглядит так:
- Пользователь получает доступ к веб-сайту с помощью
http://mylocal:8080/moon
= > показывает home.jsp - Пользователь нажимает кнопку SignIn, и появляется всплывающее окно с запросом имени пользователя и пароля = > по-прежнему в home.jsp
- Пользователь нажимает кнопку Submit = = Я предполагаю, что он пойдет /acct/signin и вернется в /demo, но я вижу Error 302 в Google Chrome, а затем он снова возвращается в /home
Любые идеи? Я застрял в течение 2 полных дней, и теперь я почти в отчаянии…
Большое вам спасибо, чтобы взглянуть на мою проблему.
================================= Первое обновление ============================
Обновление: форма в home.jsp
<form:form role="form" method="POST" action="acct/signin"
class="form-signin">
<div class="row">
<div class="col-lg-5">
<input name="username" size="20" type="email"
class="form-control" placeholder="Email address" required
autofocus>
<input name="password" type="password"
class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</div>
</div>
</form:form>
================================= Второе обновление ======= ============================
Я попытался реализовать UserDetailsService (не использовать auth в памяти), но все же… та же проблема — Ошибка 302
AppUserDetailsServiceImpl.java
@Component
public class AppUserDetailsServiceImpl implements UserDetailsService {
private final Logger logger = LoggerFactory.getLogger(AppUserDetailsServiceImpl.class);
@Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
logger.info("loadUserByUsername username=" + username);
logger.info("======== {} ========",SecurityContextHolder.getContext().getAuthentication());
if (!username.equals("hello")) {
throw new UsernameNotFoundException(username + " not found");
}
// creating dummy user details
return new UserDetails() {
private static final long serialVersionUID = 2059202961588104658L;
@Override
public boolean isEnabled() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return "world";
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> auths = new java.util.ArrayList<SimpleGrantedAuthority>();
auths.add(new SimpleGrantedAuthority("USER"));
return auths;
}
};
}
В журнале отображается:
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](24) loadUserByUsername username=hello
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](25) ======== org.springframew[email protected]f1e4f742: Principal: [email protected]; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]12afc: RemoteIpAddress: 127.0.0.1; SessionId: 023BC9A8B997ECBD826DD7C33AF55FC7; Granted Authorities: USER ========
I use Spring 4 to create a simple application. Recently, I’m adding Spring Security 3 to the project but always get the Error Code 302 ( so it redirect to home page always ).
Here is my SecurityConfig:
@Configuration
@EnableWebMvcSecurity
@ComponentScan(basePackages = { "com.moon.repository" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("hello").password("world").roles("USER");
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring().antMatchers("/resources/**", "/views/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/home")
.loginProcessingUrl("/acct/signin")
.and()
.logout()
.permitAll();
}
}
I have a Controller called AccountController:
@Controller
@RequestMapping(value = "/acct")
public class AccountController {
private final Logger logger = LoggerFactory.getLogger(AccountController.class);
@RequestMapping(value = "/signin", method = RequestMethod.POST)
public String signin(@RequestParam("username") String username,
@RequestParam("password") String password) {
logger.info("======== [username:{0}][password:{1}] ========", username, password);
if ("[email protected]".equalsIgnoreCase(username)) {
return "error";
} else {
return "demo";
}
}
}
My WEB-INF structure:
WEB-INF
----views
--------home.jsp
--------demo.jsp
--------error.jsp
The flow is like:
- User access the web site with
http://mylocal:8080/moon
=> it shows home.jsp - User press the button SignIn and it pops a sub-window asked for username and password => still in home.jsp
- User press Submit button => I assume it will go /acct/signin and return to /demo, but I see Error 302 in Google Chrome and then it goes to /home again
Any ideas ? I’m stuck in 2 full days and now i’m almost in despair…
thank you very much every one to take a look at my problem
=================================== 1st Update ===================================
Update: The form in home.jsp
<form:form role="form" method="POST" action="acct/signin"
class="form-signin">
<div class="row">
<div class="col-lg-5">
<input name="username" size="20" type="email"
class="form-control" placeholder="Email address" required
autofocus>
<input name="password" type="password"
class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</div>
</div>
</form:form>
=================================== 2nd Update ===================================
I tried to implement UserDetailsService(not to use in-memory auth) but still… the same problem — Error 302
AppUserDetailsServiceImpl.java
@Component
public class AppUserDetailsServiceImpl implements UserDetailsService {
private final Logger logger = LoggerFactory.getLogger(AppUserDetailsServiceImpl.class);
@Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
logger.info("loadUserByUsername username=" + username);
logger.info("======== {} ========",SecurityContextHolder.getContext().getAuthentication());
if (!username.equals("hello")) {
throw new UsernameNotFoundException(username + " not found");
}
// creating dummy user details
return new UserDetails() {
private static final long serialVersionUID = 2059202961588104658L;
@Override
public boolean isEnabled() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return "world";
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> auths = new java.util.ArrayList<SimpleGrantedAuthority>();
auths.add(new SimpleGrantedAuthority("USER"));
return auths;
}
};
}
The log shows:
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](24) loadUserByUsername username=hello
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](25) ======== org.springframew[email protected]f1e4f742: Principal: [email protected]; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]12afc: RemoteIpAddress: 127.0.0.1; SessionId: 023BC9A8B997ECBD826DD7C33AF55FC7; Granted Authorities: USER ========
What is the default login error for springspring security?
Spring security by default will show login error in case customer provides invalid username or password. Spring security internally uses the Spring framework resource bundle feature to show customize error messages to the customer.
What is a 302 error in http?
The specification document of RFC for HTTP 1.0 states that the aim of a “302 Found” response code is intended to indicate that the client should execute a temporary redirect. However, many new browsers will process the code 302 received through the POST request as invalid GET request.
How to check server response code 301 or 302?
There is another option – to apply for checking the server response code to online services, for example, http://example. com/e_redirect/. If you set up a redirect correctly, after entering the domain name, you will see the response code 301 or 302. It depends on what kind of redirection you planned to receive initially.
How do I set up Spring Security for a web application?
This can be achieved either through the Spring Security configuration or web application configuration in the web.xml file. In the remaining sections, we will take a more in-depth look at each of these options.
To avoid having to create a new trivial SuccessHandler
, override the successfulAuthentication
method in your filter and just call the chain.doFilter()
method after having set the Authentication
object in the security context.
For me I came from a little different use-case but ‘suddenly’ had the same problem before it perfectly worked.
My Setup Spring with a ExtJs frontend where I now build in a rest interface.
It all worked super nice and then suddenly I started having http status 302 responses (WTH?)
Since I implemented by code by following this example: https://octoperf.com/blog/2018/03/08/securing-rest-api-spring-security/
there is a declaration of a SimpleUrlAuthenticationSuccessHandler.
See 4.4 SecurityConfig where the TokenAuthenticationFilter is constructed with a class NoRedirectStrategy; see 4.1 Redirect Strategy
In turn not having this NoRedirectStrategy set up in my extension of the AbstractAuthenticationProcessingFilter it would show me http 302 responses.
Вопрос:
Я использую Spring 4 для создания простого приложения. В последнее время я добавляю Spring Security 3 в проект, но всегда получаю код ошибки 302 (поэтому он всегда перенаправляется на страницу home).
Вот мой SecurityConfig:
@Configuration
@EnableWebMvcSecurity
@ComponentScan(basePackages = { "com.moon.repository" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("hello").password("world").roles("USER");
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring().antMatchers("/resources/**", "/views/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/home")
.loginProcessingUrl("/acct/signin")
.and()
.logout()
.permitAll();
}
}
У меня есть контроллер, называемый AccountController:
@Controller
@RequestMapping(value = "/acct")
public class AccountController {
private final Logger logger = LoggerFactory.getLogger(AccountController.class);
@RequestMapping(value = "/signin", method = RequestMethod.POST)
public String signin(@RequestParam("username") String username,
@RequestParam("password") String password) {
logger.info("======== [username:{0}][password:{1}] ========", username, password);
if ("error@1.1".equalsIgnoreCase(username)) {
return "error";
} else {
return "demo";
}
}
}
Моя структура WEB-INF:
WEB-INF
----views
--------home.jsp
--------demo.jsp
--------error.jsp
Поток выглядит так:
- Пользователь получает доступ к веб-сайту с помощью
http://mylocal:8080/moon
= > показывает home.jsp - Пользователь нажимает кнопку SignIn, и появляется всплывающее окно с запросом имени пользователя и пароля = > по-прежнему в home.jsp
- Пользователь нажимает кнопку Submit = = Я предполагаю, что он пойдет /acct/signin и вернется в /demo, но я вижу Error 302 в Google Chrome, а затем он снова возвращается в /home
Любые идеи? Я застрял в течение 2 полных дней, и теперь я почти в отчаянии…
Большое вам спасибо, чтобы взглянуть на мою проблему.
================================= Первое обновление ============================
Обновление: форма в home.jsp
<form:form role="form" method="POST" action="acct/signin"
class="form-signin">
<div class="row">
<div class="col-lg-5">
<input name="username" size="20" type="email"
class="form-control" placeholder="Email address" required
autofocus>
<input name="password" type="password"
class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</div>
</div>
</form:form>
================================= Второе обновление ======= ============================
Я попытался реализовать UserDetailsService (не использовать auth в памяти), но все же… та же проблема – Ошибка 302
AppUserDetailsServiceImpl.java
@Component
public class AppUserDetailsServiceImpl implements UserDetailsService {
private final Logger logger = LoggerFactory.getLogger(AppUserDetailsServiceImpl.class);
@Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
logger.info("loadUserByUsername username=" + username);
logger.info("======== {} ========",SecurityContextHolder.getContext().getAuthentication());
if (!username.equals("hello")) {
throw new UsernameNotFoundException(username + " not found");
}
// creating dummy user details
return new UserDetails() {
private static final long serialVersionUID = 2059202961588104658L;
@Override
public boolean isEnabled() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return "world";
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> auths = new java.util.ArrayList<SimpleGrantedAuthority>();
auths.add(new SimpleGrantedAuthority("USER"));
return auths;
}
};
}
В журнале отображается:
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](24) loadUserByUsername username=hello
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](25) ======== org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f1e4f742: Principal: com.moon.repository.AppUserDetailsServiceImpl$1@e3dc1b1; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@12afc: RemoteIpAddress: 127.0.0.1; SessionId: 023BC9A8B997ECBD826DD7C33AF55FC7; Granted Authorities: USER ========
Лучший ответ:
Я считаю, что Spring перенаправляет вас в /home
потому что вы на самом деле не аутентифицировали пользователя через процесс входа в систему.
- Вы
http://mylocal:8080/moon
доступ к своему веб-приложению черезhttp://mylocal:8080/moon
возвращая представление home.jsp - Вы нажимаете кнопку Войти, отправляя форму входа поскольку логин формы не объявляется явно, Spring Security отобразит окно с приглашением ввести имя пользователя и пароль, чтобы конечный пользователь мог ввести свои учетные данные
- Эти учетные данные затем отправляются на URL-адрес обработки входа (
/acct/signin
), для которого у вас есть сопоставление с методомsignin
вAccountController
- Такой контроллер не может аутентифицировать пользователя Spring, но все равно перенаправляет запрос в
/demo
, возвращая строку - Путь
/demo
защищен (.anyRequest().authenticated()
) для любого пользователя, не.anyRequest().authenticated()
проверку подлинности, поскольку текущий пользователь действительно не прошел проверку подлинности, Spring Security автоматически перенаправит запрос на страницу входа - Вы попали в
/home
(.loginPage("/home")
)
Используя InMemoryUserDetailsManagerConfigurer (см. Javadoc inMemoryAuthentication), вы можете успешно войти только через настроенные учетные данные. Если вам нужна полноценная система аутентификации, вы должны предоставить реализацию UserDetailsService для вашей конфигурации Spring Security (через метод userDetailsService).
РЕДАКТИРОВАТЬ: После разговора с chialin.lin, кажется, отсутствующая конфигурация была defaultSuccessfulUrl для Spring Security, чтобы знать, куда перенаправить пользователя после аутентификации.
Ответ №1
Для меня я пришел из немного другого варианта использования, но у “внезапно” возникла та же проблема, прежде чем она отлично заработала.
Мой Setup Spring с внешним интерфейсом ExtJs, где я сейчас встраиваю интерфейс отдыха.
Все работало очень хорошо, и вдруг у меня появилось http 302 ответа (WTH?)
Поскольку я реализовал с помощью кода, следуя этому примеру: https://octoperf.com/blog/2018/03/08/securing-rest-api-spring-security/
существует объявление SimpleUrlAuthenticationSuccessHandler.
См. 4.4 SecurityConfig, где TokenAuthenticationFilter создается с классом NoRedirectStrategy; см. 4.1 Стратегия перенаправления
В свою очередь, если бы в моем расширении AbstractAuthenticationProcessingFilter не было настроено NoRedirectStrategy, было бы показано http 302 ответа.
Ответ №2
Для того, чтобы избежать того, чтобы создать новое тривиальное SuccessHandler
, переопределить successfulAuthentication
метод в фильтре и просто вызовите chain.doFilter()
метод после установки Authentication
объекта в контексте безопасности.