如何在ImpUserDetailsS​​ervice中获取客户端IP地址

时间:2019-05-18 08:38:23

标签: spring spring-boot spring-security

我想从方法implUserDetailsS​​ervice类的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:找不到线程绑定请求:是   您指的是实际网络请求之外的请求属性,   或在原始接收线程之外处理请求?如果   您实际上是在网络请求中进行操作,但仍然收到此请求   消息,您的代码可能正在外部运行   DispatcherServlet / DispatcherPortlet:在这种情况下,请使用   RequestContextListener或RequestContextFilter公开当前   请求。

2 个答案:

答案 0 :(得分:0)

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

  1. 注册RequestContextListener
  2. 注册RequestContextFilter。确保将其放在过滤器链的最开始(例如springSecurityFilterChain之前)

如果您使用的是Spring Boot,并且在类路径上具有spring-mvc,则其自动配置默认应为您注册一个RequestContextFilter

答案 1 :(得分:-2)

loadUserByUsername(String username)更改为

loadUserByUsername(String username, HttpServletRequest request)

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

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自动装配。