Spring Security 是能夠為Spring 企業(yè)應(yīng)用提供聲明式的安全訪問控制解決方案的安全框架,為應(yīng)用系統(tǒng)提供聲明式的安全訪問控制功能,減少為企業(yè)系統(tǒng)安全訪問控制編寫大量重復(fù)的代碼。
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
└── 測試 - spring-security-test.jar
核心詳細描述參考中文官網(wǎng)
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>
代碼清單:
@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)用就具備如下功能:
從類關(guān)系圖可以清楚**@EnableWebSecurity**注解是開啟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認證配置類。
WebSecurityConfiguration 是web安全配置核心類,WebSecurityConfiguration最主要的功能就是創(chuàng)建了springSecurityFilterChain Bean,springSecurityFilterChain 是spring security的核心過濾器,是整個認證的入口。WebSecurityConfiguration中完成了聲明springSecurityFilterChain的作用,并且最終交給DelegatingFilterProxy這個代理類,負責(zé)攔截請求(注意DelegatingFilterProxy這個類不是spring security包中的,而是存在于web包中,spring使用了代理模式來實現(xiàn)安全過濾的解耦)。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();
}
//省略=====================}
SpringWebMvcImportSelector主要作用是判斷當(dāng)前的環(huán)境是否包含springmvc,因為spring security可以在非spring環(huán)境下使用,為了避免DispatcherServlet的重復(fù)配置,所以使用了這個注解來區(qū)分。
OAuth2ImportSelector類是為了對 OAuth2.0 開放授權(quán)協(xié)議進行支持。ClientRegistration 如果被引用,具體點也就是 spring-security-oauth2 模塊被啟用(引入依賴jar)時。會啟用 OAuth2 客戶端配置 OAuth2ClientConfiguration
HttpSecurityConfiguration配置類首先通過@Autowired去獲取容器中的一個AuthenticationManager實例,如果沒能獲取到則使用依賴注入的AuthenticationConfiguration實例創(chuàng)建一個AuthenticationManager實例,這個實例其實就是ProviderManager。然后初始化httpSecurity。
通過HttpSecurity配置指明了Web Security 攔截什么URL、登錄認證方式、設(shè)置什么權(quán)限等。
AuthenticationConfiguration 主要作用就是創(chuàng)建全局的身份認證管理者AuthenticationManager,AuthenticationManager便是最核心的身份認證管理器。 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);
}
AuthenticationManager 提供了認證的入口,源碼清單:
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
}
AuthenticationManager 接收 Authentication 對象作為參數(shù),并通過 authenticate(Authentication) 方法對其進行驗證;AuthenticationProvider實現(xiàn)類用來支撐對 Authentication 對象的驗證動作;UsernamePasswordAuthenticationToken實現(xiàn)了 Authentication主要是將用戶輸入的用戶名和密碼進行封裝,并供給 AuthenticationManager 進行驗證;驗證完成以后將返回一個認證成功的 Authentication 對象;
Authentication 源碼:
public interface Authentication extends Principal, Serializable {
//#1.權(quán)限集合
Collection<? extends GrantedAuthority> getAuthorities();
//#2. 用戶密碼認證時,可以理解為密碼
Object getCredentials();
//#3. 認證時包含的信息
Object getDetails();
//# 4. 用戶密碼認證時,可以理解為用戶名
Object getPrincipal();
//# 5. 是否被認證,認證為true
boolean isAuthenticated();
//# 6. 設(shè)置是否能夠被認證
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
ProviderManager 它是 AuthenticationManager 的一個實現(xiàn)類,提供了基本的認證邏輯和方法;它包含了一個 List<AuthenticationProvider> 對象,通過 AuthenticationProvider 接口來擴展出不同的認證提供者(當(dāng)Spring Security默認提供的實現(xiàn)類不能滿足需求的時候可以擴展AuthenticationProvider 覆蓋supports(Class<?> authentication) 方法);
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
//# 獲取當(dāng)前認證類型
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驗證是否支持當(dāng)前認證
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的認證方法進行認證
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 {
//認證失敗,調(diào)用父類的認證方法進行認證
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;
}
AuthenticationProvider, ProviderManager通過AuthenticationProvider擴展多種認證方法,AuthenticationProvider 本身也就是一個接口,從類圖中我們可以看出它的實現(xiàn)類AbstractUserDetailsAuthenticationProvider 和AbstractUserDetailsAuthenticationProvider的子類DaoAuthenticationProvider 。
DaoAuthenticationProvider 是Spring Security中一個核心的Provider,對所有的數(shù)據(jù)庫提供了基本方法和入口。DaoAuthenticationProvider源碼清單:
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
/**
* 實現(xiàn)用戶密碼加密
*/
private PasswordEncoder passwordEncoder;
//省略
/**
*
* 實現(xiàn) additionalAuthenticationChecks 的驗證方法(主要驗證密碼);
*/
@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"));
}
}
//省略
/**
* 實現(xiàn)了 AbstractUserDetailsAuthenticationProvider retrieveUser 抽象方法
* 主要是通過注入UserDetailsService接口對象,并調(diào)用其接口方法 loadUserByUsername(String username)獲取得到相關(guān)的用戶信息。
* UserDetailsService接口非常重要。
*/
@Override
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
prepareTimingAttackProtection();
try {
//數(shù)據(jù)庫獲取用戶信息的擴展點
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);
}
}
//省略
}
AbstractUserDetailsAuthenticationProvider主要實現(xiàn)了AuthenticationProvider的接口方法 authenticate 并提供了相關(guān)的驗證邏輯;
抽象獲取用戶信息方法
protected abstract UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException;
三步驗證工作: i. preAuthenticationChecks ii. additionalAuthenticationChecks(抽象方法,子類實現(xiàn)) iii. postAuthenticationChecks將驗證結(jié)果封裝成UsernamePasswordAuthenticationToken返回。
源碼清單:
public abstract class AbstractUserDetailsAuthenticationProvider
implements AuthenticationProvider, InitializingBean, MessageSourceAware {
//省略
//抽象驗證方法(主要驗證密碼)
protected abstract void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException;
//省略
/**
*
* 實現(xiàn)AuthenticationProvider.authenticate驗證方法
*/
@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類實現(xiàn)(主要判斷當(dāng)前用戶是否鎖定,過期,凍結(jié)User接口)
this.preAuthenticationChecks.check(user);
//3. 子類實現(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.檢測用戶密碼是否過期對應(yīng)#2 的User接口
this.postAuthenticationChecks.check(user);
if (!cacheWasUsed) {
this.userCache.putUserInCache(user);
}
Object principalToReturn=user;
if (this.forcePrincipalAsString) {
principalToReturn=user.getUsername();
}
//4. 將驗證結(jié)果封裝成UsernamePasswordAuthenticationToken
return createSuccessAuthentication(principalToReturn, authentication, user);
}
private String determineUsername(Authentication authentication) {
return (authentication.getPrincipal()==null) ? "NONE_PROVIDED" : authentication.getName();
}
//封裝驗證結(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;
//省略
}
UserDetailsService接口作為橋梁,是DaoAuthenticationProvier與特定用戶信息來源進行解耦的地方,UserDetailsService由UserDetails和UserDetailsManager所構(gòu)成;UserDetails和UserDetailsManager各司其責(zé),一個是對基本用戶信息進行封裝,一個是對基本用戶信息進行管理;特別注意,UserDetailsService、UserDetails以及UserDetailsManager都是可被用戶自定義的擴展點,我們可以繼承這些接口提供自己的讀取用戶來源和管理用戶的方法,比如我們可以自己實現(xiàn)一個 與特定 ORM 框架,比如 Mybatis 或者 Hibernate,相關(guān)的UserDetailsService和UserDetailsManager;
UserDetails 驗證用戶實體
public interface UserDetails extends Serializable {
#1.權(quán)限集合
Collection<? extends GrantedAuthority> getAuthorities();
#2.密碼
String getPassword();
#3.用戶民
String getUsername();
#4.用戶是否過期
boolean isAccountNonExpired();
#5.是否鎖定
boolean isAccountNonLocked();
#6.用戶密碼是否過期
boolean isCredentialsNonExpired();
#7.賬號是否可用(可理解為是否刪除)
boolean isEnabled();
}
文由掘金@天行天忌授權(quán)發(fā)布,前端晚間課對其內(nèi)容進行微改。
HTML,超文本標記語言,是一種用于創(chuàng)建網(wǎng)頁的標準標記語言。自從引入 HTML 以來,它就一直用于構(gòu)建互聯(lián)網(wǎng)。與 JavaScript 和 CSS 一起,HTML 構(gòu)成前端開發(fā)的三劍客。
盡管許多新技術(shù)使網(wǎng)站創(chuàng)建過程變得更簡單、更高效,但 HTML 始終是核心。隨著 HTML5 的普及,在 2014 年,這種標記語言發(fā)生了很多變化,變得更加友好,瀏覽器對新標準的支持熱度也越來越高。而HTML并不止于此,還在不斷發(fā)生變化,并且可能會獲得一些特性來證明對 HTML6 的命名更改是合理的。
該元素<dialog> 將隨 HTML6 一起提供。它被認為等同于用 JavaScript 開發(fā)的模態(tài),并且已經(jīng)標準化,但只有少數(shù)瀏覽器完全支持。但這種現(xiàn)象會改變,很快它將在所有瀏覽器中得到支持。
這個元素在其默認格式下,只會將光標顯示在它所在的位置上,但可以使用 JavaScript 打開模式。
<dialog>
<form method="dialog">
<input type="submit" value="確定" />
<input type="submit" value="取消" />
</form>
</dialog>
在默認形式下,該元素創(chuàng)建一個灰色背景,其下方是非交互式內(nèi)容。
可以在 <dialog> 其中的表單上使用一種方法,該方法將發(fā)送值并將其傳遞回自身 <dialog>。
總的來說,這個標簽在用戶交互和改進的界面中變得有益。
可以通過更改 <dialog> 標簽的 open 屬性以控制打開和關(guān)閉。
<dialog open>
<p>組件內(nèi)容</p>
</dialog>
FutureClaw 雜志主編 Bobby Mozumder 建議:
將錨元素鏈接到 JSON/XML、API 端點,讓瀏覽器在內(nèi)部將數(shù)據(jù)加載到新的數(shù)據(jù)結(jié)構(gòu)中,然后瀏覽器將 DOM 元素替換為根據(jù)需要加載的任何數(shù)據(jù)。初始數(shù)據(jù)(以及標準錯誤響應(yīng))可以放在標題裝置中,如果需要,可以稍后替換。
據(jù)他介紹,這是單頁應(yīng)用程序網(wǎng)頁設(shè)計模式,可以提高響應(yīng)速度和加載時間,因為不需要加載 JavaScript。
這個是一個比較有意思的提案,就有點類似我們以前沒有做前后端分離之前的混合編程的模式,HTML變成模板語言,通過JSON API請求數(shù)據(jù),不一樣的是變成瀏覽器來默認解析,瀏覽器內(nèi)部加載數(shù)據(jù)到新的數(shù)據(jù)結(jié)構(gòu)中,然后瀏覽器將按需加載到的數(shù)據(jù)替換成 DOM 元素。
大家可以看一下InfoQ上的這篇文章《針對非正式 HTML6 提案“無需 JavaScript 的單頁應(yīng)用”引發(fā)的論戰(zhàn)》,了解更多!
https://www.infoq.cn/article/2015/03/html6-without-javascript
HTML6 愛好者相信即將到來的更新將允許瀏覽器調(diào)整圖像大小以獲得更好的觀看體驗。
每個瀏覽器都難以呈現(xiàn)相對于設(shè)備和屏幕尺寸的最佳圖像尺寸,不幸的是,src 標簽 img 在處理這個問題時不是很有效。
這個問題可以通過一個新標簽 <srcset> 來解決,它使瀏覽器在多個圖像之間進行選擇的工作變得更加容易。
將可用庫引入 HTML6 絕對是提高開發(fā)效率的重要一步。
很多時候,需要在互聯(lián)網(wǎng)上定義一般信息,而這些一般信息可以是任何公開的信息,例如電話號碼、姓名、地址等。微格式是能夠定義一般數(shù)據(jù)的標準。微格式可以增強設(shè)計者的能力,并可以減少搜索引擎推斷公共信息所需的努力。
盡管標簽<ul>、<ol>非常有用,但在某些情況下仍有一些不足之處。可以處理交互元素的標簽將是一個不錯的選擇。
這就是創(chuàng)建標簽 <menu> 的驅(qū)動力,它可以處理按鈕驅(qū)動的列表元素。
<menu type="toolbar">
<li><button>個人信息</button></li>
<li><button>系統(tǒng)設(shè)置</button></li>
<li><button>賬號注銷</button></li>
</menu>
因此 <menu>,除了能夠像普通列表一樣運行之外,還可以增強 HTML 列表的功能。
雖然HTML5在安全性方面還不錯,瀏覽器和網(wǎng)絡(luò)技術(shù)也提供了合理的保護。毫無疑問,在身份驗證和安全領(lǐng)域還有很多事情可以做。如密鑰可以異地存儲;這將防止不受歡迎的人訪問并支持身份驗證。使用嵌入式密鑰而不是 cookie,使數(shù)字簽名更好等。
HTML6 允許以更好的方式使用設(shè)備上的相機和媒體。將能夠控制相機、它的效果、模式、全景圖像、HDR 和其他屬性。
沒有什么是完美的,HTML 也不是完美的,所以 HTML 規(guī)范可以做很多事情來使它更好。應(yīng)該對一些有用的規(guī)范進行標準化,以增強 HTML 的能力。小的變化已經(jīng)開始推出。如增強藍牙支持、p2p 文件傳輸、惡意軟件保護、云存儲集成,下一個 HTML 版本可以考慮一下。
解決企業(yè)“注銷難”的問題,市市場監(jiān)管局說:今天,上海市注銷企業(yè)“一窗通”網(wǎng)上平臺正式上線→企業(yè)填報注銷申請信息后,平臺同步推送給市場監(jiān)管、稅務(wù)、人社、商務(wù)、海關(guān)、人民銀行、外管等行政部門以及人民法院等司法部門,各部門并聯(lián)預(yù)審辦理,提高效率。平臺還提供銀行賬戶撤銷的預(yù)約服務(wù)功能和在國家企業(yè)信用信息公示系統(tǒng)免費發(fā)布注銷公告的功能。怎么使用?看過來↓
企業(yè)注銷流程再造
企業(yè)填報注銷申請信息后,平臺同步推送給各相關(guān)部門,各部門并聯(lián)預(yù)審辦理。平臺引導(dǎo)企業(yè)按照最優(yōu)方案辦理注銷,幫助申請人了解各項業(yè)務(wù)的前后辦理關(guān)系。平臺還提供銀行賬戶撤銷的預(yù)約服務(wù)功能,幫助企業(yè)縮短注銷銀行賬戶的辦理時間。
注銷企業(yè)“一窗通”網(wǎng)上平臺現(xiàn)有2個入口:
第一個入口:上海市人民政府官網(wǎng)“中國上海”網(wǎng)站
(http://www.shanghai.gov.cn/)首頁上點擊“一網(wǎng)通辦”
然后可以在第二個頁面的“優(yōu)化營商環(huán)境”欄目下找到“企業(yè)注銷”按鈕
第二個入口:上海市市場監(jiān)管局官網(wǎng)上的專欄通道
(http://www.sgs.gov.cn/shaic/index_new.html)
企業(yè)注銷規(guī)范透明
平臺為注銷申請人集中提供各部門辦理指南、結(jié)果反饋、全流程進度跟蹤等電子政務(wù)服務(wù),及時告知企業(yè)辦理流程、辦理要求和進度情況,督促各業(yè)務(wù)部門按照規(guī)定時限和要求完成注銷業(yè)務(wù)程序,進一步實現(xiàn)注銷流程的規(guī)范化、法治化。
企業(yè)注銷便捷高效
通過平臺的信息互通共享,各部門可從平臺獲取企業(yè)信息和部門辦理結(jié)果,從而簡化數(shù)據(jù)填報采集和材料提交要求,優(yōu)化辦理流程。
海關(guān)、人力資源社會保障部門可以利用注銷平臺,通過數(shù)據(jù)校驗和信息共享實現(xiàn)網(wǎng)上辦理;市場監(jiān)管部門可以實現(xiàn)各類申請文書材料的自動生成,進一步壓縮注銷登記辦理時間;稅務(wù)等部門可以實現(xiàn)預(yù)審并出具個性化“診斷書”,告知企業(yè)是否符合稅務(wù)免辦或即辦條件,減少和簡化材料提交的數(shù)量和要求。
此外,平臺還為企業(yè)提供了在國家企業(yè)信用信息公示系統(tǒng)上免費發(fā)布注銷公告的功能。
企業(yè)注銷智能增效
平臺通過和多個企業(yè)數(shù)據(jù)庫的對接,實現(xiàn)智能比對篩選,對企業(yè)注銷申請進行分類處置,進一步提升辦理效率:
符合簡易注銷登記條件的企業(yè),可進入國家企業(yè)信用信息公示系統(tǒng)辦理簡易注銷,并可在平臺上查看簡易注銷辦理進度。
對其他企業(yè)提出的注銷申請,平臺將相關(guān)申請信息同步發(fā)送給各相關(guān)業(yè)務(wù)部門,各部門進行預(yù)審,按照各自要求對注銷企業(yè)實行分類處理。對于可通過數(shù)據(jù)共享即時辦結(jié)的,業(yè)務(wù)系統(tǒng)實時反饋平臺;對于不適用線上直接辦理的,根據(jù)企業(yè)情況出具“診斷書”,將辦理本部門注銷所需提交的材料、辦理要求、聯(lián)系方式等信息通過平臺和短信反饋給企業(yè)。通過清單式告知方式,實現(xiàn)窗口辦事“一口清”。
資料:市市場監(jiān)管局
編輯:景雯
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。