0

I want get client IP address in method loadUserByUsername() from class implUserDetailsService this my code but it doesn't work

@Service
public class LoginServiceImpl implements UserDetailsService {

@Autowired
UserDao loginDao;

@Autowired
private HttpServletRequest request;

@Override
public UserDetails loadUserByUsername(String username) {
    try {
        final String ip = getClientIp(request);

        net.liyan.psc.main.entity.main.User user = loginDao.findByUserNameForLogin(username);
        if (user == null) throw new UsernameNotFoundException("User not found.");
        Set<GrantedAuthority> grantedAuthorities = new HashSet<>();

        if (isLocalZone()) {
            grantedAuthorities.add(new SimpleGrantedAuthority('ROLE_1'));
        } else {
            grantedAuthorities.add(new SimpleGrantedAuthority('ROLE_2'));
        }

        return new org.springframework.security.core.userdetails.User(
                user.getUsername(),
                user.getPassword(),
                true,
                true,
                true,
                true,
                grantedAuthorities);
    } catch (UsernameNotFoundException ex) {
        throw new UsernameNotFoundException("User not found.");
    } catch (Exception ex) {
        throw new UsernameNotFoundException("User not found.");
    }
}

   private static String getClientIp(HttpServletRequest request) {

    String remoteAddr = "";

    if (request != null) {
        remoteAddr = request.getHeader("X-FORWARDED-FOR");
        if (remoteAddr == null || "".equals(remoteAddr)) {
            remoteAddr = request.getRemoteAddr();
        }
    }

    return remoteAddr;
}


private boolean isLocalZone(String Ip){
    // ...
}
}

It get exseption:

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

Romil Patel
  • 12,879
  • 7
  • 47
  • 76
majid_shoorabi
  • 121
  • 1
  • 1
  • 16
  • check out this question https://stackoverflow.com/questions/36736861/spring-security-access-request-parameters-inside-userdetailsservice-implementa – Toerktumlare May 18 '19 at 21:31

2 Answers2

0

There are various options to make @Autowired able to inject HttpServletRequest into a bean:

  1. Register RequestContextListener
  2. Register RequestContextFilter. Make sure it is placed at the very beginning of the filter chain (e.g. Before springSecurityFilterChain)

If you are using Spring boot and have a spring-mvc on the classpath , its auto-configuration should register one RequestContextFilter for you by default.

Ken Chan
  • 84,777
  • 26
  • 143
  • 172
-2

Change the loadUserByUsername(String username) to

loadUserByUsername(String username, HttpServletRequest request)

Pass the request from controller end to your service end. Something like below,

import javax.servlet.http.HttpServletRequest;
@Controller
public class YourControllerName {
       @Autowired
       UserDetailsService userDetailsService 
       @GetMapping("/your-url")
       public String methodName(HttpServletRequest request /*your other perams*/){
              UserDetails userDetails = userDetailsService .loadUserByUsername(String 
              username, request); 
              //other operations
             return "view";
        }
}

Remove the HttpServletRequest autowire from service end.

jese_moriarty
  • 178
  • 1
  • 5
  • it's an implement of UserDetailsService and can't change number parameter method there is't this Override in interface – majid_shoorabi May 18 '19 at 09:59
  • Change the method defination in UserDetailsService Interface. You can then override in LoginServiceImpl class. On a different note HttpServletRequest is a web content. You get this upon your application web interaction. So it has to pass from controller end or from interceptor. – jese_moriarty May 18 '19 at 10:03
  • if he changes the interface method definition, he must perform the login manually everytime and cannot use spring security's automatic login filter. – Toerktumlare May 18 '19 at 21:29