首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件开发 >

SpringSecurity 源码分析1

2012-07-01 
SpringSecurity 源码分析一???? 通过SecurityContextHolder.getContext()获得SecurityContext?? 总接口Sec

SpringSecurity 源码分析一

?

??? 通过SecurityContextHolder.getContext()获得SecurityContext
?? 总接口SecurityContextHolderStrategy

SpringSecurity 源码分析1

private static void initialize() {
??????? if ((strategyName == null) || "".equals(strategyName)) {
??????????? // Set default
??????????? strategyName = MODE_THREADLOCAL;
??????? }

??????? if (strategyName.equals(MODE_THREADLOCAL)) {
??????????? strategy = new ThreadLocalSecurityContextHolderStrategy();
??????? } else if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
??????????? strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
??????? } else if (strategyName.equals(MODE_GLOBAL)) {
??????????? strategy = new GlobalSecurityContextHolderStrategy();
??????? } else {
??????????? // Try to load a custom strategy
??????????? try {
??????????????? Class clazz = Class.forName(strategyName);
??????????????? Constructor customStrategy = clazz.getConstructor(new Class[] {});
??????????????? strategy = (SecurityContextHolderStrategy) customStrategy.newInstance(new Object[] {});
??????????? } catch (Exception ex) {
??????????????? ReflectionUtils.handleReflectionException(ex);
??????????? }
??????? }

??????? initializeCount++;
??? }???????

当SecurityContextHolder初始化的时候。判断调用哪个SecurityContextHolderStrategy的实现类

Authentication auth = SecurityContextHolder.getContext().getAuthentication();

让后通过 SecurityContext 接口 实现类 SecurityContextImpl? 获得????getAuthentication()的到Authentication 对象,Authentication 对象中装了很多用户信息



SpringSecurity 源码分析1
?
?
SpringSecurity 源码分析1
?

Authentication 主要是包括一些用户认证的信息,比如权限啊。名字啊什么的。。。

Springsecurity 主要是 认证+授权+filter

认证 分 证管理器+认证者。

