abstractuserdetailsauthenticationprovider.java
来自「acegi构造安全的java系统」· Java 代码 · 共 320 行 · 第 1/2 页
JAVA
320 行
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited * * 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 * * http://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.acegisecurity.providers.dao;import org.acegisecurity.AccountExpiredException;import org.acegisecurity.AcegiMessageSource;import org.acegisecurity.Authentication;import org.acegisecurity.AuthenticationException;import org.acegisecurity.BadCredentialsException;import org.acegisecurity.CredentialsExpiredException;import org.acegisecurity.DisabledException;import org.acegisecurity.LockedException;import org.acegisecurity.providers.AuthenticationProvider;import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;import org.acegisecurity.providers.dao.cache.NullUserCache;import org.acegisecurity.userdetails.UserDetails;import org.acegisecurity.userdetails.UserDetailsService;import org.acegisecurity.userdetails.UsernameNotFoundException;import org.acegisecurity.userdetails.UserDetailsChecker;import org.springframework.beans.factory.InitializingBean;import org.springframework.context.MessageSource;import org.springframework.context.MessageSourceAware;import org.springframework.context.support.MessageSourceAccessor;import org.springframework.util.Assert;/** * A base {@link AuthenticationProvider} that allows subclasses to override and work with {@link * org.acegisecurity.userdetails.UserDetails} objects. The class is designed to respond to {@link * UsernamePasswordAuthenticationToken} authentication requests. * * <p> * Upon successful validation, a <code>UsernamePasswordAuthenticationToken</code> will be created and returned to the * caller. The token will include as its principal either a <code>String</code> representation of the username, or the * {@link UserDetails} that was returned from the authentication repository. Using <code>String</code> is appropriate * if a container adapter is being used, as it expects <code>String</code> representations of the username. * Using <code>UserDetails</code> is appropriate if you require access to additional properties of the authenticated * user, such as email addresses, human-friendly names etc. As container adapters are not recommended to be used, * and <code>UserDetails</code> implementations provide additional flexibility, by default a <code>UserDetails</code> * is returned. To override this * default, set the {@link #setForcePrincipalAsString} to <code>true</code>. * </p> * <p>Caching is handled via the <code>UserDetails</code> object being placed in the {@link UserCache}. This * ensures that subsequent requests with the same username can be validated without needing to query the {@link * UserDetailsService}. It should be noted that if a user appears to present an incorrect password, the {@link * UserDetailsService} will be queried to confirm the most up-to-date password was used for comparison.</p> * * @author Ben Alex * @version $Id: AbstractUserDetailsAuthenticationProvider.java 2654 2008-02-18 20:44:09Z luke_t $ */public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware { //~ Instance fields ================================================================================================ protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor(); private UserCache userCache = new NullUserCache(); private boolean forcePrincipalAsString = false; protected boolean hideUserNotFoundExceptions = true; private UserDetailsChecker preAuthenticationChecks = new DefaultPreAuthenticationChecks(); private UserDetailsChecker postAuthenticationChecks = new DefaultPostAuthenticationChecks(); //~ Methods ======================================================================================================== /** * Allows subclasses to perform any additional checks of a returned (or cached) <code>UserDetails</code> * for a given authentication request. Generally a subclass will at least compare the {@link * Authentication#getCredentials()} with a {@link UserDetails#getPassword()}. If custom logic is needed to compare * additional properties of <code>UserDetails</code> and/or <code>UsernamePasswordAuthenticationToken</code>, * these should also appear in this method. * * @param userDetails as retrieved from the {@link #retrieveUser(String, UsernamePasswordAuthenticationToken)} or * <code>UserCache</code> * @param authentication the current request that needs to be authenticated * * @throws AuthenticationException AuthenticationException if the credentials could not be validated (generally a * <code>BadCredentialsException</code>, an <code>AuthenticationServiceException</code>) */ protected abstract void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException; public final void afterPropertiesSet() throws Exception { Assert.notNull(this.userCache, "A user cache must be set"); Assert.notNull(this.messages, "A message source must be set"); doAfterPropertiesSet(); } public Authentication authenticate(Authentication authentication) throws AuthenticationException { Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication, messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports", "Only UsernamePasswordAuthenticationToken is supported")); // Determine username String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName(); boolean cacheWasUsed = true; UserDetails user = this.userCache.getUserFromCache(username); if (user == null) { cacheWasUsed = false; try { user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); } catch (UsernameNotFoundException notFound) { if (hideUserNotFoundExceptions) { throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } else { throw notFound; } } Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract"); } preAuthenticationChecks.check(user); // This check must come here, as we don't want to tell users // about account status unless they presented the correct credentials try { additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication); } catch (AuthenticationException exception) { if (cacheWasUsed) { // There was a problem, so try again after checking // we're using latest data (ie not from the cache) cacheWasUsed = false; user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication); } else { throw exception; } } postAuthenticationChecks.check(user); if (!cacheWasUsed) { this.userCache.putUserInCache(user); } Object principalToReturn = user;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?