替换UsernamePasswordAuthenticationFilter类
1. pom.xml
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> </dependency><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>unpack</id> <phase>generate-sources</phase> <goals> <goal>unpack</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <overWrite>false</overWrite> <outputDirectory>${project.build.directory}/classes</outputDirectory> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin></pre><p><br/></p><p>2.重写<font color="#ff0000">FormLoginConfigurer</font>类,替换其中的<font color="#ff0000">UsernamePasswordAuthenticationFilter</font>为<font color="#ff0000">UsernamePasswordAuthenticationWithLogFilter</font>类</p><p><br/></p><pre>package org.springframework.security.config.annotation.web.configurers;
import com.sparkmap.platform.security.filter.UsernamePasswordAuthenticationWithLogFilter;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.ForwardAuthenticationFailureHandler;
import org.springframework.security.web.authentication.ForwardAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
-
Adds form based authentication. All attributes have reasonable defaults making all
-
parameters are optional. If no {@link #loginPage(String)} is specified, a default login
-
page will be generated by the framework.
-
<h2>Security Filters</h2>
-
The following Filters are populated
-
<ul>
-
<li>{@link UsernamePasswordAuthenticationFilter}</li>
-
</ul>
-
<h2>Shared Objects Created</h2>
-
The following shared objects are populated
-
<ul>
-
<li>{@link AuthenticationEntryPoint}</li>
-
</ul>
-
<h2>Shared Objects Used</h2>
-
The following shared objects are used:
-
<ul>
-
<li>{@link org.springframework.security.authentication.AuthenticationManager}</li>
-
<li>{@link RememberMeServices} - is optionally used. See {@link RememberMeConfigurer}
-
</li>
-
<li>{@link SessionAuthenticationStrategy} - is optionally used. See
-
{@link SessionManagementConfigurer}</li>
-
<li>{@link DefaultLoginPageGeneratingFilter} - if present will be populated with
-
information from the configuration</li>
-
</ul>
-
@author Rob Winch
-
@author Shazin Sadakath
-
@since 3.2
*/
public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {/**
- Creates a new instance
- @see HttpSecurity#formLogin()
*/
public FormLoginConfigurer() {
super(new UsernamePasswordAuthenticationWithLogFilter(), null); // 改为自己写的类
usernameParameter(“username”);
passwordParameter(“password”);
}
/**
- <p>
- Specifies the URL to send users to if login is required. If used with
- {@link EnableWebSecurity} a default login page will be generated when this
- attribute is not specified.
- </p>
- <p>
- If a URL is specified or this is not being used in conjunction with
- {@link EnableWebSecurity}, users are required to process the specified URL to
- generate a login page. In general, the login page should create a form that submits
- a request with the following requirements to work with
- {@link UsernamePasswordAuthenticationFilter}:
- </p>
- <ul>
- <li>It must be an HTTP POST</li>
- <li>It must be submitted to {@link #loginProcessingUrl(String)}</li>
- <li>It should include the username as an HTTP parameter by the name of
- {@link #usernameParameter(String)}</li>
- <li>It should include the password as an HTTP parameter by the name of
- {@link #passwordParameter(String)}</li>
- </ul>
- <h2>Example login.jsp</h2>
- Login pages can be rendered with any technology you choose so long as the rules
- above are followed. Below is an example login.jsp that can be used as a quick start
- when using JSP’s or as a baseline to translate into another view technology.
- <pre>
- <!-- loginProcessingUrl should correspond to FormLoginConfigurer#loginProcessingUrl. Don’t forget to perform a POST -->
- <c:url value=“/login” var=“loginProcessingUrl”/>
- <form action=“${loginProcessingUrl}” method=“post”>
- <fieldset>
-
&lt;legend&gt;Please Login&lt;/legend&gt;
-
&lt;!-- use param.error assuming FormLoginConfigurer#failureUrl contains the query parameter error --&gt;
-
&lt;c:if test="${param.error != null}"&gt;
-
&lt;div&gt;
-
Failed to login.
-
&lt;c:if test="${SPRING_SECURITY_LAST_EXCEPTION != null}"&gt;
-
Reason: &lt;c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" /&gt;
-
&lt;/c:if&gt;
-
&lt;/div&gt;
-
&lt;/c:if&gt;
-
&lt;!-- the configured LogoutConfigurer#logoutSuccessUrl is /login?logout and contains the query param logout --&gt;
-
&lt;c:if test="${param.logout != null}"&gt;
-
&lt;div&gt;
-
You have been logged out.
-
&lt;/div&gt;
-
&lt;/c:if&gt;
-
&lt;p&gt;
-
&lt;label for="username"&gt;Username&lt;/label&gt;
-
&lt;input type="text" id="username" name="username"/&gt;
-
&lt;/p&gt;
-
&lt;p&gt;
-
&lt;label for="password"&gt;Password&lt;/label&gt;
-
&lt;input type="password" id="password" name="password"/&gt;
-
&lt;/p&gt;
-
&lt;!-- if using RememberMeConfigurer make sure remember-me matches RememberMeConfigurer#rememberMeParameter --&gt;
-
&lt;p&gt;
-
&lt;label for="remember-me"&gt;Remember Me?&lt;/label&gt;
-
&lt;input type="checkbox" id="remember-me" name="remember-me"/&gt;
-
&lt;/p&gt;
-
&lt;div&gt;
-
&lt;button type="submit" class="btn"&gt;Log in&lt;/button&gt;
-
&lt;/div&gt;
- </fieldset>
- </form>
- </pre>
- <h2>Impact on other defaults</h2>
- Updating this value, also impacts a number of other default values. For example,
- the following are the default values when only formLogin() was specified.
- <ul>
- <li>/login GET - the login form</li>
- <li>/login POST - process the credentials and if valid authenticate the user</li>
- <li>/login?error GET - redirect here for failed authentication attempts</li>
- <li>/login?logout GET - redirect here after successfully logging out</li>
- </ul>
- If “/authenticate” was passed to this method it update the defaults as shown below:
- <ul>
- <li>/authenticate GET - the login form</li>
- <li>/authenticate POST - process the credentials and if valid authenticate the user
- </li>
- <li>/authenticate?error GET - redirect here for failed authentication attempts</li>
- <li>/authenticate?logout GET - redirect here after successfully logging out</li>
- </ul>
- @param loginPage the login page to redirect to if authentication is required (i.e.
- “/login”)
- @return the {@link FormLoginConfigurer} for additional customization
*/
@Override
public FormLoginConfigurer<H> loginPage(String loginPage) {
return super.loginPage(loginPage);
}
/**
- The HTTP parameter to look for the username when performing authentication. Default
- is “username”.
- @param usernameParameter the HTTP parameter to look for the username when
- performing authentication
- @return the {@link FormLoginConfigurer} for additional customization
*/
public FormLoginConfigurer<H> usernameParameter(String usernameParameter) {
getAuthenticationFilter().setUsernameParameter(usernameParameter);
return this;
}
/**
- The HTTP parameter to look for the password when performing authentication. Default
- is “password”.
- @param passwordParameter the HTTP parameter to look for the password when
- performing authentication
- @return the {@link FormLoginConfigurer} for additional customization
*/
public FormLoginConfigurer<H> passwordParameter(String passwordParameter) {
getAuthenticationFilter().setPasswordParameter(passwordParameter);
return this;
}
/**
- Forward Authentication Failure Handler
- @param forwardUrl the target URL in case of failure
- @return the {@link FormLoginConfigurer} for additional customization
*/
public FormLoginConfigurer<H> failureForwardUrl(String forwardUrl) {
failureHandler(new ForwardAuthenticationFailureHandler(forwardUrl));
return this;
}
/**
- Forward Authentication Success Handler
- @param forwardUrl the target URL in case of success
- @return the {@link FormLoginConfigurer} for additional customization
*/
public FormLoginConfigurer<H> successForwardUrl(String forwardUrl) {
successHandler(new ForwardAuthenticationSuccessHandler(forwardUrl));
return this;
}
@Override
public void init(H http) throws Exception {
super.init(http);
initDefaultLoginFilter(http);
}@Override
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
return new AntPathRequestMatcher(loginProcessingUrl, “POST”);
}/**
- Gets the HTTP parameter that is used to submit the username.
- @return the HTTP parameter that is used to submit the username
*/
private String getUsernameParameter() {
return getAuthenticationFilter().getUsernameParameter();
}
/**
- Gets the HTTP parameter that is used to submit the password.
- @return the HTTP parameter that is used to submit the password
*/
private String getPasswordParameter() {
return getAuthenticationFilter().getPasswordParameter();
}
/**
- If available, initializes the {@link DefaultLoginPageGeneratingFilter} shared
- object.
- @param http the {@link HttpSecurityBuilder} to use
*/
private void initDefaultLoginFilter(H http) {
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http
.getSharedObject(DefaultLoginPageGeneratingFilter.class);
if (loginPageGeneratingFilter != null && !isCustomLoginPage()) {
loginPageGeneratingFilter.setFormLoginEnabled(true);
loginPageGeneratingFilter.setUsernameParameter(getUsernameParameter());
loginPageGeneratingFilter.setPasswordParameter(getPasswordParameter());
loginPageGeneratingFilter.setLoginPageUrl(getLoginPage());
loginPageGeneratingFilter.setFailureUrl(getFailureUrl());
loginPageGeneratingFilter.setAuthenticationUrl(getLoginProcessingUrl());
}
}
}
3.实现自己写的UsernamePasswordAuthenticationWithLogFilter类
package com.ruitu.platform.security.filter;
import java.io.IOException;
import java.util.Date;
import com.alibaba.fastjson2.JSONObject;
import com.ruitu.platform.security.domain.LoginLog;
import com.ruitu.platform.security.domain.SecurityUser;
import com.ruitu.platform.security.enumeration.LoginStatus;
import com.ruitu.platform.security.service.LoginLogService;
import com.ruitu.platform.utils.ExceptionUtil;
import com.ruitu.platform.utils.RequestInfoUtil;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
- 扩展UsernamePasswordAuthenticationFilter类,实现日志功能
*/
public class UsernamePasswordAuthenticationWithLogFilter extends UsernamePasswordAuthenticationFilter {
private LoginLogService loginLogService = null;
private ThreadLocal<Long> currentTime = new ThreadLocal<>();
public LoginLogService getLoginLogService() {
return loginLogService;
}
public void setLoginLogService(LoginLogService loginLogService) {
this.loginLogService = loginLogService;
}
public UsernamePasswordAuthenticationWithLogFilter() {
super();
}
public UsernamePasswordAuthenticationWithLogFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
public UsernamePasswordAuthenticationWithLogFilter(AuthenticationManager authenticationManager, LoginLogService loginLogService) {
super(authenticationManager);
this.loginLogService = loginLogService;
}
public UsernamePasswordAuthenticationWithLogFilter(LoginLogService loginLogService) {
this.loginLogService = loginLogService;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
currentTime.set(System.currentTimeMillis());// 记录方法的执行时间
return super.attemptAuthentication(request, response);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, authResult);
Date startTime = new Date();
startTime.setTime(currentTime.get());
currentTime.remove();
//
if (loginLogService != null) {
SecurityUser securityUser = (SecurityUser) authResult.getPrincipal();
String username = securityUser.getUsername();
String password = obtainPassword(request);
LoginLog loginLog = new LoginLog();
loginLog.setStatus(LoginStatus.SUCCESS.name());
loginLog.setResponseResult(JSONObject.toJSONString(authResult));
loginLog.setUsername(username);
loginLog.setPassword(password);
loginLog.setBrowser(RequestInfoUtil.getBrowser(request));
loginLog.setIp(RequestInfoUtil.getIp(request));
loginLog.setRequestTime(startTime);
loginLog.setCreateTime(new Date());
loginLog.setResponseTime(loginLog.getCreateTime());
loginLogService.recordLoginLog(loginLog);
} else {
System.out.println("-----------------------------------------: successfulAuthentication ");
}
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
super.unsuccessfulAuthentication(request, response, failed);
Date startTime = new Date();
startTime.setTime(currentTime.get());
currentTime.remove();
if (loginLogService != null) {
String username = obtainUsername(request);
username = (username != null) ? username.trim() : “”;
String password = obtainPassword(request);
LoginLog loginLog = new LoginLog();
loginLog.setStatus(LoginStatus.FAIL.name());
loginLog.setExceptionDetail(ExceptionUtil.getStackMsg(failed).substring(255));
loginLog.setUsername(username);
loginLog.setPassword(password);
loginLog.setBrowser(RequestInfoUtil.getBrowser(request));
loginLog.setIp(RequestInfoUtil.getIp(request));
loginLog.setRequestTime(startTime);
loginLog.setCreateTime(new Date());
loginLog.setResponseTime(loginLog.getCreateTime());
loginLogService.recordLoginLog(loginLog);
} else {
System.out.println("-----------------------------------------: unsuccessfulAuthentication ");
}
}
}
-----
如何记录SpringSecurity6.1中用户登录行为