SecurityContextHolder

将给定的 SecurityContext 与当前执行线程关联。
此类提供了一系列操作委托给 SecurityConextHolderStrategy 实例的静态方法。
这个类的目的是提供一种方便的方法来指定应该用于给定JVM的策略。
这是一个JVM范围的设置,因为该类中的所有内容都是静态的,以便于调用代码。
该类定义了三个常量 MODE_THREADLOCAL、MODE_INHERITABLETHREADLOCAL、MODE_GLOBAL用来指定实际的SecurityConextHolderStrategy 实例,用户也可以用自定义SecurityConextHolderStrategy具体实现的完全限定类名指定。
有两种方法可以指定
第一种方法是通过以SYSTEM_PROPERTY为关键字的系统属性指定它。
第二种方法是在使用类之前调用setStrategyName(String)。
如果这两种方法都没有使用,该类将默认使用MODE_THREADLOCAL,这是向后兼容的,具有较少的JVM不兼容性,并且适用于服务器(而MODE_GLOBAL绝对不适合服务器使用)。

public class SecurityContextHolder {public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";public static final String MODE_GLOBAL = "MODE_GLOBAL";public static final String SYSTEM_PROPERTY = "spring.security.strategy";private static String strategyName = System.getProperty(SYSTEM_PROPERTY);private static SecurityContextHolderStrategy strategy;private static int initializeCount = 0;static {initialize();}// 改变首选策略。对于给定的JVM,不要多次调用此方法,因为它将重新初始化策略,并对使用旧策略的任何现有线程产生不利影响public static void setStrategyName(String strategyName) {SecurityContextHolder.strategyName = strategyName;initialize();}// 从当前线程显式清除SecurityContextpublic static void clearContext() {strategy.clearContext();}public static SecurityContext getContext() {return strategy.getContext();}// 将新SecurityContext与当前执行线程关联public static void setContext(SecurityContext context) {strategy.setContext(context);}public static SecurityContextHolderStrategy getContextHolderStrategy() {return strategy;}public static int getInitializeCount() {return initializeCount;}public static SecurityContext createEmptyContext() {return strategy.createEmptyContext();}private static void initialize() {if (!StringUtils.hasText(strategyName)) {// 默认值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 {Class<?> clazz = Class.forName(strategyName);Constructor<?> customStrategy = clazz.getConstructor();strategy = (SecurityContextHolderStrategy) customStrategy.newInstance();} catch (Exception ex) {ReflectionUtils.handleReflectionException(ex);}}initializeCount++;}}
SecurityContext

定义与当前执行线程关联的最小安全信息的接口。安全上下文存储在SecurityConextHolder中。

public interface SecurityContext extends Serializable {Authentication getAuthentication();void setAuthentication(Authentication authentication);
}
Authentication

表示身份验证请求的令牌,或AuthenticationManager.authenticate(Authentication)方法处理请求后经过身份验证的主体的令牌。
一旦请求通过身份验证,身份验证通常会存储在由SecurityConextHolder通过所使用的身份验证机制管理的线程本地SecurityContext中。
无需使用Spring Security的任何一种身份验证机制,即可通过创建一个身份验证实例并使用以下代码来实现显式身份验证:
SecurityContextHolder.getContext().setAuthentication(anAuthentication);
请注意,除非身份验证的已验证属性设置为真,否则它仍将由遇到它的任何安全拦截器(用于方法或Web调用)进行身份验证。
在大多数情况下,框架透明地负责为您管理安全上下文和身份验证对象。

public interface Authentication extends Principal, Serializable {// 获取权限列表Collection<? extends GrantedAuthority> getAuthorities();// 获取凭据,登录密码或者短信验证码、访问tokenObject getCredentials();// 获取认证详情,可自定义Object getDetails();// 获取认证信息,用户名或者手机号码等  Object getPrincipal();// 是否认过证标识boolean isAuthenticated();// 设置是否认证过void setAuthenticated(boolean authenticated) throws IllegalArgumentException;
}

AuthenticationProvider

该类表示可以处理特定的 Authentication 实现;认证器的接口类,几乎所有的认证认证逻辑类都要实现这个接口。

public interface AuthenticationProvider {// 认证接口方法// 使用与AuthenticationManager.authenticate(Authentication)相同的约定执行身份认证操作// 参数:身份验证请求(Authentication )// 返回:认证通过的包括凭据额身份验证对象(Authentication ),如果当前 AuthenticationProvider 不支持传入的 Authentication 时,// 可能返回null; 这样就会下一个 AuthenticationProvider // 认证失败throw AuthenticationExceptionAuthentication authenticate(Authentication authentication) throws AuthenticationException;// 是否支持对给定类型的AuthenticationToken类进行认证boolean supports(Class<?> authentication);
}
AbstractUserDetailsAuthenticationProvider

允许子类重写和使用UserDetail对象的基AuthenticationProvider。该类旨在响应UsernamePasswordAuthenticationToken身份验证请求。
验证成功后,将创建一个UsernamePasswordAuthenticationToken并将其返回给调用方。令牌将包括用户名的字符串表示形式或从身份验证存储库返回的UserDetail作为其主体。如果正在使用容器适配器,则使用字符串是合适的,因为它需要用户名的字符串表示形式。如果您需要访问经过身份验证的用户的其他属性(如电子邮件地址、人性化名称等),则使用UserDetail是合适的。由于不建议使用容器适配器,并且UserDetail实现提供了额外的灵活性,因此默认情况下将返回UserDetail。若要覆盖此默认值,请将setForceEpalAsString设置为True。
缓存通过存储放在UserCache中的UserDetail对象来处理。这确保了可以验证具有相同用户名的后续请求,而无需查询UserDetailsService。应该注意的是,如果用户似乎提供了不正确的密码,则将查询UserDetailsService以确认使用了最新的密码进行比较。缓存可能只适用于无状态应用程序。例如,在普通的Web应用程序中,SecurityContext存储在用户的会话中,并且不会在每次请求时对用户进行重新身份验证。因此,默认的缓存实现是NullUserCache。

public interface AbstractUserDetailsAuthenticationProvider {/*允许子类对给定身份验证请求返回的(或缓存的)UserDetail执行任何附加检查。通常情况下,子类至少会将Authentication.getCredentials()与UserDetails.getPassword()进行比较。如果需要自定义逻辑来比较UserDetail和/或UsernamePasswordAuthenticationToken的其他属性,则这些属性也应出现在此方法中。userDetail: 从RetrieseUser(字符串,UsernamePasswordAuthenticationToken)或User缓存检索到的。authentication: 需要进行身份验证的当前请求如果无法验证凭据,则会抛出身份验证异常(通常为BadCredentialsException,即AuthenticationServiceException)*/protected abstract void additionalAuthenticationChecks(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication)throws AuthenticationException;
}
DaoAuthenticationProvider

从 UserDetailsService 查询用户详细信息的 AuthationProvider 实现

AuthenticationManager

身份验证管理器;处理身份验证(Authentication)请求

public interface AuthenticationManager {/*尝试对传递的 Authentication  对象进行身份验证,如果成功,则返回完全填充的 Authentication 证对象(包括授予的权限)。AuthenticationManager 必须遵守以下有关例外情况的契约:如果帐户被禁用,throw DisabledException如果帐户被锁定,throw LockedException如果提供了不正确的凭据,throw  BadCredentialsException虽然上述例外是可选的,但 AuthenticationManager 必须始终检测凭据。应按上述顺序检测异常并在适用时抛出(即,如果帐户被禁用或锁定,则身份验证请求立即被拒绝,并且不执行凭据检测过程)。这可防止针对禁用或锁定的帐户检测凭据。参数:authentication 身份验证请求对象返回:完全经过身份验证的对象,包括凭据异常:如果身份验证失败,则抛出AuthenticationException*/Authentication authenticate(Authentication authentication) throws AuthenticationException;
}
ProviderManager

迭代通过一组身份验证提供程序的身份验证请求。
在提供非空响应之前,通常会按顺序尝试 AuthationProvider。非空响应表示提供程序有权决定身份验证请求,不再尝试其他 provider 。
如果后续 provider 成功验证了请求,则忽略先前的验证异常,并使用成功的验证。
如果没有后续 provider 提供非空响应或新的身份验证异常,则将使用收到的最后一个身份验证异常。
如果没有 provider 返回非空响应,或者没有可以处理当前 身份验证的 provider ,则ProviderManager 将抛出 ProviderNotFoundException。
还可以设置父身份验证管理器,如果配置的提供程序都不能执行身份验证,也会尝试这样做。这是为了支持名称空间配置选项,这通常不是必需的特性。
此过程的例外情况是提供程序抛出AccountStatusException,在这种情况下,将不会查询列表中的其他提供程序。
身份验证后,如果返回的身份验证对象实现了CredentialsContainer接口,则将从该对象中清除凭据。可以通过修改eraseCredentialsAfterAuthentication属性来控制此行为。

发布事件
身份验证事件发布被委托给已配置的AuthationEventPublisher,它缺省为不发布事件的空实现,因此,如果您自己配置Bean,如果您想要接收事件,则必须注入一个发布者Bean。
标准实现是DefaultAuthenticationEventPublisher,它将常见异常映射到事件(在身份验证失败的情况下),并在身份验证成功时发布一个AuthenticationSuccessEvent。
如果您使用的是名称空间,则 http 配置将自动使用该Bean的一个实例,因此您将自动从应用程序的Web部分接收事件。
请注意,当该实现从 “parent” AuthationManager 获得身份验证结果(或异常)时,它还会发布身份验证失败事件(如果已设置)。因此,在这种情况下,通常不应将父对象配置为发布事件,否则会出现重复事件。

public class ProviderManager implements AuthenticationManager, MessageSourceAware,InitializingBean {/*尝试对传递的身份验证对象进行身份验证。将连续尝试身份验证提供程序列表,直到身份验证提供程序指示它能够对传递的身份验证对象类型进行身份验证。然后将尝试使用该身份验证提供程序进  行身份验证。如果多个身份验证提供者支持传递的身份验证对象,则第一个能够成功验证身份验证对象的身份验证对象将确定结果,从而重写先前支持身份验证提供者     引发的任何可能的身份验证异常。身份验证成功后,不会尝试任何后续的身份验证提供程序。如果任何支持的AuthenticationProvider未成功进行身份验证,则将重新抛出最后抛出的AuthenticationException异常。参数:authentication 身份验证请求对象返回:完全经过身份验证的对象,包括凭据异常:如果身份验证失败,则抛出AuthenticationException*/Authentication authenticate(Authentication authentication) throws AuthenticationException;
}
AuthenticationManagerBuilder

用于创建 AuthenticationManager 的 SecurityBuilder。允许轻松地在内存中构建身份验证、LDAP身份验证、基于JDBC的身份验证、添加UserDetailsService和添加AuthenticationProvider。

public class AuthenticationManagerBuilderextendsAbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder>implements ProviderManagerBuilder<AuthenticationManagerBuilder> {/*允许提供父身份验证管理器,如果此身份验证管理器无法尝试对提供的身份验证进行身份验证,则将尝试该父身份验证管理器。*/public AuthenticationManagerBuilder parentAuthenticationManager(AuthenticationManager authenticationManager) {......}/*根据传入的自定义UserDetailsService添加身份验证。然后,它返回一个DaoAuthenticationConfigurer,以允许定制身份验证。此方法还确保UserDetailsService可用于getDefaultUserDetailsService()方法。请注意,其他UserDetailsService可能会覆盖此       UserDetailsService作为默认设置。返回:允许定制DAO身份验证的DaoAuthenticationConfigureer。异常:如果在添加基于UserDetailsService的身份验证时出错*/public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(T userDetailsService) throws Exception {......}/*根据传入的自定义AuthationProvider添加身份验证。由于AuthenticationProvider实现是未知的,因此所有定制都必须在外部完成,并立即返回AuthenticationManagerBuilder。此方法不能确保UserDetailsService可用于getDefaultUserDetailsService()方法。请注意,如果在添加AuthationProvider时发生错误,则可能会引发异常。返回:一个AuthenticationManagerBuilder*/public AuthenticationManagerBuilder authenticationProvider(AuthenticationProvider authenticationProvider) {this.authenticationProviders.add(authenticationProvider);return this;}}

AuthenticationManagerBuilder类在spring-security-config-5.2.4-RELEAS.jar中的org.springframework.security.config.annotation.authentication.configuration包中的配置类
AuthenticationConfiguration中对AuthenticationManagerBuilder类中定义了beanAuthenticationConfiguration.class

@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {AuthenticationConfiguration.LazyPasswordEncoder defaultPasswordEncoder = new AuthenticationConfiguration.LazyPasswordEncoder(context);AuthenticationEventPublisher authenticationEventPublisher = (AuthenticationEventPublisher)getBeanOrNull(context, AuthenticationEventPublisher.class);AuthenticationConfiguration.DefaultPasswordEncoderAuthenticationManagerBuilder result = new AuthenticationConfiguration.DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, defaultPasswordEncoder);if (authenticationEventPublisher != null) {result.authenticationEventPublisher(authenticationEventPublisher);}return result;
}
HttpSecurity

