Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 中文字幕在线观看日韩,日韩去日本高清在线,亚洲美女综合

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          SpringSecurity(一)源碼分析及認(rèn)證流程

          SpringSecurity(一)源碼分析及認(rèn)證流程

          、Spring Security 概述

          Spring Security 是能夠?yàn)镾pring 企業(yè)應(yīng)用提供聲明式的安全訪問(wèn)控制解決方案的安全框架,為應(yīng)用系統(tǒng)提供聲明式的安全訪問(wèn)控制功能,減少為企業(yè)系統(tǒng)安全訪問(wèn)控制編寫大量重復(fù)的代碼。

          1.1 Spring Security項(xiàng)目核心模塊

          spring-security
          ├── 核心 - spring-security-core.jar
          ├── Remoting - spring-security-remoting.jar
          ├── Web - spring-security-web.jar
          ├── 配置 - spring-security-config.jar
          ├── LDAP - spring-security-ldap.jar
          ├── OAuth 2.0核心 - spring-security-oauth2-core.jar
          ├── OAuth 2.0客戶端 - spring-security-oauth2-client.jar
          ├── OAuth 2.0 JOSE - spring-security-oauth2-jose.jar
          ├── ACL - spring-security-acl.jar
          ├── CAS - spring-security-cas.jar
          ├── OpenID - spring-security-openid.jar
          └── 測(cè)試 - spring-security-test.jar
          

          核心詳細(xì)描述參考中文官網(wǎng)

          1.2 Spring Security 簡(jiǎn)單集成

          Spring Security 支持Maven和Gradle集成,本文主要使用Spring Boot與Maven: pom.xml

          <dependencies>
              <!-- ... other dependency elements ... -->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-security</artifactId>
              </dependency>
          </dependencies>
          

          1.2.1 使用Security安全功能

          • 增加配置類,使用注解@EnableWebSecurity開(kāi)啟Web安全功能
          • 實(shí)現(xiàn)了接口WebSecurityConfigurer或者繼承自WebSecurityConfigurerAdapter),增加Security安全配置。

          代碼清單:

          @EnableWebSecurity
          public class SecurityConfig extends WebSecurityConfigurerAdapter {
          
            @Override
            protected void configure(HttpSecurity http) throws Exception {
              http
                  .authorizeRequests((authorize) -> authorize
                      .antMatchers("/css/**", "/index").permitAll()
                      .antMatchers("/user/**").hasRole("USER")
                  )
                  .formLogin((formLogin) -> formLogin
                      .loginPage("/login")
                      .failureUrl("/login-error")
                  );
            }
            @Bean
            public UserDetailsService userDetailsService() {
              UserDetails userDetails=User.withDefaultPasswordEncoder()
                  .username("user")
                  .password("password")
                  .roles("USER")
                  .build();
              return new InMemoryUserDetailsManager(userDetails);
            }
          }
          

          當(dāng)添加了SecurityConfig 之后我們的應(yīng)用就具備如下功能:

          • 要求對(duì)應(yīng)用程序中的除了/css/**", "/index每個(gè)URL進(jìn)行身份驗(yàn)證
          • 要求對(duì)應(yīng)用程序中的/user/**的URL訪問(wèn)都需要USER角色才能訪問(wèn)
          • 指定“/login”該路徑為登錄頁(yè)面,當(dāng)未認(rèn)證的用戶嘗試訪問(wèn)任何受保護(hù)的資源時(shí),都會(huì)跳轉(zhuǎn)到“/login”。
          • 默認(rèn)指定“/logout”為注銷頁(yè)面
          • 配置一個(gè)內(nèi)存中的用戶認(rèn)證器,使用admin/admin作為用戶名和密碼,具有USER角色。
          • CSRF攻擊預(yù)防
          • 會(huì)話固定保護(hù)
          • 安全標(biāo)頭集成
          • 用于安全請(qǐng)求的 HTTP嚴(yán)格傳輸安全性
          • X-Content-Type-Options集成
          • 緩存控制(稍后可由應(yīng)用程序覆蓋以允許緩存靜態(tài)資源)
          • X-XSS-Protection集成
          • X-Frame-Options集成有助于防止Clickjacking
          • 與以下Servlet API方法集成
          • HttpServletRequest的#getRemoteUser()
          • HttpServletRequest.html#getUserPrincipal()
          • HttpServletRequest.html#的isUserInRole(java.lang.String中)
          • HttpServletRequest.html#login(java.lang.String,java.lang.String)
          • HttpServletRequest.html#注銷()

          2、源碼分析-Security安全認(rèn)證實(shí)現(xiàn)

          2.1 Security安全認(rèn)證過(guò)程類圖

          2.2 Security安全認(rèn)證自動(dòng)化配置

          2.2.1 @EnableWebSecurity

          從類關(guān)系圖可以清楚**@EnableWebSecurity**注解是開(kāi)啟Security安全功能的核心注解,EnableWebSecurity源碼清單:

          @Retention(RetentionPolicy.RUNTIME)
          @Target(ElementType.TYPE)
          @Documented
          @Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
          		HttpSecurityConfiguration.class })
          @EnableGlobalAuthentication
          @Configuration
          public @interface EnableWebSecurity {
          
          	/**
          	 * Controls debugging support for Spring Security. Default is false.
          	 * @return if true, enables debug support with Spring Security
          	 */
          	boolean debug() default false;
          
          }
          

          @EnableWebSecurity是組合注解,引入了Impost注解包含的外部配置以及激活了@EnableGlobalAuthentication注解,而@EnableGlobalAuthentication注解激活了AuthenticationConfiguration認(rèn)證配置類。

          2.2.2 WebSecurityConfiguration

          WebSecurityConfiguration 是web安全配置核心類,WebSecurityConfiguration最主要的功能就是創(chuàng)建了springSecurityFilterChain Bean,springSecurityFilterChain 是spring security的核心過(guò)濾器,是整個(gè)認(rèn)證的入口。WebSecurityConfiguration中完成了聲明springSecurityFilterChain的作用,并且最終交給DelegatingFilterProxy這個(gè)代理類,負(fù)責(zé)攔截請(qǐng)求(注意DelegatingFilterProxy這個(gè)類不是spring security包中的,而是存在于web包中,spring使用了代理模式來(lái)實(shí)現(xiàn)安全過(guò)濾的解耦)。WebSecurityConfiguration源碼清單:

          @Configuration(proxyBeanMethods=false)
          public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
          //省略==========================================@Bean(name=AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
          	public Filter springSecurityFilterChain() throws Exception {
          		boolean hasConfigurers=this.webSecurityConfigurers !=null && !this.webSecurityConfigurers.isEmpty();
          		boolean hasFilterChain=!this.securityFilterChains.isEmpty();
          		Assert.state(!(hasConfigurers && hasFilterChain),
          				"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");
          		if (!hasConfigurers && !hasFilterChain) {
          			WebSecurityConfigurerAdapter adapter=this.objectObjectPostProcessor
          					.postProcess(new WebSecurityConfigurerAdapter() {
          					});
          			this.webSecurity.apply(adapter);
          		}
          		for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
          			this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
          			for (Filter filter : securityFilterChain.getFilters()) {
          				if (filter instanceof FilterSecurityInterceptor) {
          					this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
          					break;
          				}
          			}
          		}
          		for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
          			customizer.customize(this.webSecurity);
          		}
          		return this.webSecurity.build();
          	}
          
          	//省略=====================}
          

          2.2.3 SpringWebMvcImportSelector

          SpringWebMvcImportSelector主要作用是判斷當(dāng)前的環(huán)境是否包含springmvc,因?yàn)閟pring security可以在非spring環(huán)境下使用,為了避免DispatcherServlet的重復(fù)配置,所以使用了這個(gè)注解來(lái)區(qū)分。

          2.2.4 OAuth2ImportSelector

          OAuth2ImportSelector類是為了對(duì) OAuth2.0 開(kāi)放授權(quán)協(xié)議進(jìn)行支持。ClientRegistration 如果被引用,具體點(diǎn)也就是 spring-security-oauth2 模塊被啟用(引入依賴jar)時(shí)。會(huì)啟用 OAuth2 客戶端配置 OAuth2ClientConfiguration

          2.2.5 HttpSecurityConfiguration

          HttpSecurityConfiguration配置類首先通過(guò)@Autowired去獲取容器中的一個(gè)AuthenticationManager實(shí)例,如果沒(méi)能獲取到則使用依賴注入的AuthenticationConfiguration實(shí)例創(chuàng)建一個(gè)AuthenticationManager實(shí)例,這個(gè)實(shí)例其實(shí)就是ProviderManager。然后初始化httpSecurity。

          2.2.5.1 HttpSecurity

          通過(guò)HttpSecurity配置指明了Web Security 攔截什么URL、登錄認(rèn)證方式、設(shè)置什么權(quán)限等。

          2.2.6 AuthenticationConfiguration

          AuthenticationConfiguration 主要作用就是創(chuàng)建全局的身份認(rèn)證管理者AuthenticationManager,AuthenticationManager便是最核心的身份認(rèn)證管理器。 AuthenticationConfiguration源碼清單:

          @Configuration(proxyBeanMethods=false)
          @Import(ObjectPostProcessorConfiguration.class)
          public class AuthenticationConfiguration {
          
          	//省略================@Bean
          	public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,
          			ApplicationContext context) {
          		LazyPasswordEncoder defaultPasswordEncoder=new LazyPasswordEncoder(context);
          		AuthenticationEventPublisher authenticationEventPublisher=getBeanOrNull(context,
          				AuthenticationEventPublisher.class);
          		DefaultPasswordEncoderAuthenticationManagerBuilder result=new DefaultPasswordEncoderAuthenticationManagerBuilder(
          				objectPostProcessor, defaultPasswordEncoder);
          		if (authenticationEventPublisher !=null) {
          			result.authenticationEventPublisher(authenticationEventPublisher);
          		}
          		return result;
          	}
          
          	@Bean
          	public static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(
          			ApplicationContext context) {
          		return new EnableGlobalAuthenticationAutowiredConfigurer(context);
          	}
          
          	@Bean
          	public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(
          			ApplicationContext context) {
          		return new InitializeUserDetailsBeanManagerConfigurer(context);
          	}
          
          	@Bean
          	public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(
          			ApplicationContext context) {
          		return new InitializeAuthenticationProviderBeanManagerConfigurer(context);
          	}
          
          	public AuthenticationManager getAuthenticationManager() throws Exception {
          		if (this.authenticationManagerInitialized) {
          			return this.authenticationManager;
          		}
          		AuthenticationManagerBuilder authBuilder=this.applicationContext.getBean(AuthenticationManagerBuilder.class);
          		if (this.buildingAuthenticationManager.getAndSet(true)) {
          			return new AuthenticationManagerDelegator(authBuilder);
          		}
          		for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) {
          			authBuilder.apply(config);
          		}
          		this.authenticationManager=authBuilder.build();
          		if (this.authenticationManager==null) {
          			this.authenticationManager=getAuthenticationManagerBean();
          		}
          		this.authenticationManagerInitialized=true;
          		return this.authenticationManager;
          	}
          
          //省略================private AuthenticationManager getAuthenticationManagerBean() {
          		return lazyBean(AuthenticationManager.class);
          	}
          

          2.3 驗(yàn)證邏輯

          2.3.1 AuthenticationManager

          AuthenticationManager 提供了認(rèn)證的入口,源碼清單:

          public interface AuthenticationManager {
          	Authentication authenticate(Authentication authentication) throws AuthenticationException;
          }
          

          AuthenticationManager 接收 Authentication 對(duì)象作為參數(shù),并通過(guò) authenticate(Authentication) 方法對(duì)其進(jìn)行驗(yàn)證;AuthenticationProvider實(shí)現(xiàn)類用來(lái)支撐對(duì) Authentication 對(duì)象的驗(yàn)證動(dòng)作;UsernamePasswordAuthenticationToken實(shí)現(xiàn)了 Authentication主要是將用戶輸入的用戶名和密碼進(jìn)行封裝,并供給 AuthenticationManager 進(jìn)行驗(yàn)證;驗(yàn)證完成以后將返回一個(gè)認(rèn)證成功的 Authentication 對(duì)象;

          2.3.2 Authentication

          Authentication 源碼:

          public interface Authentication extends Principal, Serializable {
          
          	//#1.權(quán)限集合
          	Collection<? extends GrantedAuthority> getAuthorities();
          	//#2. 用戶密碼認(rèn)證時(shí),可以理解為密碼
              Object getCredentials();
               //#3. 認(rèn)證時(shí)包含的信息
          	Object getDetails();
              //# 4. 用戶密碼認(rèn)證時(shí),可以理解為用戶名
          	Object getPrincipal();
              //# 5. 是否被認(rèn)證,認(rèn)證為true
          	boolean isAuthenticated();
              //# 6. 設(shè)置是否能夠被認(rèn)證
          	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
          }
          

          2.3.3 ProviderManager

          ProviderManager 它是 AuthenticationManager 的一個(gè)實(shí)現(xiàn)類,提供了基本的認(rèn)證邏輯和方法;它包含了一個(gè) List<AuthenticationProvider> 對(duì)象,通過(guò) AuthenticationProvider 接口來(lái)擴(kuò)展出不同的認(rèn)證提供者(當(dāng)Spring Security默認(rèn)提供的實(shí)現(xiàn)類不能滿足需求的時(shí)候可以擴(kuò)展AuthenticationProvider 覆蓋supports(Class<?> authentication) 方法);

          @Override
          	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                          //# 獲取當(dāng)前認(rèn)證類型
          		Class<? extends Authentication> toTest=authentication.getClass();
          		AuthenticationException lastException=null;
          		AuthenticationException parentException=null;
          		Authentication result=null;
          		Authentication parentResult=null;
          		int currentPosition=0;
          		int size=this.providers.size();
                          //遍歷所有providers,調(diào)用supports驗(yàn)證是否支持當(dāng)前認(rèn)證
          		for (AuthenticationProvider provider : getProviders()) {
          			if (!provider.supports(toTest)) {
          				continue;
          			}
          			if (logger.isTraceEnabled()) {
          				logger.trace(LogMessage.format("Authenticating request with %s (%d/%d)",
          						provider.getClass().getSimpleName(), ++currentPosition, size));
          			}
          			try {
                         //調(diào)用provider的認(rèn)證方法進(jìn)行認(rèn)證
          				result=provider.authenticate(authentication);
          				if (result !=null) {
          					copyDetails(authentication, result);
          					break;
          				}
          			}
          			catch (AccountStatusException | InternalAuthenticationServiceException ex) {
          				prepareException(ex, authentication);
          				// SEC-546: Avoid polling additional providers if auth failure is due to
          				// invalid account status
          				throw ex;
          			}
          			catch (AuthenticationException ex) {
          				lastException=ex;
          			}
          		}
          		if (result==null && this.parent !=null) {
          			// Allow the parent to try.
          			try {
                           //認(rèn)證失敗,調(diào)用父類的認(rèn)證方法進(jìn)行認(rèn)證
          				parentResult=this.parent.authenticate(authentication);
          				result=parentResult;
          
          			}
          			catch (ProviderNotFoundException ex) {
          				// ignore as we will throw below if no other exception occurred prior to
          				// calling parent and the parent
          				// may throw ProviderNotFound even though a provider in the child already
          				// handled the request
          			}
          			catch (AuthenticationException ex) {
          				parentException=ex;
          				lastException=ex;
          			}
          		}
          		if (result !=null) {
          			if (this.eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
          				// Authentication is complete. Remove credentials and other secret data
          				// from authentication
          				((CredentialsContainer) result).eraseCredentials();
          			}
          			// If the parent AuthenticationManager was attempted and successful then it
          			// will publish an AuthenticationSuccessEvent
          			// This check prevents a duplicate AuthenticationSuccessEvent if the parent
          			// AuthenticationManager already published it
          			if (parentResult==null) {
          				this.eventPublisher.publishAuthenticationSuccess(result);
          			}
          
          			return result;
          		}
          
          		// Parent was null, or didn't authenticate (or throw an exception).
          		if (lastException==null) {
          			lastException=new ProviderNotFoundException(this.messages.getMessage("ProviderManager.providerNotFound",
          					new Object[] { toTest.getName() }, "No AuthenticationProvider found for {0}"));
          		}
          		// If the parent AuthenticationManager was attempted and failed then it will
          		// publish an AbstractAuthenticationFailureEvent
          		// This check prevents a duplicate AbstractAuthenticationFailureEvent if the
          		// parent AuthenticationManager already published it
          		if (parentException==null) {
          			prepareException(lastException, authentication);
          		}
          		throw lastException;
          	}
          

          2.3.3 AuthenticationProvider

          AuthenticationProvider, ProviderManager通過(guò)AuthenticationProvider擴(kuò)展多種認(rèn)證方法,AuthenticationProvider 本身也就是一個(gè)接口,從類圖中我們可以看出它的實(shí)現(xiàn)類AbstractUserDetailsAuthenticationProvider 和AbstractUserDetailsAuthenticationProvider的子類DaoAuthenticationProvider 。

          2.3.4 DaoAuthenticationProvider

          DaoAuthenticationProvider 是Spring Security中一個(gè)核心的Provider,對(duì)所有的數(shù)據(jù)庫(kù)提供了基本方法和入口。DaoAuthenticationProvider源碼清單:

          public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
          
          	/**
          	 * 實(shí)現(xiàn)用戶密碼加密
          	 */
          	private PasswordEncoder passwordEncoder;
          
          	//省略
          
          	/**
          	 *
          	 * 實(shí)現(xiàn) additionalAuthenticationChecks 的驗(yàn)證方法(主要驗(yàn)證密碼);
          	 */
          	@Override
          	@SuppressWarnings("deprecation")
          	protected void additionalAuthenticationChecks(UserDetails userDetails,
          			UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
          		if (authentication.getCredentials()==null) {
          			this.logger.debug("Failed to authenticate since no credentials provided");
          			throw new BadCredentialsException(this.messages
          					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
          		}
          		String presentedPassword=authentication.getCredentials().toString();
          		if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
          			this.logger.debug("Failed to authenticate since password does not match stored value");
          			throw new BadCredentialsException(this.messages
          					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
          		}
          	}
          
          //省略
          
          	/**
          	 * 實(shí)現(xiàn)了 AbstractUserDetailsAuthenticationProvider retrieveUser 抽象方法
          	 * 主要是通過(guò)注入U(xiǎn)serDetailsService接口對(duì)象,并調(diào)用其接口方法 loadUserByUsername(String username)獲取得到相關(guān)的用戶信息。
          	 * UserDetailsService接口非常重要。
          	 */
          	@Override
          	protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
          			throws AuthenticationException {
          		prepareTimingAttackProtection();
          		try {
          			//數(shù)據(jù)庫(kù)獲取用戶信息的擴(kuò)展點(diǎn)
          			UserDetails loadedUser=this.getUserDetailsService().loadUserByUsername(username);
          			if (loadedUser==null) {
          				throw new InternalAuthenticationServiceException(
          						"UserDetailsService returned null, which is an interface contract violation");
          			}
          			return loadedUser;
          		}
          		catch (UsernameNotFoundException ex) {
          			mitigateAgainstTimingAttack(authentication);
          			throw ex;
          		}
          		catch (InternalAuthenticationServiceException ex) {
          			throw ex;
          		}
          		catch (Exception ex) {
          			throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
          		}
          	}
          
          	//省略
          }
          

          2.3.4 AbstractUserDetailsAuthenticationProvider

          AbstractUserDetailsAuthenticationProvider主要實(shí)現(xiàn)了AuthenticationProvider的接口方法 authenticate 并提供了相關(guān)的驗(yàn)證邏輯;

          抽象獲取用戶信息方法

          protected abstract UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
          			throws AuthenticationException;
          

          三步驗(yàn)證工作: i. preAuthenticationChecks ii. additionalAuthenticationChecks(抽象方法,子類實(shí)現(xiàn)) iii. postAuthenticationChecks將驗(yàn)證結(jié)果封裝成UsernamePasswordAuthenticationToken返回。

          源碼清單:

          public abstract class AbstractUserDetailsAuthenticationProvider
          		implements AuthenticationProvider, InitializingBean, MessageSourceAware {
          //省略
          	//抽象驗(yàn)證方法(主要驗(yàn)證密碼)
          	protected abstract void additionalAuthenticationChecks(UserDetails userDetails,
          			UsernamePasswordAuthenticationToken authentication) throws AuthenticationException;
          
          //省略
          
          	/**
          	 *
          	 * 實(shí)現(xiàn)AuthenticationProvider.authenticate驗(yàn)證方法
          	 */
          	@Override
          	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
          		Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
          				() -> this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports",
          						"Only UsernamePasswordAuthenticationToken is supported"));
          		String username=determineUsername(authentication);
          		boolean cacheWasUsed=true;
          		UserDetails user=this.userCache.getUserFromCache(username);
          		if (user==null) {
          			cacheWasUsed=false;
          			try {
          				//1. 獲取用戶信息
          				user=retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
          			}
          			catch (UsernameNotFoundException ex) {
          				this.logger.debug("Failed to find user '" + username + "'");
          				if (!this.hideUserNotFoundExceptions) {
          					throw ex;
          				}
          				throw new BadCredentialsException(this.messages
          						.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
          			}
          			Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract");
          		}
          		try {
          			//2. 預(yù)檢查由DefaultPreAuthenticationChecks類實(shí)現(xiàn)(主要判斷當(dāng)前用戶是否鎖定,過(guò)期,凍結(jié)User接口)
          			this.preAuthenticationChecks.check(user);
          			//3. 子類實(shí)現(xiàn)
          			additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
          		}
          		catch (AuthenticationException ex) {
          			if (!cacheWasUsed) {
          				throw ex;
          			}
          			// There was a problem, so try again after checking
          			// we're using latest data (i.e. not from the cache)
          			cacheWasUsed=false;
          			user=retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
          			this.preAuthenticationChecks.check(user);
          			additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
          		}
          		//#4.檢測(cè)用戶密碼是否過(guò)期對(duì)應(yīng)#2 的User接口
          		this.postAuthenticationChecks.check(user);
          		if (!cacheWasUsed) {
          			this.userCache.putUserInCache(user);
          		}
          		Object principalToReturn=user;
          		if (this.forcePrincipalAsString) {
          			principalToReturn=user.getUsername();
          		}
          		//4. 將驗(yàn)證結(jié)果封裝成UsernamePasswordAuthenticationToken
          		return createSuccessAuthentication(principalToReturn, authentication, user);
          	}
          
          	private String determineUsername(Authentication authentication) {
          		return (authentication.getPrincipal()==null) ? "NONE_PROVIDED" : authentication.getName();
          	}
          
          	//封裝驗(yàn)證結(jié)果
          	protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
          			UserDetails user) {
          		// Ensure we return the original credentials the user supplied,
          		// so subsequent attempts are successful even with encoded passwords.
          		// Also ensure we return the original getDetails(), so that future
          		// authentication events after cache expiry contain the details
          		UsernamePasswordAuthenticationToken result=new UsernamePasswordAuthenticationToken(principal,
          				authentication.getCredentials(), this.authoritiesMapper.mapAuthorities(user.getAuthorities()));
          		result.setDetails(authentication.getDetails());
          		this.logger.debug("Authenticated user");
          		return result;
          	}
          
          	//抽象獲取用戶信息接口
          	protected abstract UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
          			throws AuthenticationException;
          
          	//省略
          
          }
          

          2.3.4 UserDetailsService

          UserDetailsService接口作為橋梁,是DaoAuthenticationProvier與特定用戶信息來(lái)源進(jìn)行解耦的地方,UserDetailsService由UserDetails和UserDetailsManager所構(gòu)成;UserDetails和UserDetailsManager各司其責(zé),一個(gè)是對(duì)基本用戶信息進(jìn)行封裝,一個(gè)是對(duì)基本用戶信息進(jìn)行管理;特別注意,UserDetailsService、UserDetails以及UserDetailsManager都是可被用戶自定義的擴(kuò)展點(diǎn),我們可以繼承這些接口提供自己的讀取用戶來(lái)源和管理用戶的方法,比如我們可以自己實(shí)現(xiàn)一個(gè) 與特定 ORM 框架,比如 Mybatis 或者 Hibernate,相關(guān)的UserDetailsService和UserDetailsManager;

          2.3.4.1 UserDetailsService

          UserDetails 驗(yàn)證用戶實(shí)體

          public interface UserDetails extends Serializable {
           #1.權(quán)限集合
           Collection<? extends GrantedAuthority> getAuthorities();
           #2.密碼	
           String getPassword();
           #3.用戶民
           String getUsername();
           #4.用戶是否過(guò)期
           boolean isAccountNonExpired();
           #5.是否鎖定	
           boolean isAccountNonLocked();
           #6.用戶密碼是否過(guò)期	
           boolean isCredentialsNonExpired();
           #7.賬號(hào)是否可用(可理解為是否刪除)
           boolean isEnabled();
          }
          

          2.4 認(rèn)證流程圖

          文由掘金@天行天忌授權(quán)發(fā)布,前端晚間課對(duì)其內(nèi)容進(jìn)行微改。


          HTML,超文本標(biāo)記語(yǔ)言,是一種用于創(chuàng)建網(wǎng)頁(yè)的標(biāo)準(zhǔn)標(biāo)記語(yǔ)言。自從引入 HTML 以來(lái),它就一直用于構(gòu)建互聯(lián)網(wǎng)。與 JavaScript 和 CSS 一起,HTML 構(gòu)成前端開(kāi)發(fā)的三劍客。

          盡管許多新技術(shù)使網(wǎng)站創(chuàng)建過(guò)程變得更簡(jiǎn)單、更高效,但 HTML 始終是核心。隨著 HTML5 的普及,在 2014 年,這種標(biāo)記語(yǔ)言發(fā)生了很多變化,變得更加友好,瀏覽器對(duì)新標(biāo)準(zhǔn)的支持熱度也越來(lái)越高。而HTML并不止于此,還在不斷發(fā)生變化,并且可能會(huì)獲得一些特性來(lái)證明對(duì) HTML6 的命名更改是合理的。

          支持原生模式

          該元素<dialog> 將隨 HTML6 一起提供。它被認(rèn)為等同于用 JavaScript 開(kāi)發(fā)的模態(tài),并且已經(jīng)標(biāo)準(zhǔn)化,但只有少數(shù)瀏覽器完全支持。但這種現(xiàn)象會(huì)改變,很快它將在所有瀏覽器中得到支持。

          這個(gè)元素在其默認(rèn)格式下,只會(huì)將光標(biāo)顯示在它所在的位置上,但可以使用 JavaScript 打開(kāi)模式。

          <dialog>
            <form method="dialog">
              <input type="submit" value="確定" />
              <input type="submit" value="取消" />
            </form>
          </dialog>

          在默認(rèn)形式下,該元素創(chuàng)建一個(gè)灰色背景,其下方是非交互式內(nèi)容。

          可以在 <dialog> 其中的表單上使用一種方法,該方法將發(fā)送值并將其傳遞回自身 <dialog>

          總的來(lái)說(shuō),這個(gè)標(biāo)簽在用戶交互和改進(jìn)的界面中變得有益。

          可以通過(guò)更改 <dialog> 標(biāo)簽的 open 屬性以控制打開(kāi)和關(guān)閉。

          <dialog open>
            <p>組件內(nèi)容</p>
          </dialog>

          沒(méi)有 JavaScript 的單頁(yè)應(yīng)用程序

          FutureClaw 雜志主編 Bobby Mozumder 建議:

          將錨元素鏈接到 JSON/XML、API 端點(diǎn),讓瀏覽器在內(nèi)部將數(shù)據(jù)加載到新的數(shù)據(jù)結(jié)構(gòu)中,然后瀏覽器將 DOM 元素替換為根據(jù)需要加載的任何數(shù)據(jù)。初始數(shù)據(jù)(以及標(biāo)準(zhǔn)錯(cuò)誤響應(yīng))可以放在標(biāo)題裝置中,如果需要,可以稍后替換。

          據(jù)他介紹,這是單頁(yè)應(yīng)用程序網(wǎng)頁(yè)設(shè)計(jì)模式,可以提高響應(yīng)速度和加載時(shí)間,因?yàn)椴恍枰虞d JavaScript。

          這個(gè)是一個(gè)比較有意思的提案,就有點(diǎn)類似我們以前沒(méi)有做前后端分離之前的混合編程的模式,HTML變成模板語(yǔ)言,通過(guò)JSON API請(qǐng)求數(shù)據(jù),不一樣的是變成瀏覽器來(lái)默認(rèn)解析,瀏覽器內(nèi)部加載數(shù)據(jù)到新的數(shù)據(jù)結(jié)構(gòu)中,然后瀏覽器將按需加載到的數(shù)據(jù)替換成 DOM 元素

          大家可以看一下InfoQ上的這篇文章《針對(duì)非正式 HTML6 提案“無(wú)需 JavaScript 的單頁(yè)應(yīng)用”引發(fā)的論戰(zhàn)》,了解更多!

          https://www.infoq.cn/article/2015/03/html6-without-javascript


          自由調(diào)整圖像大小

          HTML6 愛(ài)好者相信即將到來(lái)的更新將允許瀏覽器調(diào)整圖像大小以獲得更好的觀看體驗(yàn)。

          每個(gè)瀏覽器都難以呈現(xiàn)相對(duì)于設(shè)備和屏幕尺寸的最佳圖像尺寸,不幸的是,src 標(biāo)簽 img 在處理這個(gè)問(wèn)題時(shí)不是很有效。

          這個(gè)問(wèn)題可以通過(guò)一個(gè)新標(biāo)簽 <srcset> 來(lái)解決,它使瀏覽器在多個(gè)圖像之間進(jìn)行選擇的工作變得更加容易。

          專用庫(kù)

          將可用庫(kù)引入 HTML6 絕對(duì)是提高開(kāi)發(fā)效率的重要一步。

          微格式

          很多時(shí)候,需要在互聯(lián)網(wǎng)上定義一般信息,而這些一般信息可以是任何公開(kāi)的信息,例如電話號(hào)碼、姓名、地址等。微格式是能夠定義一般數(shù)據(jù)的標(biāo)準(zhǔn)。微格式可以增強(qiáng)設(shè)計(jì)者的能力,并可以減少搜索引擎推斷公共信息所需的努力。

          自定義菜單

          盡管標(biāo)簽<ul>、<ol>非常有用,但在某些情況下仍有一些不足之處。可以處理交互元素的標(biāo)簽將是一個(gè)不錯(cuò)的選擇。

          這就是創(chuàng)建標(biāo)簽 <menu> 的驅(qū)動(dòng)力,它可以處理按鈕驅(qū)動(dòng)的列表元素。

          <menu type="toolbar">
            <li><button>個(gè)人信息</button></li>
            <li><button>系統(tǒng)設(shè)置</button></li>
            <li><button>賬號(hào)注銷</button></li>
          </menu>

          因此 <menu>,除了能夠像普通列表一樣運(yùn)行之外,還可以增強(qiáng) HTML 列表的功能。

          增強(qiáng)身份驗(yàn)證

          雖然HTML5在安全性方面還不錯(cuò),瀏覽器和網(wǎng)絡(luò)技術(shù)也提供了合理的保護(hù)。毫無(wú)疑問(wèn),在身份驗(yàn)證和安全領(lǐng)域還有很多事情可以做。如密鑰可以異地存儲(chǔ);這將防止不受歡迎的人訪問(wèn)并支持身份驗(yàn)證。使用嵌入式密鑰而不是 cookie,使數(shù)字簽名更好等。

          集成攝像頭

          HTML6 允許以更好的方式使用設(shè)備上的相機(jī)和媒體。將能夠控制相機(jī)、它的效果、模式、全景圖像、HDR 和其他屬性。

          總結(jié)

          沒(méi)有什么是完美的,HTML 也不是完美的,所以 HTML 規(guī)范可以做很多事情來(lái)使它更好。應(yīng)該對(duì)一些有用的規(guī)范進(jìn)行標(biāo)準(zhǔn)化,以增強(qiáng) HTML 的能力。小的變化已經(jīng)開(kāi)始推出。如增強(qiáng)藍(lán)牙支持、p2p 文件傳輸、惡意軟件保護(hù)、云存儲(chǔ)集成,下一個(gè) HTML 版本可以考慮一下。

          解決企業(yè)“注銷難”的問(wèn)題,市市場(chǎng)監(jiān)管局說(shuō):今天,上海市注銷企業(yè)“一窗通”網(wǎng)上平臺(tái)正式上線→企業(yè)填報(bào)注銷申請(qǐng)信息后,平臺(tái)同步推送給市場(chǎng)監(jiān)管、稅務(wù)、人社、商務(wù)、海關(guān)、人民銀行、外管等行政部門以及人民法院等司法部門,各部門并聯(lián)預(yù)審辦理,提高效率。平臺(tái)還提供銀行賬戶撤銷的預(yù)約服務(wù)功能和在國(guó)家企業(yè)信用信息公示系統(tǒng)免費(fèi)發(fā)布注銷公告的功能。怎么使用?看過(guò)來(lái)↓

          企業(yè)注銷流程再造

          企業(yè)填報(bào)注銷申請(qǐng)信息后,平臺(tái)同步推送給各相關(guān)部門,各部門并聯(lián)預(yù)審辦理。平臺(tái)引導(dǎo)企業(yè)按照最優(yōu)方案辦理注銷,幫助申請(qǐng)人了解各項(xiàng)業(yè)務(wù)的前后辦理關(guān)系。平臺(tái)還提供銀行賬戶撤銷的預(yù)約服務(wù)功能,幫助企業(yè)縮短注銷銀行賬戶的辦理時(shí)間。

          注銷企業(yè)“一窗通”網(wǎng)上平臺(tái)現(xiàn)有2個(gè)入口:

          第一個(gè)入口:上海市人民政府官網(wǎng)“中國(guó)上海”網(wǎng)站

          (http://www.shanghai.gov.cn/)首頁(yè)上點(diǎn)擊“一網(wǎng)通辦”

          然后可以在第二個(gè)頁(yè)面的“優(yōu)化營(yíng)商環(huán)境”欄目下找到“企業(yè)注銷”按鈕

          第二個(gè)入口:上海市市場(chǎng)監(jiān)管局官網(wǎng)上的專欄通道

          (http://www.sgs.gov.cn/shaic/index_new.html)

          企業(yè)注銷規(guī)范透明

          平臺(tái)為注銷申請(qǐng)人集中提供各部門辦理指南、結(jié)果反饋、全流程進(jìn)度跟蹤等電子政務(wù)服務(wù),及時(shí)告知企業(yè)辦理流程、辦理要求和進(jìn)度情況,督促各業(yè)務(wù)部門按照規(guī)定時(shí)限和要求完成注銷業(yè)務(wù)程序,進(jìn)一步實(shí)現(xiàn)注銷流程的規(guī)范化、法治化。

          企業(yè)注銷便捷高效

          通過(guò)平臺(tái)的信息互通共享,各部門可從平臺(tái)獲取企業(yè)信息和部門辦理結(jié)果,從而簡(jiǎn)化數(shù)據(jù)填報(bào)采集和材料提交要求,優(yōu)化辦理流程。

          海關(guān)、人力資源社會(huì)保障部門可以利用注銷平臺(tái),通過(guò)數(shù)據(jù)校驗(yàn)和信息共享實(shí)現(xiàn)網(wǎng)上辦理;市場(chǎng)監(jiān)管部門可以實(shí)現(xiàn)各類申請(qǐng)文書材料的自動(dòng)生成,進(jìn)一步壓縮注銷登記辦理時(shí)間;稅務(wù)等部門可以實(shí)現(xiàn)預(yù)審并出具個(gè)性化“診斷書”,告知企業(yè)是否符合稅務(wù)免辦或即辦條件,減少和簡(jiǎn)化材料提交的數(shù)量和要求。

          此外,平臺(tái)還為企業(yè)提供了在國(guó)家企業(yè)信用信息公示系統(tǒng)上免費(fèi)發(fā)布注銷公告的功能。

          企業(yè)注銷智能增效

          平臺(tái)通過(guò)和多個(gè)企業(yè)數(shù)據(jù)庫(kù)的對(duì)接,實(shí)現(xiàn)智能比對(duì)篩選,對(duì)企業(yè)注銷申請(qǐng)進(jìn)行分類處置,進(jìn)一步提升辦理效率:

          符合簡(jiǎn)易注銷登記條件的企業(yè),可進(jìn)入國(guó)家企業(yè)信用信息公示系統(tǒng)辦理簡(jiǎn)易注銷,并可在平臺(tái)上查看簡(jiǎn)易注銷辦理進(jìn)度。

          對(duì)其他企業(yè)提出的注銷申請(qǐng),平臺(tái)將相關(guān)申請(qǐng)信息同步發(fā)送給各相關(guān)業(yè)務(wù)部門,各部門進(jìn)行預(yù)審,按照各自要求對(duì)注銷企業(yè)實(shí)行分類處理。對(duì)于可通過(guò)數(shù)據(jù)共享即時(shí)辦結(jié)的,業(yè)務(wù)系統(tǒng)實(shí)時(shí)反饋平臺(tái);對(duì)于不適用線上直接辦理的,根據(jù)企業(yè)情況出具“診斷書”,將辦理本部門注銷所需提交的材料、辦理要求、聯(lián)系方式等信息通過(guò)平臺(tái)和短信反饋給企業(yè)。通過(guò)清單式告知方式,實(shí)現(xiàn)窗口辦事“一口清”。

          資料:市市場(chǎng)監(jiān)管局

          編輯:景雯


          主站蜘蛛池模板: 久久精品国产第一区二区| 国产成人一区在线不卡| 韩国资源视频一区二区三区| 手机看片一区二区| 天美传媒一区二区三区| 无码乱码av天堂一区二区 | 久久91精品国产一区二区| 国产成人av一区二区三区在线 | 亚洲AV日韩精品一区二区三区| 亚洲香蕉久久一区二区| 亚洲福利视频一区| 好看的电影网站亚洲一区| 丰满人妻一区二区三区视频53| 亚洲国产专区一区| 亚洲av片一区二区三区| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 精品一区二区三区波多野结衣| 大伊香蕉精品一区视频在线| 精品一区二区三区视频 | 国产成人久久精品一区二区三区| 人妻少妇精品一区二区三区| 高清国产精品人妻一区二区 | 精品一区二区三区影院在线午夜 | 日韩免费观看一区| 亚洲综合一区二区国产精品| 消息称老熟妇乱视频一区二区| 久久精品一区二区| 蜜臀Av午夜一区二区三区| 久久无码人妻一区二区三区| 韩国福利一区二区美女视频| 日日摸夜夜添一区| 在线免费视频一区| 国产精品一区二区三区99| 综合无码一区二区三区| 久久一本一区二区三区| 91国偷自产一区二区三区| 福利片福利一区二区三区| 日韩综合无码一区二区| 91大神在线精品视频一区| 午夜视频在线观看一区二区| 一区二区三区波多野结衣|