Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring security - access request parameters inside UserDetailsService implementation

I'm working on a java spring mvc application. I have implemented the UserDetailsService interface like this:

@Component
@Transactional
public class SecurityDAO implements UserDetailsService{

     @Override
     public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
         ...
     }

     ....
}

I need to find the user login url inside loadUserByUsername method(because the project has multiple login urls). In fact, I want to access request parameters inside UserDetailsService implementation.

like image 489
hamed Avatar asked Apr 20 '16 07:04

hamed


People also ask

Which method in UserDetailsService needs to be implemented so that Spring Security Framework can get the user details of a specific user?

The UserDetailsService interface is used to retrieve user-related data. It has one method named loadUserByUsername() which can be overridden to customize the process of finding the user. It is used by the DaoAuthenticationProvider to load details about the user during authentication.

How does Spring Security authentication work internally?

The short answer: At its core, Spring Security is really just a bunch of servlet filters that help you add authentication and authorization to your web application. It also integrates well with frameworks like Spring Web MVC (or Spring Boot), as well as with standards like OAuth2 or SAML.

How do you allow a user only access their own data in spring boot?

In any @Controller , @RestController annotated bean you can use Principal directly as a method argument. @RequestMapping("/users/{user_id}") public String getUserInfo(@PathVariable("user_id") Long userId, Principal principal){ // test if userId is current principal or principal is an ADMIN .... }


3 Answers

Just inject the request on your service:

 @Autowired
 private HttpServletRequest request;

For it to work you need to register RequestContextListener previously, though:

@Bean 
public RequestContextListener requestContextListener(){
    return new RequestContextListener();
} 
like image 85
dambros Avatar answered Oct 17 '22 23:10

dambros


Simple way: 1) register RequestContextListener

@Bean
public RequestContextListener requestContextListener(){
return new RequestContextListener();
}

2) And to main class:

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.
currentRequestAttributes()).
getRequest();

3) After that we can take params in custom headers:

request.getHeader("OrganizationId")
like image 37
Игорь Демянюк Avatar answered Oct 17 '22 22:10

Игорь Демянюк


All the information is available through HttpServletRequest. You can obtain it by:

Dependency injection

The easiest way would be to inject servlet request directly into your UserDetailsService: class:

public MyDetailsService implements UserDetailsService {

  @Autowired
  private HttpServletRequest request;

  //...

}

or

public MyDetailsService implements UserDetailsService {

  @Autowired
  private HttpServletRequest request;

    public UserDetails loadUserByUsername(String username){
                HttpServletRequest request  =
             ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes())
                    .getRequest();
    }

}

Remember to add the following listener to your web.xml if you are not spring boot:

<listener>
    <listener-class>
        org.springframework.web.context.request.RequestContextListener
    </listener-class>
</listener>

If you are using spring boot, add below this.

@Bean 
public RequestContextListener requestContextListener(){
    return new RequestContextListener();
}

UPDATE: This works because Spring injects special scoped proxy implementing HttpServletRequest, so you are able to access request-scoped request "bean" from singleton-scoped MyDetailsService. Under the hood every call to request's parameters is routed to org.springframework.web.context.request.RequestContextHolder#requestAttributesHolder ThreadLocal which you can also access directly. As you can see Spring is very flexible when it comes to scoping rules. It just works.

RequestContextHolder

Another approach is to use RequestContextHolder:

HttpServletRequest request = 
  ((ServletRequestAttributes) RequestContextHolder.
    currentRequestAttributes()).
    getRequest();

Further reading:

  • Creating a Spring bean holds ServletRequest properties
  • Spring: how do I inject an HttpServletRequest into a request-scoped bean?
like image 6
Sudhakar Avatar answered Oct 17 '22 22:10

Sudhakar