Get user IP in Spring Boot

For security reasons, we need to get user IP. In a normal Spring Boot application that interacts with end-users directly (without proxy, load balance and etc.), We can simply get user IP from HttpServletRequest by getRemoteHost().

But in most cases, we need to put an Nginx or Apache in front of our application and route requests to it. In this case, HttpServletRequest.getRemoteHost() returns our proxy server IP. So we need to set user IP in a header of request in our proxy and then redirect it to our application. X-FORWARDED-FOR is used for this reason but there is more than one option:

  • X-Forwarded-For
  • Proxy-Client-IP
  • WL-Proxy-Client-IP
  • HTTP_X_FORWARDED_FOR
  • HTTP_X_FORWARDED
  • HTTP_X_CLUSTER_CLIENT_IP
  • HTTP_CLIENT_IP
  • HTTP_FORWARDED_FOR
  • HTTP_FORWARDED
  • HTTP_VIA
  • REMOTE_ADDR

We can put these options in the application properties file and then check them in our code like this one:


application:
  header-ip-candidates: X-Forwarded-For,Proxy-Client-IP,WL-Proxy-Client-IP,HTTP_X_FORWARDED_FOR,HTTP_X_FORWARDED,HTTP_X_CLUSTER_CLIENT_IP,HTTP_CLIENT_IP,HTTP_FORWARDED_FOR,HTTP_FORWARDED,HTTP_VIA,REMOTE_ADDR

@RestController
@RequestMapping("/ip")
public class IPResource {

    @Value("${application.header-ip-candidates}")
    private String[] headerCandidates;

    @GetMapping
    public ResponseEntity getHome() {
        if (RequestContextHolder.getRequestAttributes() == null) {
            return ResponseEntity.ok("0.0.0.0");
        }

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        for (String header: headerCandidates) {
            String ipList = request.getHeader(header);
            if (ipList != null && ipList.length() != 0 && !"unknown".equalsIgnoreCase(ipList)) {
                String ip = ipList.split(",")[0];
                return ResponseEntity.ok(ip);
            }
        }
        return ResponseEntity.ok(request.getRemoteAddr());
    }
}

Convert file to base64 on fron-end in VueJS

It's a normal task to upload a file from the front-end to the back-end. And every developer tried it. Posting a file with a form data type request is a normal way. But what if we want to show a image before upload it to the server? We have an image box and we want to show it to the user before save it.

I found a solution base on base64. I convert the image to base64 and assign it to a variable and connect the image box to present it. Also we can upload base64 to the server and there we convert it to binary image format and save it!

In VueJS, I using the watch to monitor changes on the image field that a user use to select a image, and after user choose a image, front-end app convert it to a base64 string and store it into another variable that connected to the image box.

Let check them in code. At first, I'll define two variable:

  1. image: connected to file input
  2. base64: to keep result of conversion
Then I set a watcher on image, to update base64 variable on image's changes:


    image: function (newVal, oldVal) {
      if(newVal) {
        this.createBase64Image(newVal);
      } else {
        this.base64 = null;
      }
    }

And at the end, I define a function to convert image to base64 and update base64 variable:


    createBase64Image: function(FileObject) {
      const reader = new FileReader();
      reader.onload = (event) => {
        this.base64 = event.target.result;
      }
      reader.readAsDataURL(FileObject);
    }

You can check out https://codepen.io/glinboy/pen/KKvEzjy for an online sample :)

Make rows clickable in VueJS table with ignore a column(s)

 As an old experience, I prefer user can select a row in table with click on it, instance of using a button in last column. In VueJS, we can easily add @click on the <tr> tag like it:

But what about last column buttons? for example, if we have a delete button and also an edit button at last column, to make user comfortable with our data table.

As a long search, I found out that we can easily use @click.stop on the <td> column's tag and then our buttons are free to run their function:

Please check out: https://codepen.io/glinboy/pen/YzxBQEN, for a simple sample :)