HttpSecurity类似于名称空间配置中的Spring Security的XML http 元素。它允许为特定的 http 请求配置基于Web的安全性。默认情况下,它将应用于所有请求,但可以使用questMatcher(RequestMatcher)或其他类似方法进行限制。
用法示例:
最基本的基于表单的配置如下所示。配置将要求所请求的任何URL都需要具有角色“Role_User”的用户。它还定义了一个内存身份验证方案,其中的用户具有用户名“USER”、密码“PASSWORD”和角色“ROLE_USER”。有关其他示例,请参阅HttpSecurity上各个方法的Java文档。

@Configuration
@EnableWebSecurity
public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");}
}
public final class HttpSecurity extendsAbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>implements SecurityBuilder<DefaultSecurityFilterChain>,HttpSecurityBuilder<HttpSecurity> {}
AbstractAuthenticationProcessingFilter

基于浏览器的基于HTTP的身份验证请求的抽象处理器。

验证过程
筛选器要求您设置身份验证管理器属性。需要一个身份验证管理器来处理通过实现类创建的身份验证请求令牌。
如果请求与setRequiresAuthenticationRequestMatcher(RequestMatcher).匹配,则此过滤器将截取请求并尝试从该请求执行身份验证。
身份验证由temtemptAuthentication方法执行,该方法必须由子类实现。

