简体   繁体   中英

Spring Boot Authorizes User In Rest Client, But Not In Browser (Rest Authorization)

Ok, so when I use my Rest Client (Insomnia). I am able to log into my Spring Server and successfully retrieves data afterwards.

But when I try to use my angularJS Client. I can successfully log in but then when I try to retrieve data, it sends back a 401 error as if it forgot I ever logged in. I am very confused.

You may notice X-AUTH-TOKEN in the code. As of right now, I do not have it setup where it is checking X-AUTH-TOKEN so disregard this and please note that it WORKS in my REST CLIENT but not in the Browser Client.

I even tried to add the same amount of request header information in my REST CLIENT as my browser client, it still retrieves data for it.

Below is my WebSecurityConfig

package app.config;

import app.repo.User.CustomUserDetailsService;
import app.security.RESTAuthenticationEntryPoint;
import app.security.RESTAuthenticationFailureHandler;
import app.security.RESTAuthenticationSuccessHandler;
import app.security.TokenAuthenticationService;
import app.security.filters.StatelessAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
@Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private static PasswordEncoder encoder;
    @Autowired
    private TokenAuthenticationService tokenAuthenticationService;

    private CustomUserDetailsService userService;

    @Autowired
    private UserDetailsService customUserDetailsService;

    @Autowired
    private RESTAuthenticationEntryPoint authenticationEntryPoint;
    @Autowired
    private RESTAuthenticationFailureHandler authenticationFailureHandler;
    @Autowired
    private RESTAuthenticationSuccessHandler authenticationSuccessHandler;

    @Autowired
    public void configureAuth(AuthenticationManagerBuilder auth,DataSource dataSource) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/**").authenticated();
        http.csrf().disable();
        http.httpBasic();
        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
        http.formLogin().defaultSuccessUrl("/").successHandler(authenticationSuccessHandler);
        http.formLogin().failureHandler(authenticationFailureHandler);

//        http.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService),
//                UsernamePasswordAuthenticationFilter.class);

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserDetailsService);
    }

    @Bean
    @Override
    public CustomUserDetailsService userDetailsService() {
        return userService;
    }

    @Bean
    public TokenAuthenticationService tokenAuthenticationService() {
        this.userService = new CustomUserDetailsService();
        tokenAuthenticationService = new TokenAuthenticationService("tooManySecrets", customUserDetailsService);
        return tokenAuthenticationService;
    }
}

I also have a CorsFilter

package app.config;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class CorsFilter implements Filter {

    private final Logger log = LoggerFactory.getLogger(CorsFilter.class);

    public CorsFilter() {
        log.info("SimpleCORSFilter init");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Expose-Headers", "X-Auth-Token");
        response.setHeader("Access-Control-Allow-Headers",
                "Content-Type, Accept, X-Requested-With, remember-me");

        chain.doFilter(req, res);
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }

}

Why is it that Spring accepts my Spring Requests after logging in, but not my Client Request after logging in.

I check If the user is authenticated via persistent database

package app.repo.User;

import app.cache.UserService;
import app.security.UserAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AccountStatusUserDetailsChecker;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@Qualifier("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepo userRepository;

    @Autowired
    private UserService userService;

    private final AccountStatusUserDetailsChecker detailsChecker = new AccountStatusUserDetailsChecker();
    private final HashMap<String, User> userMap = new HashMap<String, User>();

    @Transactional(readOnly=true)
    @Override
    public UserDetails loadUserByUsername(final String username)
            throws UsernameNotFoundException {

        app.repo.User.User user = userRepository.findByUsername(username);
        if(user == null) {
            throw new UsernameNotFoundException("Bad Credentials");
        }
        userService.setUserInfo(user);
        List<GrantedAuthority> authorities = buildUserAuthority(user.getRoles());
        UserDetails userDetails = buildUserForAuthentication(user, authorities);
//        detailsChecker.check(userDetails);
        return userDetails;

    }

    private UserDetails buildUserForAuthentication(app.repo.User.User user,
                                            List<GrantedAuthority> authorities) {
        return new User(user.getUsername(), user.getPassword(), authorities);
    }

    private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {

        Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

        // Build user's authorities
        for (UserRole userRole : userRoles) {
            setAuths.add(new SimpleGrantedAuthority(userRole.getRoleName()));
        }

        return new ArrayList<GrantedAuthority>(setAuths);
    }

    public void addUser(User user) {
        userMap.put(user.getUsername(), user);
    }
}

Here is my Request Headers for Browser LOGIN

Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:0
Host:localhost:8080
Origin:http://localhost:8100
Referer:http://localhost:8100/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36

Here are response headers for browser LOGIN

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, Accept, X-Requested-With, remember-me
Access-Control-Allow-Methods:POST, GET, OPTIONS, DELETE
Access-Control-Allow-Origin:http://localhost:8100
Access-Control-Expose-Headers:X-Auth-Token
Access-Control-Max-Age:3600
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Length:88
Date:Thu, 19 Nov 2015 16:22:39 GMT
Expires:0
Pragma:no-cache
Server:Apache-Coyote/1.1
Set-Cookie:JSESSIONID=966F22A08A6D30E73FDC0DF40749C5C2; Path=/; HttpOnly
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

Here are Request Headers For Retrieving Data in browser

Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:0
Host:localhost:8080
Origin:http://localhost:8100
Referer:http://localhost:8100/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36

response headers for retrieving data Data in Browser

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, Accept, X-Requested-With, remember-me
Access-Control-Allow-Methods:POST, GET, OPTIONS, DELETE
Access-Control-Allow-Origin:http://localhost:8100
Access-Control-Expose-Headers:X-Auth-Token
Access-Control-Max-Age:3600
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Type:application/json;charset=UTF-8
Date:Thu, 19 Nov 2015 16:25:03 GMT
Expires:0
Pragma:no-cache
Server:Apache-Coyote/1.1
Transfer-Encoding:chunked
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

For my Rest Client. The Response Headers are the Same. For The Request headers for Rest Client, It doesnt have any to show. But I tried adding the exact same headers to the Rest Client and it still works.

Here is my angularjs call

$http({
  method: 'POST',
  url: loginUrl
}).then(function successCallback(response) {
  var resp = response;
  $http({
    method: 'POST',
    url: $scope.siteUrl+'/get-all-games'
  }).then(function successCallback(response) {
    var resp = response;
      // this callback will be called asynchronously
      // when the response is available
  }, function errorCallback(response) {
    var resp = response;
      // called asynchronously if an error occurs
      // or server returns response with an error status.
  });
    // this callback will be called asynchronously
    // when the response is available
}, function errorCallback(response) {
  var resp = response;
    // called asynchronously if an error occurs
    // or server returns response with an error status.
}); 

I setup my $http call to do a call to retrieve data immediately after success of login... It still returns a 401 error even though I successfully logged in.

The credential info, which is cookie/session id in this case, should be carried with your request for retrieving data in browser. The angular client can be configured like the following to do that.

$httpProvider.defaults.withCredentials = true;

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

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