spring security HttpServlet3RequestFactory 源码
spring security HttpServlet3RequestFactory 代码
文件路径:/web/src/main/java/org/springframework/security/web/servletapi/HttpServlet3RequestFactory.java
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.servletapi;
import java.io.IOException;
import java.util.List;
import jakarta.servlet.AsyncContext;
import jakarta.servlet.AsyncListener;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.concurrent.DelegatingSecurityContextRunnable;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* Provides integration with the Servlet 3 APIs. The additional methods that are
* integrated with can be found below:
*
* <ul>
* <li>{@link HttpServletRequest#authenticate(HttpServletResponse)} - Allows the user to
* determine if they are authenticated and if not send the user to the login page. See
* {@link #setAuthenticationEntryPoint(AuthenticationEntryPoint)}.</li>
* <li>{@link HttpServletRequest#login(String, String)} - Allows the user to authenticate
* using the {@link AuthenticationManager}. See
* {@link #setAuthenticationManager(AuthenticationManager)}.</li>
* <li>{@link HttpServletRequest#logout()} - Allows the user to logout using the
* {@link LogoutHandler}s configured in Spring Security. See
* {@link #setLogoutHandlers(List)}.</li>
* <li>{@link AsyncContext#start(Runnable)} - Automatically copy the
* {@link SecurityContext} from the {@link SecurityContextHolder} found on the Thread that
* invoked {@link AsyncContext#start(Runnable)} to the Thread that processes the
* {@link Runnable}.</li>
* </ul>
*
* @author Rob Winch
* @see SecurityContextHolderAwareRequestFilter
* @see Servlet3SecurityContextHolderAwareRequestWrapper
* @see SecurityContextAsyncContext
*/
final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
private Log logger = LogFactory.getLog(getClass());
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private final String rolePrefix;
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private final AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
private AuthenticationEntryPoint authenticationEntryPoint;
private AuthenticationManager authenticationManager;
private List<LogoutHandler> logoutHandlers;
HttpServlet3RequestFactory(String rolePrefix) {
this.rolePrefix = rolePrefix;
}
/**
* <p>
* Sets the {@link AuthenticationEntryPoint} used when integrating
* {@link HttpServletRequest} with Servlet 3 APIs. Specifically, it will be used when
* {@link HttpServletRequest#authenticate(HttpServletResponse)} is called and the user
* is not authenticated.
* </p>
* <p>
* If the value is null (default), then the default container behavior will be be
* retained when invoking {@link HttpServletRequest#authenticate(HttpServletResponse)}
* .
* </p>
* @param authenticationEntryPoint the {@link AuthenticationEntryPoint} to use when
* invoking {@link HttpServletRequest#authenticate(HttpServletResponse)} if the user
* is not authenticated.
*/
void setAuthenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
this.authenticationEntryPoint = authenticationEntryPoint;
}
/**
* <p>
* Sets the {@link AuthenticationManager} used when integrating
* {@link HttpServletRequest} with Servlet 3 APIs. Specifically, it will be used when
* {@link HttpServletRequest#login(String, String)} is invoked to determine if the
* user is authenticated.
* </p>
* <p>
* If the value is null (default), then the default container behavior will be
* retained when invoking {@link HttpServletRequest#login(String, String)}.
* </p>
* @param authenticationManager the {@link AuthenticationManager} to use when invoking
* {@link HttpServletRequest#login(String, String)}
*/
void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
/**
* <p>
* Sets the {@link LogoutHandler}s used when integrating with
* {@link HttpServletRequest} with Servlet 3 APIs. Specifically it will be used when
* {@link HttpServletRequest#logout()} is invoked in order to log the user out. So
* long as the {@link LogoutHandler}s do not commit the {@link HttpServletResponse}
* (expected), then the user is in charge of handling the response.
* </p>
* <p>
* If the value is null (default), the default container behavior will be retained
* when invoking {@link HttpServletRequest#logout()}.
* </p>
* @param logoutHandlers the {@code List<LogoutHandler>}s when invoking
* {@link HttpServletRequest#logout()}.
*/
void setLogoutHandlers(List<LogoutHandler> logoutHandlers) {
this.logoutHandlers = logoutHandlers;
}
/**
* Sets the {@link AuthenticationTrustResolver} to be used. The default is
* {@link AuthenticationTrustResolverImpl}.
* @param trustResolver the {@link AuthenticationTrustResolver} to use. Cannot be
* null.
*/
void setTrustResolver(AuthenticationTrustResolver trustResolver) {
Assert.notNull(trustResolver, "trustResolver cannot be null");
this.trustResolver = trustResolver;
}
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
@Override
public HttpServletRequest create(HttpServletRequest request, HttpServletResponse response) {
Servlet3SecurityContextHolderAwareRequestWrapper wrapper = new Servlet3SecurityContextHolderAwareRequestWrapper(
request, this.rolePrefix, response);
wrapper.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
return wrapper;
}
private class Servlet3SecurityContextHolderAwareRequestWrapper extends SecurityContextHolderAwareRequestWrapper {
private final HttpServletResponse response;
Servlet3SecurityContextHolderAwareRequestWrapper(HttpServletRequest request, String rolePrefix,
HttpServletResponse response) {
super(request, HttpServlet3RequestFactory.this.trustResolver, rolePrefix);
this.response = response;
}
@Override
public AsyncContext getAsyncContext() {
AsyncContext asyncContext = super.getAsyncContext();
if (asyncContext == null) {
return null;
}
return new SecurityContextAsyncContext(asyncContext);
}
@Override
public AsyncContext startAsync() {
AsyncContext startAsync = super.startAsync();
return new SecurityContextAsyncContext(startAsync);
}
@Override
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
throws IllegalStateException {
AsyncContext startAsync = super.startAsync(servletRequest, servletResponse);
return new SecurityContextAsyncContext(startAsync);
}
@Override
public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
AuthenticationEntryPoint entryPoint = HttpServlet3RequestFactory.this.authenticationEntryPoint;
if (entryPoint == null) {
HttpServlet3RequestFactory.this.logger.debug(
"authenticationEntryPoint is null, so allowing original HttpServletRequest to handle authenticate");
return super.authenticate(response);
}
if (isAuthenticated()) {
return true;
}
entryPoint.commence(this, response,
new AuthenticationCredentialsNotFoundException("User is not Authenticated"));
return false;
}
@Override
public void login(String username, String password) throws ServletException {
if (isAuthenticated()) {
throw new ServletException("Cannot perform login for '" + username + "' already authenticated as '"
+ getRemoteUser() + "'");
}
AuthenticationManager authManager = HttpServlet3RequestFactory.this.authenticationManager;
if (authManager == null) {
HttpServlet3RequestFactory.this.logger.debug(
"authenticationManager is null, so allowing original HttpServletRequest to handle login");
super.login(username, password);
return;
}
Authentication authentication = getAuthentication(authManager, username, password);
SecurityContext context = HttpServlet3RequestFactory.this.securityContextHolderStrategy
.createEmptyContext();
context.setAuthentication(authentication);
HttpServlet3RequestFactory.this.securityContextHolderStrategy.setContext(context);
}
private Authentication getAuthentication(AuthenticationManager authManager, String username, String password)
throws ServletException {
try {
UsernamePasswordAuthenticationToken authentication = UsernamePasswordAuthenticationToken
.unauthenticated(username, password);
Object details = HttpServlet3RequestFactory.this.authenticationDetailsSource.buildDetails(this);
authentication.setDetails(details);
return authManager.authenticate(authentication);
}
catch (AuthenticationException ex) {
HttpServlet3RequestFactory.this.securityContextHolderStrategy.clearContext();
throw new ServletException(ex.getMessage(), ex);
}
}
@Override
public void logout() throws ServletException {
List<LogoutHandler> handlers = HttpServlet3RequestFactory.this.logoutHandlers;
if (CollectionUtils.isEmpty(handlers)) {
HttpServlet3RequestFactory.this.logger
.debug("logoutHandlers is null, so allowing original HttpServletRequest to handle logout");
super.logout();
return;
}
Authentication authentication = HttpServlet3RequestFactory.this.securityContextHolderStrategy.getContext()
.getAuthentication();
for (LogoutHandler handler : handlers) {
handler.logout(this, this.response, authentication);
}
}
private boolean isAuthenticated() {
return getUserPrincipal() != null;
}
}
private static class SecurityContextAsyncContext implements AsyncContext {
private final AsyncContext asyncContext;
SecurityContextAsyncContext(AsyncContext asyncContext) {
this.asyncContext = asyncContext;
}
@Override
public ServletRequest getRequest() {
return this.asyncContext.getRequest();
}
@Override
public ServletResponse getResponse() {
return this.asyncContext.getResponse();
}
@Override
public boolean hasOriginalRequestAndResponse() {
return this.asyncContext.hasOriginalRequestAndResponse();
}
@Override
public void dispatch() {
this.asyncContext.dispatch();
}
@Override
public void dispatch(String path) {
this.asyncContext.dispatch(path);
}
@Override
public void dispatch(ServletContext context, String path) {
this.asyncContext.dispatch(context, path);
}
@Override
public void complete() {
this.asyncContext.complete();
}
@Override
public void start(Runnable run) {
this.asyncContext.start(new DelegatingSecurityContextRunnable(run));
}
@Override
public void addListener(AsyncListener listener) {
this.asyncContext.addListener(listener);
}
@Override
public void addListener(AsyncListener listener, ServletRequest request, ServletResponse response) {
this.asyncContext.addListener(listener, request, response);
}
@Override
public <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException {
return this.asyncContext.createListener(clazz);
}
@Override
public long getTimeout() {
return this.asyncContext.getTimeout();
}
@Override
public void setTimeout(long timeout) {
this.asyncContext.setTimeout(timeout);
}
}
}
相关信息
相关文章
spring security HttpServletRequestFactory 源码
spring security SecurityContextHolderAwareRequestFilter 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