验证成功
如果身份验证成功,则生成的身份验证对象将被放入当前线程的SecurityContext中,该线程被保证已由先前的过滤器创建。
在成功登录后,将调用配置的AuthationSuccessHandler将重定向带到适当的目的地。默认行为是在SavedRequestAwareAuthenticationSuccessHandler中实现的,它将利用ExceptionTranslationFilter设置的任何DefaultSavedRequest,并将用户重定向到其中包含的URL。否则,它将重定向到Webapp根目录“/”。您可以通过注入此类的不同配置实例或使用不同的实现来自定义此行为。
有关更多信息,请参阅SuccessfulAuthentication(HttpServletRequest,HttpServletResponse,FilterChain,Authentication)方法。

验证失败
如果身份验证失败,它将委托给已配置的AuthenticationFailureHandler,以允许将失败信息传递给客户端。默认实现是SimpleUrlAuthenticationFailureHandler,它向客户端发送401错误代码。它也可以配置失败URL作为替代。同样,您可以在这里注入您需要的任何行为。

发布事件
如果身份验证成功,则将通过应用程序上下文发布一个InteractiveAuthationSuccessEvent。如果身份验证不成功,则不会发布任何事件,因为这通常会通过特定于AuthenticationManager的应用程序事件来记录。

会话认证策略
该类有一个可选的SessionAuthenticationStrategy,它将在成功调用temtemptAuthentication()后立即被调用。可以注入不同的实现,以实现会话固定攻击预防或控制主体可能同时拥有的会话数量等功能。

