background
We have a Web project that provides a number of Rest apis. Access control is also implemented so that requests to access the API must carry tokens obtained after prior authentication.
Authentication is carried out in Filter, which obtains the requested Token for verification. If successful, the user information in the Token can be obtained. The core of this paper is to explain how to gracefully transfer the user information (user ID) to the API interface (Controller).
Method 1 (Sucks)
We have carried out a unified interception in Filter. If the user ID is obtained in Controller, the Token can still be resolved again to obtain the user ID
@GetMapping("/hello")
public String test(HttpServletRequest request) {
String token = request.getHeader("token");
JWTResult result = JWTUtils.checkToken(token);
Long userId = result.getUserId();
}
Copy the code
Method 2 (Elegant)
Method 1 requires the Token to be parsed again, which wastes resources. We can pass the user ID parsed in Filter directly to the interface through the Header.
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String token = request.getHeader("token");
JWTResult result = JWTUtils.checkToken(token);
Long userId = result.getUserId();
HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(httpRequest) {
@Override
public String getHeader(String name) {
if (name.equals("loginUserId")) {
return userId .toString();
}
returnsuper.getHeader(name); }}; chain.doFilter(requestWrapper, httpResponse); }Copy the code
The interface gets the parsed user ID directly from the Header:
@GetMapping("/hello")
public String save2(HttpServletRequest request) {
Long userId = Long.parseLong(request.getHeader("loginUserId"));
}
Copy the code
Method 3 (elegant)
It’s nice to pass it through the Header, but if you’re a code freakish, you might feel a little weird if you don’t use the Header. Let’s say I define a loginUserId parameter on the method, and you inject it in.
GET parameter mode
Append parameters to Filter:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String token = request.getHeader("token");
JWTResult result = JWTUtils.checkToken(token);
Long userId = result.getUserId();
HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(httpRequest) {
@Override
public String[] getParameterValues(String name) {
if (name.equals("loginUserId")) {
return new String[] { userId .toString() };
}
return super.getParameterValues(name);
}
@Override
public Enumeration<String> getParameterNames() {
Set<String> paramNames = new LinkedHashSet<>();
paramNames.add("loginUserId");
Enumeration<String> names = super.getParameterNames();
while(names.hasMoreElements()) {
paramNames.add(names.nextElement());
}
returnCollections.enumeration(paramNames); }}; chain.doFilter(requestWrapper, httpResponse); }Copy the code
Directly fill in the parameters in the interface to obtain:
@GetMapping("/hello") public String save2(String name, Long loginUserId) {// loginUserId is the value appended to Filter}Copy the code
For POST requests, you can also do this:
@PostMapping("/hello")
public String save2(User user, Long loginUserId) {
}
Copy the code
However, when we use post requests, either as form submissions or as json bodies, we don’t use get arguments, which means we need to inject the loginUserId into the object:
Create a parameter entity class:
public class User {
private String name;
private Long loginUserId;
}
Copy the code
Simulate form submission to see if it works:
@PostMapping("/hello")
public User save2(User user) {
return user;
}
Copy the code
Testing with PostMan, the form mode is supported directly:
Try Json submission again:
@PostMapping("/hello")
public User save2(@RequestBody User user) {
return user;
}
Copy the code
If you look at the picture below, it failed and you have to find a way to implement it again
Only need to modify the content of the submitted in HttpServletRequestWrapper can:
@Override
public ServletInputStream getInputStream() throws IOException {
byte[] requestBody = new byte[0];
try {
requestBody = StreamUtils.copyToByteArray(request.getInputStream());
Map map = JsonUtils.toBean(Map.class, new String(requestBody));
map.put("loginUserId", loginUserId);
requestBody = JsonUtils.toJson(map).getBytes();
} catch (IOException e) {
throw new RuntimeException(e);
}
final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
}
Copy the code
Insert user ID from Token resolution into parameter. Insert user ID from Token resolution into parameter.