Spring 如何在InputerDetails服务中获取客户端IP地址

Spring 如何在InputerDetails服务中获取客户端IP地址,spring,spring-boot,spring-security,Spring,Spring Boot,Spring Security,我想从ImplUserDetails类中的loadUserByUsername方法中获取客户端IP地址。这是我的代码,但它不起作用 @Service public class LoginServiceImpl implements UserDetailsService { @Autowired UserDao loginDao; @Autowired private HttpServletRequest request; @Override public UserDetails loadU

我想从ImplUserDetails类中的loadUserByUsername方法中获取客户端IP地址。这是我的代码,但它不起作用

@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){
    // ...
}
}
它得到了分离:

java.lang.IllegalStateException:未找到线程绑定请求:是 您引用了实际web请求之外的请求属性, 或者在最初接收线程之外处理请求?如果 您实际上是在web请求中操作,并且仍然收到此请求 消息,您的代码可能正在外部运行 DispatcherServlet/DispatcherPortlet:在这种情况下,使用 RequestContextListener或RequestContextFilter公开当前 请求

将loadUserByUsernameString用户名更改为

loadUserByUsernameString用户名,HttpServletRequest请求

将请求从控制器端传递到服务端。像下面这样

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";
        }
}

从服务端删除HttpServletRequest autowire。

有多种选项可以使@Autowired能够将HttpServletRequest注入bean:

注册RequestContextListener 注册RequestContextFilter。确保将其放置在过滤器链的最开头,例如springSecurityFilterChain之前
如果您正在使用Spring boot,并且在类路径上有一个Spring mvc,那么默认情况下,它的自动配置应该为您注册一个。

它是UserDetailsService的一个实现,不能更改数字参数方法Interface中没有此覆盖更改UserDetailsService接口中的方法定义。然后可以在LoginServiceImpl类中重写。另一方面,HttpServletRequest是一个web内容。您可以在应用程序web交互时获得这些信息。因此,它必须从控制器端或拦截器传递。如果他更改接口方法定义,他必须每次手动执行登录,并且不能使用spring security的自动登录筛选器。检查此问题