public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBeanimplements ApplicationEventPublisherAware, MessageSourceAware {/*** @param DefaultFilterProcessUrl–FilterProcessUrl的默认值*/protected AbstractAuthenticationProcessingFilter(String defaultFilterProcessesUrl) {setFilterProcessesUrl(defaultFilterProcessesUrl);}/*** Creates a new instance** @param 用于确定是否需要身份验证的RequestMatcher*/protected AbstractAuthenticationProcessingFilter(RequestMatcher requiresAuthenticationRequestMatcher) {Assert.notNull(requiresAuthenticationRequestMatcher,"requiresAuthenticationRequestMatcher cannot be null");this.requiresAuthenticationRequestMatcher = requiresAuthenticationRequestMatcher;}/*调用requiresAuthentication方法以确定请求是否为身份验证请求,是否应由此筛选器处理。如果是鉴权请求,则调用temtemptAuthentication进行鉴权。然后有三种可能的结果:1、返回一个身份验证对象。将调用已配置的SessionAuthenticationStrategy(以处理任何与会话相关的行为,如创建新会话以防止会话固定攻击),然后调用successfulAuthentication(HttpServletRequest、HttpServletResponse、FilterChain、Authentication)方法。2、在身份验证过程中发生身份验证异常。将调用不成功的身份验证方法。3、返回空,表示鉴权过程未完成。然后该方法将立即返回,假设子类已经完成了继续身份验证过程所需的任何工作(如重定向)。假设返回的身份验证对象不为空时,此方法将接收稍后的请求。*/public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) res;if (!requiresAuthentication(request, response)) {chain.doFilter(request, response);return;}if (logger.isDebugEnabled()) {logger.debug("Request is to process authentication");}Authentication authResult;try {authResult = attemptAuthentication(request, response);if (authResult == null) {// return immediately as subclass has indicated that it hasn't completed(立即返回,因为子类已指示它尚未完成)// authenticationreturn;}sessionStrategy.onAuthentication(authResult, request, response);}catch (InternalAuthenticationServiceException failed) {logger.error("An internal error occurred while trying to authenticate the user.", failed);unsuccessfulAuthentication(request, response, failed);return;}catch (AuthenticationException failed) {// Authentication failed(认证失败)unsuccessfulAuthentication(request, response, failed);return;}// Authentication successif (continueChainBeforeSuccessfulAuthentication) {chain.doFilter(request, response);}successfulAuthentication(request, response, chain, authResult);} /*执行实际身份验证。实施应执行以下操作之一:1、为经过身份验证的用户返回填充的身份验证令牌,指示身份验证成功。2、返回NULL,表示身份验证过程仍在进行中。在返回之前,实现应该执行完成该过程所需的任何附加工作。3、如果身份验证过程失败,则引发身份验证异常*/public abstract Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException, IOException,ServletException;/*** 设置过滤处理Url,也就是过滤器拦截的登录认证请求Url*/public void setFilterProcessesUrl(String filterProcessesUrl) {this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(filterProcessesUrl));}/*** 认证失败后的处理方法*/protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,          AuthenticationException failed) throws IOException, ServletException {// 清空与当前线程绑定的SecurityContextSecurityContextHolder.clearContext();if (this.logger.isDebugEnabled()) {this.logger.debug("Authentication request failed: " + failed.toString(), failed);this.logger.debug("Updated SecurityContextHolder to contain null Authentication");this.logger.debug("Delegating to authentication failure handler " + this.failureHandler);}// 清除之前持久化保存的认证信息并设置response中的cookie失效this.rememberMeServices.loginFail(request, response);// 认证失败处理器回调,这个处理器回调也可以在自定义的认证处理过滤器中进行自定义设置this.failureHandler.onAuthenticationFailure(request, response, failed);}/*** 设置认证管理器*/public void setAuthenticationManager(AuthenticationManager authenticationManager) {this.authenticationManager = authenticationManager;}/*** 设置认证成功处理器*/public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {Assert.notNull(successHandler, "successHandler cannot be null");this.successHandler = successHandler;}/*** 设置认证失败失败处理器*/public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {Assert.notNull(failureHandler, "failureHandler cannot be null");this.failureHandler = failureHandler;}
}
UsernamePasswordAuthenticationFilter

处理表单提交身份验证请求
在SpringSecurity3.0之前的版本中,它被称为AuthenticationProcessingFilter。
登录表单必须向此过滤器提供两个参数:用户名和密码。
要使用的默认参数名称包含在静态字段SPRING_SECURITY_FORM_USERNAME_KEY和SPRING_SECURITY_FORM_PASSWORD_KEY中。
也可以通过设置 usernameParameter 和 passwordParameter 属性来更改参数名称。
默认情况下,此Fileter 只处理URL为 /login的请求。

public class UsernamePasswordAuthenticationFilter extendsAbstractAuthenticationProcessingFilter {/*默认拦截 /login路径,且必须时POST请求方法*/public UsernamePasswordAuthenticationFilter() {super(new AntPathRequestMatcher("/login", "POST"));}/*** attemptAuthentication方法中从HttpServletRequest请求对象中* 提取username和password参数并封装成UsernamePasswordAuthenticationToken对象* 最后调用其认证管理器的authentication方法,并返回该方法的返回值* 也就是*/public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (this.postOnly && !request.getMethod().equals("POST")) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());} else {String username = this.obtainUsername(request);String password = this.obtainPassword(request);if (username == null) {username = "";}if (password == null) {password = "";}username = username.trim();UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);this.setDetails(request, authRequest);/**下面这个方法也就是ProviderManager#authenticate方法* 在前面的ProviderManager#authenticate方法源码中已经分析过了,* 这里就不啰嗦了*/return this.getAuthenticationManager().authenticate(authRequest);}}
}

