How to quickly view the login IP address and other information in Spring Security? One move

I've 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 by custom filters. I suggest you read it and understand the authentication logic in Spring Security by the way.

No nonsense. Let's look at today's article.

1.Authentication

I've talked with you many times in front of the Authentication interface, and I'd like to talk again today. In addition, you should pay attention to: breaking through the experience of high paid Java architecture projects is always the core. If you don't have the latest Java architecture practical course and the big factory 30k + interview book, you can go to the small-scale Java architecture learning. Skirt: seven umbrella bar zero and clothing Zero umbrella (Digital homophony) can be found under the conversion. Many new Java architecture project courses can also be exchanged with the old driver!  

The Authentication interface is used to store our login user information. In fact, it further encapsulates the principal (java.security.Principal).

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;
}
Copy code

The interface is explained as follows:

  1. The getAuthorities method is used to get the user's permissions.
  2. The getCredentials method is used to obtain user credentials, which is generally called passwords.
  3. The getDetails method is used to get the details carried by the user, which may be the current request or something like that.
  4. The getPrincipal method is used to get the current user. It may be a user name or a user object.
  5. Is the current user authenticated.

Here is a more 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 identity authentication, such as IP address, certificate information, etc.

In fact, by default, the IP address and sessionId of the user's login are stored here. Let's look at the source code.

2. Source code analysis

SongGe's spring security series has been written to Article 12. After reading the previous articles, I believe you have understood that a filter that users must pass for login is UsernamePasswordAuthenticationFilter. In the attemptAuthentication method of this class, extract the request parameters. In the attemptAuthentication method, you will call a method, setDetails.

Let's look at the setDetails method:

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

UsernamePasswordAuthenticationToken is the specific implementation of Authentication, so here is actually setting details. As for the value of details, it is built by authenticationDetailsSource. Let's look at the following:

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
}
Copy code

By default, WebAuthenticationDetailsSource is used to build WebAuthenticationDetails, and the result is set to the details property of Authentication. As for the properties defined in WebAuthenticationDetails, you can basically see that this is to save the user's login address and sessionId.

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

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

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

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

WebAuthenticationDetails@fffc7f0c: RemoteIpAddress: 127.0.0.1; SessionId: 303C7F254DF8B86667A2B20AA0667160
Copy code

As you can see, the IP address and SessionId of the user are given. These two properties have corresponding get methods in WebAuthenticationDetails, and the property values can also be obtained separately.

3. Customization

Of course, WebAuthenticationDetails 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 WebAuthenticationDetails.

If we want to customize web authentication details, we need to redefine it together with web authentication details source.

Combination Last article I'll show you an example of a custom web authentication details.

Last article We use the MyAuthenticationProvider class to determine the verification code. Let's review it Last article Code:

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("Verification code error");
        }
        super.additionalAuthenticationChecks(userDetails, authentication);
    }
}
Copy code

However, this verification operation can also be done in the user-defined WebAuthenticationDetails. 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);
    }
}
Copy code

First of all, we define MyWebAuthenticationDetails. Because the HttpServletRequest object is just provided in its construction method, we can directly use the object to judge the verification code and give the result to isPassed variable to save. If we want to extend properties, we only need to define more properties in MyWebAuthenticationDetails, and then extract them from HttpServletRequest and set them to the corresponding properties, so that we can get these properties anytime, anywhere after the login is successful.

Finally, MyWebAuthenticationDetails is constructed in MyWebAuthenticationDetails source and returned.

After the definition, we can call 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("Verification code error");
        }
        super.additionalAuthenticationChecks(userDetails, authentication);
    }
}
Copy code

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 WebAuthenticationDetailsSource with the customized MyWebAuthenticationDetailsSource. It's very simple. We just need to define it in SecurityConfig:

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

Inject MyWebAuthenticationDetailsSource into SecurityConfig and configure authenticationDetailsSource in formLogin to successfully use our customized WebAuthenticationDetails.

After the customization is completed, the original functions in WebAuthenticationDetails remain, that is to say, we can use the old methods to continue to obtain user IP and sessionId information, as follows:

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

In this case, when the type is forced to change to MyWebAuthenticationDetails.

Finally, note: breaking through the experience of high paid Java architecture projects is always the core. If you don't have the latest Java architecture practice course and the big factory 30k + interview book, you can go to the small-scale Java architecture learning. Skirt: you can find it under the transformation of seven bar umbrella and zero clothing umbrella (Digital homophony). There are many new Java architecture project tutorials in it, and you can also exchange with the old driver for advice!
The text and pictures of this article come from the Internet and my own ideas. They are only for learning and communication. They have no commercial use. The copyright belongs to the original author. If you have any questions, please contact us in time for handling

Tags: Java Spring Session

Posted on Thu, 07 May 2020 01:08:54 -0700 by Niruth