认证管理器(org.springframework.security.AuthenticationManager接口


SpringSecurity 源码分析1
?

?

?

?

public class ProviderManager extends AbstractAuthenticationManager implements InitializingBean, MessageSourceAware,        ApplicationEventPublisherAware  {    //~ Static fields/initializers =====================================================================================    private static final Log logger = LogFactory.getLog(ProviderManager.class);    private static final Properties DEFAULT_EXCEPTION_MAPPINGS = new Properties();    //~ Instance fields ================================================================================================    private ApplicationEventPublisher applicationEventPublisher;    private ConcurrentSessionController sessionController = new NullConcurrentSessionController();    private List providers;    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();    private Properties exceptionMappings = new Properties();    private Properties additionalExceptionMappings = new Properties();
?<!-- 认证管理器(org.springframework.security.AuthenticationManager接口) org.springframework.security.providers.ProviderManager是认证管理器的一个实现, ProviderManager通过遍历一个提供者的集合来实现身份验证, 直到某一个认证提供者能够成功地验证该用户的身份--><!-- 通过Providers提供认证者列表,如果一个认证提供者失败可以尝试另外一个认证提供者,以保证获取不同来源的身份认证,如 DaoAuthenticationProvider 从数据库中读取用户信息验证身份 AnonymousAuthenticationProvider 匿名用户身份认证 RememberMeAuthenticationProvider 已存cookie中的用户信息身份认证 其它的还有 AuthByAdapterProvider 使用容器的适配器验证身份 CasAuthenticationProvider 根据Yale中心认证服务验证身份, 用于实现单点登陆 JaasAuthenticationProvider 从JASS登陆配置中获取用户信息验证身份 RemoteAuthenticationProvider 根据远程服务验证用户身份 RunAsImplAuthenticationProvider 对身份已被管理器替换的用户进行验证 X509AuthenticationProvider 从X509认证中获取用户信息验证身份 TestingAuthenticationProvider 单元测试时使用 每个认证者会对自己指定的证明信息进行认证,如DaoAuthenticationProvider仅对UsernamePasswordAuthenticationToken这个证明信息进行认证。 总接口 AuthenticationManager 管理器 装着 很多个AuthenticationProvider 管理者--><bean id="authenticationManager" src="/img/2012/06/27/0149343531.png">
?

public interface AuthenticationProvider {    //~ Methods ========================================================================================================    /**     * Performs authentication with the same contract as {@link     * org.springframework.security.AuthenticationManager#authenticate(Authentication)}.     *     * @param authentication the authentication request object.     *     * @return a fully authenticated object including credentials. May return <code>null</code> if the     *         <code>AuthenticationProvider</code> is unable to support authentication of the passed     *         <code>Authentication</code> object. In such a case, the next <code>AuthenticationProvider</code> that     *         supports the presented <code>Authentication</code> class will be tried.     *     * @throws AuthenticationException if authentication fails.     */    Authentication authenticate(Authentication authentication)        throws AuthenticationException;

?? 有一个认证方法。不同的实现类通过这个方法来认证用户。下面来看下DaoAuthenticationProvider认证者是怎么认证用户的。

public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {    //~ Instance fields ================================================================================================    private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();    private SaltSource saltSource;    private UserDetailsService userDetailsService;    private boolean includeDetailsObject = true; protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)            throws AuthenticationException {        UserDetails loadedUser;        try {            loadedUser = this.getUserDetailsService().loadUserByUsername(username);        }        catch (DataAccessException repositoryProblem) {            throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);        }        if (loadedUser == null) {            throw new AuthenticationServiceException(                    "UserDetailsService returned null, which is an interface contract violation");        }        return loadedUser;    }

? DaoAuthenticationProvider认证者通过注入UserDetailsService来获取用户信息

<!-- 认证管理器  总接口AuthenticationProvider --><bean id="daoAuthenticationProvider" name="code"><!-- 获得userDetails的service  总接口UserDetailsService 子类--> <bean id="userDetailsService"  name="code">admin=admin,ROLE_SUPERVISORuser1=user1,ROLE_USERuser2=user2,ROLE_USERuser3=user3,disabled,ROLE_USER#scott/wombatscott=2b58af6dddbd072ed27ffc86725d7d3a,ROLE_USER

?

还可以这样:

<property name="userMap"> <value> admin=admin,ROLE_SUPERVISORuser1=user1,ROLE_USERuser2=user2,ROLE_USERuser3=user3,disabled,ROLE_USER </value> </property>

?至于org.springframework.security.userdetails.memory.InMemoryDaoImpl?怎么封装,可想而知

 */public class InMemoryDaoImpl implements UserDetailsService, InitializingBean {    public void afterPropertiesSet() throws Exception {        Assert.notNull(this.userMap,            "A list of users, passwords, enabled/disabled status and their granted authorities must be set");    }    public UserMap getUserMap() {        return userMap;    }    public UserDetails loadUserByUsername(String username)        throws UsernameNotFoundException, DataAccessException {        return userMap.getUser(username);    }    public void setUserMap(UserMap userMap) {        this.userMap = userMap;    }    public void setUserProperties(Properties props) {        UserMap userMap = new UserMap();        this.userMap = UserMapEditor.addUsersFromProperties(userMap, props);    }}

?下面来看这个service有多少中实现方式。实现类


SpringSecurity 源码分析1
?看实现类名字就可以想到。可以通过jdbc配置在数据库中,InMemoryDaoImpl配置文件中(加载到内存)

?可以把用户信息放到Ldap。?UserDetailsService 通过loadUserByUsername方法加载用户信息

?

class CachingUserDetailsService implements UserDetailsService {private UserCache userCache = new NullUserCache();private UserDetailsService delegate;CachingUserDetailsService(UserDetailsService delegate) {this.delegate = delegate;}public UserCache getUserCache() {return userCache;}public void setUserCache(UserCache userCache) {this.userCache = userCache;}public UserDetails loadUserByUsername(String username) {UserDetails user = userCache.getUserFromCache(username);if (user == null) {user = delegate.loadUserByUsername(username);}Assert.notNull(user, "UserDetailsService " + delegate + " returned null for username " + username + ". " +"This is an interface contract violation");userCache.putUserInCache(user);return user;}}

?还可以为实现类注入缓存默认是private UserCache userCache = new NullUserCache();

下面来看下springsecurity的缓存


SpringSecurity 源码分析1
?

springsecurity的缓存主要还是通过ehcache缓存实现的。只是封装了一下方法。下面请看UserCache实现类

public class EhCacheBasedUserCache implements UserCache, InitializingBean {    //~ Static fields/initializers =====================================================================================    private static final Log logger = LogFactory.getLog(EhCacheBasedUserCache.class);    //~ Instance fields ================================================================================================    private Ehcache cache;    //~ Methods ========================================================================================================    public void afterPropertiesSet() throws Exception {        Assert.notNull(cache, "cache mandatory");    }    public Ehcache getCache() {        return cache;    }    public UserDetails getUserFromCache(String username) {        Element element = null;        try {            element = cache.get(username);        } catch (CacheException cacheException) {            throw new DataRetrievalFailureException("Cache failure: " + cacheException.getMessage());        }        if (logger.isDebugEnabled()) {            logger.debug("Cache hit: " + (element != null) + "; username: " + username);        }        if (element == null) {            return null;        } else {            return (UserDetails) element.getValue();        }    }    public void putUserInCache(UserDetails user) {        Element element = new Element(user.getUsername(), user);        if (logger.isDebugEnabled()) {            logger.debug("Cache put: " + element.getKey());        }        cache.put(element);    }    public void removeUserFromCache(UserDetails user) {        if (logger.isDebugEnabled()) {            logger.debug("Cache remove: " + user.getUsername());        }        this.removeUserFromCache(user.getUsername());    }    public void removeUserFromCache(String username) {        cache.remove(username);    }    public void setCache(Ehcache cache) {        this.cache = cache;    }}

?在这里可以看到这些方法都是调用了ehcache里面的方法。?这里的?? private Ehcache cache;是靠你在配置文件配的。注入进来的。

<bean value="userCahce"></property> </bean>

? SpringSecurity刚入门不久,主要把概率,理论弄清楚了。感觉还是比较容易的。让后在结合源码看一下。映像就深刻多了,今天就写到这了。下次在看下SpringSecurity的Filter在说吧。。。。。

?



?

热点排行