参考:
  • 一文梳理SpringSecurity中的登录认证流程

Servlet 身份验证体系结构(源码)相关推荐

  1. 基于java web servlet生鲜商城管理系统源码含报告文档

    (一)目的 电子商务的迅速兴起,网上购物也为人们的生活提供了极大的便利,不受时间和空间的限制.商城系统的兴起,扩大了消费市场的空间,对于大型企业来说,建设商城系统是正确的选择,不仅要扩大销售渠道,而且 ...

  2. php授权验证系统源码-全解开源版

    简介: php授权验证系统源码全解开源版,正版授权查询管理. 安装方法:上传PHP环境,访问域名instll,根据提示自动安装! 网盘下载地址: http://kekewl.org/MBJa7XXNk ...

  3. Thinkphp开发App网络授权验证系统源码

    正文: Thinkphp开发App网络授权验证系统源码,没有过多的介绍,大家自己去研究吧,有ZF接口,卡Mi管理,Ying用管理,Yong户管理等功能. 下载方式: lanzou.com/iAYMm0 ...

  4. 全新Thinkphp开发App网络授权验证系统源码

    正文: Thinkphp开发App网络授权验证系统源码,没有过多的介绍,大家自己去研究吧,有支付接口,卡卡密管理,应用用管理,用户管理等功能. 程序: wwuyh.lanzoub.com/iAEmy0 ...

  5. 最新天狼星网络验证完整源码+功能强大/UI也不错

    正文: 最新天狼星网络验证完整源码+功能强大/UI也不错,程序是通过PHP开发的,功能方面真心没得说,程序的搭建很简单,就正常搭建就行了,用过这网络验证程序的都还觉得不错. 天狼星网络验证:一个可以添 ...

  6. harbor登录验证_Harbor 源码浅析

    Harbor 源码浅析​www.qikqiak.com Harbor 是一个CNCF基金会托管的开源的可信的云原生docker registry项目,可以用于存储.签名.扫描镜像内容,Harbor 通 ...

  7. q群机器人php,机器人自动审核入群验证php源码

    本来想易插件源码和php源码一起发的,突然之间没了兴趣.有时间在发布一个更简单的利用查询授权接口实现 php源码如下:<?php //标记编码方式,防止浏览器乱码 header('Content ...

  8. 微信公众平台开发(1)验证TOKEN源码

    说明:使用的是官方的源代码进行验证,所使用的服务器为新浪SAE.在官方源代码中只需更改:define("TOKEN", "weixin");的值为自己的TOKE ...

  9. 基于Java+JSP+Servlet的网上商城源码案例

    源码编号:F-B15 项目类型:Java web项目(开源免费) 项目名称:基于JSP+Servlet的网上商城(交易吧) 项目架构:B/S架构 开发语言:Java语言 前端技术:HTML.CSS.J ...

  10. php源码 炸鸡网络验证系统源码/功能强大

    源码介绍 PHP源码 炸鸡网络验证系统基于Php+MySql数据库架构的网络验证系统,安全稳定.性能强悍.承载能力强,支持高并发.高承载.多线路,支持服务器集群架设,高性能设计,速度非常快,效率非常高 ...

