How to quickly view login user’s IP address and other information in spring security?

Time:2020-10-22

The last article talked about how to use a more elegant way to customize spring security login logic. A more elegant way can effectively avoid the inefficiency brought about by custom filters. It is recommended that you read it and understand the authentication logic in spring security by the way.

On the basis of the above, this paper will continue to discuss with you how to store login user details.

This is the 12th article in this series. Read the previous articles in this series to better understand this article:

  1. Dig a big hole and spring security will open up!
  2. SongGe takes you to spring security hand in hand. Don’t ask how to decrypt the password
  3. Hand in hand to teach you to customize the form login in spring security
  4. Spring security does front-end and back-end separation, so we don’t do page Jump! All JSON interaction
  5. Authorization in spring security is so simple
  6. How does spring security store user data in the database?
  7. Spring Security + spring data JPA join forces to make security management easier!
  8. Spring boot + spring security realizes automatic login function
  9. How to control the security risk of spring boot automatic login?
  10. In microservice projects, where is spring security better than Shiro?
  11. Two ways of spring security custom authentication logic (Advanced playing method)

OK, no nonsense. Let’s take a look at today’s article.

1.Authentication

I have talked with you many times in front of the authentication interface, and I will talk about it again today.

The authentication interface is used to store our login user information. In fact, it is used for the principal( java.security.Principal )Further encapsulation is done.

Let’s look at a definition of authentication:

public interface Authentication extends Principal, Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();
    Object getCredentials();
    Object getDetails();
    Object getPrincipal();
    boolean isAuthenticated();
    void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

The interface is explained as follows:

  1. The getauthorities method is used to obtain the user’s permissions.
  2. The getcredentials method is used to obtain the user’s credentials, usually passwords.
  3. The getdetails method is used to get the details carried by the user, possibly the current request or something.
  4. The getprincipal method is used to get the current user, which may be a user name or a user object.
  5. Isauthenticated whether the current user is authenticated successfully.

Here is a fun method called getdetails. For this method, the source code is explained as follows:

Stores additional details about the authentication request. These might be an IP address, certificate serial number etc.

From this explanation, we can see that this method is actually used to store other information about authentication, such as IP address, certificate information, etc.

In fact, by default, the IP address and sessionid of the user login are stored here. Let’s look at it from the perspective of source code.

2. Source code analysis

SongGe’s spring security series has been written to Article 12. After reading the previous article, I believe you have understood that a filter that users must go through is the usernamepasswordauthenticationfilter. In the attemptauthentication method of this class, the request parameters are extracted. In the attemptauthentication method, a method, setdetails, will be called.

Let’s take a look at the setdetails method:

protected void setDetails(HttpServletRequest request,
        UsernamePasswordAuthenticationToken authRequest) {
    authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}

As for the authentication details, we set the authentication details value in the authentication details

public class WebAuthenticationDetailsSource implements
        AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {
    public WebAuthenticationDetails buildDetails(HttpServletRequest context) {
        return new WebAuthenticationDetails(context);
    }
}
public class WebAuthenticationDetails implements Serializable {
    private final String remoteAddress;
    private final String sessionId;
    public WebAuthenticationDetails(HttpServletRequest request) {
        this.remoteAddress = request.getRemoteAddr();

        HttpSession session = request.getSession(false);
        this.sessionId = (session != null) ? session.getId() : null;
    }
    //Omit other methods
}

By default, webauthenticationdetails source is used to build webauthenticationdetails, and the result is set to the details property of authentication. As for the properties defined in webauthentication details, you can basically see that the user login address and sessionid are saved.

So, you can basically understand that the IP address of the user login can be obtained directly from the webauthentication details.

Let me give a simple example. For example, after we log in successfully, we can get the user’s IP address anytime, anywhere through the following methods:

@Service
public class HelloService {
    public void hello() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();
        System.out.println(details);
    }
}

The reason why this acquisition process is done in service is to demonstratewhenever and wherever possibleThis feature. Then we call this method in controller. When we access the interface, we can see the following logs:

[email protected]: RemoteIpAddress: 127.0.0.1; SessionId: 303C7F254DF8B86667A2B20AA0667160

