Spring 302 error

declaration: package: org.springframework.http, enum: HttpStatus

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
  • 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 name
    NullPointerException — if the argument is null
  • value

    public int value()

    Return the integer value of this status code.

    Specified by:
    value in interface HttpStatusCode
  • 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 interface HttpStatusCode
    See Also:
    • RFC 2616
  • is2xxSuccessful

    public boolean is2xxSuccessful()

    Whether this status code is in the Successful class (2xx).

    Specified by:
    is2xxSuccessful in interface HttpStatusCode
    See Also:
    • RFC 2616
  • is3xxRedirection

    public boolean is3xxRedirection()

    Whether this status code is in the Redirection class (3xx).

    Specified by:
    is3xxRedirection in interface HttpStatusCode
    See Also:
    • RFC 2616
  • is4xxClientError

    public boolean is4xxClientError()

    Whether this status code is in the Client Error class (4xx).

    Specified by:
    is4xxClientError in interface HttpStatusCode
    See Also:
    • RFC 2616
  • is5xxServerError

    public boolean is5xxServerError()

    Whether this status code is in the Server Error class (5xx).

    Specified by:
    is5xxServerError in interface HttpStatusCode
    See Also:
    • RFC 2616
  • isError

    public boolean isError()

    Whether this status code is in the Client or Server Error class

    Specified by:
    isError in interface HttpStatusCode
    See Also:
    • RFC 2616
    • RFC 2616
      (4xx or 5xx).
    • HttpStatusCode.is4xxClientError()
    • HttpStatusCode.is5xxServerError()
  • toString

    Return a string representation of this status code.

    Overrides:
    toString in class Enum<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, or null 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 &copy; 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:

  1. User access the web site with http://mylocal:8080/moon => it shows home.jsp
  2. User press the button SignIn and it pops a sub-window asked for username and password => still in home.jsp
  3. 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:

postman 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:

Users List

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:

  1. User access the web site with http://mylocal:8080/moon => it shows home.jsp
  2. User press the button SignIn and it pops a sub-window asked for username and password => still in home.jsp
  3. 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 потому что вы на самом деле не аутентифицировали пользователя через процесс входа в систему.

  1. Вы http://mylocal:8080/moon доступ к своему веб-приложению через http://mylocal:8080/moon возвращая представление home.jsp
  2. Вы нажимаете кнопку Войти, отправляя форму входа поскольку логин формы не объявляется явно, Spring Security отобразит окно с приглашением ввести имя пользователя и пароль, чтобы конечный пользователь мог ввести свои учетные данные
  3. Эти учетные данные затем отправляются на URL-адрес обработки входа (/acct/signin), для которого у вас есть сопоставление с методом signin в AccountController
  4. Такой контроллер не может аутентифицировать пользователя Spring, но все равно перенаправляет запрос в /demo, возвращая строку
  5. Путь /demo защищен (.anyRequest().authenticated()) для любого пользователя, не .anyRequest().authenticated() проверку подлинности, поскольку текущий пользователь действительно не прошел проверку подлинности, Spring Security автоматически перенаправит запрос на страницу входа
  6. Вы попали в /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 объекта в контексте безопасности.

Понравилась статья? Поделить с друзьями:
  • Spotify как изменить адрес электронной почты
  • Spotify installer error code 24 как исправить
  • Spore как изменить цвет империи на этапе космос
  • Spore как изменить существо на этапе космос
  • Spooler subsystem app обнаружена ошибка приложение будет закрыто windows xp