最新文章

  1. 报告:最大化人工智能(AI)机遇
  2. Office365 Exchange Hybrid No.15 DNS切换及邮件传输排错
  3. OpenGL编程指南7:视图-
  4. TCP建立连接三次握手和释放连接四次握手
  5. android mysql sqlite_Android SQLite (一) 数据库简介
  6. shell的debug模式
  7. Python简洁的出入库系统(模块化)
  8. bash算术求值和errexit陷阱
  9. BZOJ5216 [Lydsy2017省队十连测]公路建设
  10. 标准误计算机excel公式,关于excel计算标准差SD和标准误SE的方法
  11. 看完这篇你就懂了深度学习的具体流程和代码该怎么写了!(Deep Learning Onramp)
  12. 计算机识别人脸原理,深入浅出人脸识别原理
  13. python批量裁剪图片_python实现图片批量剪切示例
  14. 禅说派-全图型PPT之图片处理技巧精粹
  15. 发电子邮件怎么发,手机发电子邮件教程来了
  16. python 物理引擎 摩擦力_为什么单机游戏中的碰撞很不真实?物理引擎真的很难做到和现实一样吗?...
  17. 大数据Clouder专项技能认证课程:Quick BI企业报表制作
  18. vue中click无效问题
  19. 小程序用vue开发可以吗,vue直接开发小程序
  20. 球弹跳10次的计算c语言,C/C++编程学习 - 第6周 ⑤ 球弹跳高度的计算

热门文章

  1. MATLAB调用cpp文件
  2. 基于SSM的大学生就业信息管理系统
  3. 【VTK】装配体Assembly的使用
  4. vtk学习教程(一)
  5. 在家自学html,怎样在家自学英语口语
  6. 微信小程序编译的时候模拟器空白显示
  7. 滤波器带宽,信号带宽 和晶振PPM(误差)的关系
  8. SQL round()函数
  9. Python爬虫理论 | (2) 网络请求与响应
  10. Python小程序(4)--52周存钱挑战