As you can see, the user’s IP address and sessionid are given. These two properties have corresponding get methods in webauthenticationdetails, and the property values can also be obtained separately.

3. Customization

Of course, webauthentication details can also be customized, because it only provides IP and sessionid information by default. If we want to save more information about HTTP requests, we can customize webauthentication details.

If we want to customize webauthentication details, we need to redefine it along with webauthentication details source.

Combined with the verification code login in the last article, I will show you an example of user-defined web authentication details.

In the last article, we judged the captcha in the myauthenticationprovider class. Let’s review the code in the previous article

public class MyAuthenticationProvider extends DaoAuthenticationProvider {

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String code = req.getParameter("code");
        String verify_code = (String) req.getSession().getAttribute("verify_code");
        if (code == null || verify_code == null || !code.equals(verify_code)) {
            Throw new authenticationserviceexception;
        }
        super.additionalAuthenticationChecks(userDetails, authentication);
    }
}

However, this verification operation can also be done in the user-defined webauthentication details. We define the following two classes:

public class MyWebAuthenticationDetails extends WebAuthenticationDetails {

    private boolean isPassed;

    public MyWebAuthenticationDetails(HttpServletRequest req) {
        super(req);
        String code = req.getParameter("code");
        String verify_code = (String) req.getSession().getAttribute("verify_code");
        if (code != null && verify_code != null && code.equals(verify_code)) {
            isPassed = true;
        }
    }

    public boolean isPassed() {
        return isPassed;
    }
}
@Component
public class MyWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest,MyWebAuthenticationDetails> {
    @Override
    public MyWebAuthenticationDetails buildDetails(HttpServletRequest context) {
        return new MyWebAuthenticationDetails(context);
    }
}

First of all, we define mywebauthenticationdetails. Since the HttpServletRequest object is provided in its construction method, we can directly use this object to judge the verification code and submit the judgment result to ispassed variable for saving.If we want to extend the properties, we just need to define more properties in mywebauthentication details, and then extract and set them to the corresponding properties from HttpServletRequest. In this way, we can obtain these properties anytime and anywhere after successful login.

Finally, mywebauthenticationdetails is constructed in mywebauthenticationdetails source and returned.

After the definition is completed, we can call it directly in myauthenticationprovider:

public class MyAuthenticationProvider extends DaoAuthenticationProvider {

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        if (!((MyWebAuthenticationDetails) authentication.getDetails()).isPassed()) {
            Throw new authenticationserviceexception;
        }
        super.additionalAuthenticationChecks(userDetails, authentication);
    }
}

Get details directly from authentication and call ispassed method. If there is a problem, throw an exception.

The last problem is how to replace the default webauthentication detailssource with the user-defined mywebauthentication detailssource. It is very simple. We only need to define it in securityconfig

@Autowired
MyWebAuthenticationDetailsSource myWebAuthenticationDetailsSource;
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            ...
            .and()
            .formLogin()
            .authenticationDetailsSource(myWebAuthenticationDetailsSource)
            ...
}

Inject mywebauthenticationdetailssource into securityconfig and configure authenticationdetailssource in formlogin to successfully use our custom webauthentication details.

In this way, after the customization is completed, the original functions in webauthentication details are still retained, that is, we can continue to obtain user IP and sessionid information by using the old method, as follows:

@Service
public class HelloService {
    public void hello() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        MyWebAuthenticationDetails details = (MyWebAuthenticationDetails) authentication.getDetails();
        System.out.println(details);
    }
}

When the type is forced to be changed here, it can be changed to mywebauthentication details.

This case can be downloaded from GitHub https://github.com/lenve/spring-security-samples

OK, I don’t know if my friends got there? If you get there, remember to watch and encourage SongGe

Recommended Today

Introduction to pyzmq

Introduction to pyzmq ZMQ (hereinafter referred to as ZMQ) is a simple and easy-to-use transport layer, like a socket library framework, it makes socket programming more simple, concise and higher performance. Is a message processing queue library that can be flexibly scaled between multiple threads, kernel and mainframe. ZMQ’s clear goal is to “become part […]