Spring External web request scope

I'm in the process of writing a Spring REST type interface for a database that will get specific results for various resources.

To keep the user, as a temporary measure, I have a Spring @Component annotated bean called CurrentUser.

@Component
public class CurrentUser {

    @Autowired
    private UserDAO userDAO;    

    private String userId;
    private String email;
    private String notes;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) throws ApiException {  
        User user = userDAO.getUser(userId) // Database call to 
        if (!user.isValid()) {
            throw ApiException(...)     // The exception would crash back to the user as a error in the response
        }       

        // Valud user so set these aspects. 
        this.userId = user.userId;      
        this.email = user.email;
    }
}

      

This object is initialized in the Spring Interceptor every time any method is called in the API using the following interceptor.

public class AuthenticationInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private CurrentUser user; 

    @Autowired
    private RequestParameters requestParameters;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ApiException {
        user.setUserId(StringUtils.defaultString(request.getParameter("userId"), "defaultUser"));
        return true;
    }
} 

      

It's only the seat owner to identify users until proper authentication is added.

I am relatively new to Spring and the reason for this post is to improve my understanding of Spring thread security aspects in situations like this

I recently discovered that Spring is not automatically thread safe, I may need more scoping attention.

I want to understand the following:

  • For the above setup, is there any danger that 1000 concurrent requests can interfere and overwrite each other? for example, a request for one user could potentially be overwritten by another user from a separate HTTP request, causing the requestor to receive invalid data.

  • What would be the best approach to solving this issue. (Even though it will be replaced, I have other objects created in a similar way) The options I am looking at (if this is a problem) sets the scope of the prototype or attaches directly to the request / session rather than letting them in their own object with autodetection.

Any information anyone could give me would be greatly appreciated as I will love her right (uh) to start with her rather than deal with bad assumptions later.

+3


source to share


2 answers


Answer 1: Yes, and you don't need 1000 requests to get into trouble. 2 requests in parallel.

Answer 2: The main problem here is one of the areas:

The default scope of Spring managed beans is Singleton. This means that there is only one instance of your CurrentUser per application.

This is clearly not what you want. (Since you have a serious security issue, there is only one CurrentUser instance per application).

Simple answer:

I would probably use Spring Security; -)



Even a simple answer:

If that's not an option:

  • Use a filter instead of a HandlerInterceptor (more direct control over cleanup)

  • Create Thread Local to store the user (and finally in Filter to clean it up) and set it to Filter

  • Create a service with a limited request (use @ScopedProxy to hook it up to Singletons) that refers to ThreadLocal as a UserService (you'll need an interface to make it work easily)

  • Autowire this UserService wherever you need it

Since every request in the Servlet framework is thread-bound by specification, and thread locators are inherently thread-safe, you are completely thread-safe and scale well. Restricted proxy server overhead is minimal.

(This is the only option, other parameters can explicitly use the request scope or use aspects in a slightly more elegant way. However, this is a fairly simple approach and gets the job done. For more complex needs, I would seriously recommend learning Spring Security).

+2


source


You can use spring mvc parameter recognition feature without making it a bean. to do this, execute the HandlerMethodArgumentResolver interface and register it with the container. And then your handler method can have a type argument of the current user

import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver{

@Override
public boolean supportsParameter(MethodParameter parameter) {
    if (parameter.getParameterType().equals(CurrentUser.class)) {
        return true;
    }
    return false;
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
        WebDataBinderFactory binderFactory) throws Exception {
    if (supportsParameter(parameter)) {
        String userId = (String) webRequest.getAttribute("userId", NativeWebRequest.SCOPE_REQUEST);
        return new CurrentUser(userId);
    }
    return null;
}

public class CurrentUser{

    public CurrentUser(String userId) {
        // TODO Auto-generated constructor stub
    }

}
}

      



After that you can have a handler method like

@RequestMapping
public String handler(CurrentUser user){
....
}

      

0


source







All Articles