1. 介紹
- 本文主要是關(guān)注于
Spring Security的表達(dá)式。會(huì)有很多案例給大家演示一下怎么使用這些表達(dá)式 - 掌握了
Spring Security表達(dá)式,會(huì)讓你很靈活地實(shí)現(xiàn)復(fù)雜的ACL控制規(guī)則
2. Maven 依賴(lài)
- 想要使用
Spring Security,你需要再pom.xml中加入以下的內(nèi)容。
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.1.1.RELEASE</version>
</dependency>
</dependencies>
最新的版本可以點(diǎn)擊這里查看
溫馨提示:這里只是包含了
Spring Security的依賴(lài),不要忘記把spring-core和spring-context的依賴(lài)都加進(jìn)去
3. 配置
首先,我們先新建一個(gè)Java配置類(lèi)
SecurityWithoutCsrfConfig該類(lèi)需要繼承
WebSecurityConfigurerAdapter,這里我們就可以使用該基類(lèi)所提供的方法。具體代碼如下:
@Configuration
@EnableAutoConfiguration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityWithoutCsrfConfig extends WebSecurityConfigurerAdapter {
...
}
- 我們也可以通過(guò)XML的方式進(jìn)行配置,不過(guò)不推薦。實(shí)例代碼如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans ...>
<global-method-security pre-post-annotations="enabled"/>
</beans:beans>
4. 表達(dá)式講解
- 下面是我們可能會(huì)用到的表達(dá)式:
hasRole, hasAnyRole
hasAuthority, hasAnyAuthority
permitAll, denyAll
isAnonymous, isRememberMe, isAuthenticated, isFullyAuthenticated
principal, authentication
hasPermission
- 接下來(lái)我們回詳細(xì)地介紹每個(gè)表達(dá)式的使用。
4.1. hasRole, hasAnyRole
- 這些表達(dá)式負(fù)責(zé)定義應(yīng)用程序中特定URL或方法的訪問(wèn)控制或授權(quán)。
- 下面是具體的寫(xiě)法:
@Override
protected void configure(final HttpSecurity http) throws Exception {
...
.antMatchers("/auth/admin/*").hasRole("ADMIN")
.antMatchers("/auth/*").hasAnyRole("ADMIN","USER")
...
}
在此示例中,我們指定對(duì)以
/auth/開(kāi)頭的所有鏈接進(jìn)行訪問(wèn)權(quán)限的限制,只有角色USER或角色ADMIN登錄的用戶(hù)有訪問(wèn)權(quán)限。此外,要訪問(wèn)以/auth/admin/開(kāi)頭的鏈接,我們需要在系統(tǒng)中具有ADMIN角色。在XML中可以進(jìn)行一下的配置:
<http>
<intercept-url pattern="/auth/admin/*" access="hasRole('ADMIN')"/>
<intercept-url pattern="/auth/*" access="hasAnyRole('ADMIN','USER')"/>
</http>
4.2. hasAuthority, hasAnyAuthority
Roles和Authorities在Spring中是很相似的主要區(qū)別在于,角色具有特殊的語(yǔ)義 - 從
Spring Security 4開(kāi)始,任何與角色相關(guān)的方法都會(huì)自動(dòng)添加ROLE_前綴。hasAuthority('ROLE_ADMIN')類(lèi)似于hasRole('ADMIN'),因?yàn)?code>ROLE_前綴會(huì)自動(dòng)添加。我們使用
authorities來(lái)賦予用戶(hù)權(quán)限的時(shí)候,比較大的好處是我們不必使用ROLE_前綴。下面示例是使用
authorities的代碼
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1").password("user1Pass").authorities("USER")
.and().withUser("admin").password("adminPass").authorities("ADMIN");
}
- 我們可以使用一下
authorities表達(dá)式來(lái)限定權(quán)限
@Override
protected void configure(final HttpSecurity http) throws Exception {
...
.antMatchers("/auth/admin/*").hasAuthority("ADMIN")
.antMatchers("/auth/*").hasAnyAuthority("ADMIN", "USER")
...
}
- 我們可以看到,這里是沒(méi)有出現(xiàn)到
roles相關(guān)的配置。 - 可以通過(guò)一下方式來(lái)配置XML文件。
<authentication-manager>
<authentication-provider>
<user-service>
<user name="user1" password="user1Pass" authorities="ROLE_USER"/>
<user name="admin" password="adminPass" authorities="ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager>
<http>
<intercept-url pattern="/auth/admin/*" access="hasAuthority('ADMIN')"/>
<intercept-url pattern="/auth/*" access="hasAnyAuthority('ADMIN','USER')"/>
</http>
4.3. permitAll, denyAll
這是兩個(gè)比較簡(jiǎn)單的方法,要么就是拒絕指定的所有請(qǐng)求,要么就是允許指定的所有請(qǐng)求。
示例:
...
.antMatchers("/*").permitAll()
...
使用此配置,我們將授權(quán)所有用戶(hù)(匿名用戶(hù)和登錄用戶(hù))訪問(wèn)以
'/'開(kāi)頭的頁(yè)面。我們也可以拒絕訪問(wèn)整個(gè)網(wǎng)站,代碼如下:
...
.antMatchers("/*").denyAll()
...
- 以下的XML配置可以達(dá)到同樣的效果。
<http auto-config="true" use-expressions="true">
<intercept-url access="permitAll" pattern="/*" /> <!-- Choose only one -->
<intercept-url access="denyAll" pattern="/*" /> <!-- Choose only one -->
</http>
4.4. isAnonymous, isRememberMe, isAuthenticated, isFullyAuthenticated
- 在本小節(jié)中,我們將重點(diǎn)關(guān)注與用戶(hù)登錄狀態(tài)相關(guān)的表達(dá)式。我們從沒(méi)有登錄頁(yè)面的用戶(hù)開(kāi)始。通過(guò)在Java配置中指定以下內(nèi)容,我們?cè)试S所有未經(jīng)授權(quán)的用戶(hù)訪問(wèn)我們的主頁(yè):
...
.antMatchers("/*").anonymous()
...
- XML配置如下:
<http>
<intercept-url pattern="/*" access="isAnonymous()"/>
</http>
- 如果希望訪問(wèn)網(wǎng)站的都需要登錄,那么我們可以使用
isAuthenticated()方案進(jìn)行以下的配置:
...
.antMatchers("/*").authenticated()
...
- or XML version:
- XML版本如下:
<http>
<intercept-url pattern="/*" access="isAuthenticated()"/>
</http>
- 此外,我們還有兩個(gè)表達(dá)式,
isRememberMe()和isFullyAuthenticated()。通過(guò)使用cookie,Spring可以實(shí)現(xiàn)存儲(chǔ)功能,因此無(wú)需每次都登錄系統(tǒng)。 - 為了能夠訪問(wèn)僅通過(guò)
記住我的功能登錄的用戶(hù),我們可以使用:
...
.antMatchers("/*").rememberMe()
...
- XML版本如下:
<http>
<intercept-url pattern="*" access="isRememberMe()"/>
</http>
最后,即使用戶(hù)已經(jīng)登錄,我們有時(shí)候想要求用戶(hù)再次進(jìn)行身份驗(yàn)證。例如,用戶(hù)想要更改設(shè)置或付款信息。
為了做到這一點(diǎn),我們可以指定
isFullyAuthenticated(),如果用戶(hù)不是匿名用戶(hù)或記住我的用戶(hù),則返回true:
...
.antMatchers("/*").fullyAuthenticated()
...
- XML版本
<http>
<intercept-url pattern="*" access="isFullyAuthenticated()"/>
</http>
4.5. principal, authentication
這些表達(dá)式允許分別從
SecurityContext和respectively表示當(dāng)前授權(quán)(或匿名)用戶(hù)的principal對(duì)象和當(dāng)前的Authentication對(duì)象例如,我們可以使用委托人來(lái)加載用戶(hù)的電子郵件,頭像或登錄用戶(hù)可訪問(wèn)的任何其他數(shù)據(jù)。
身份驗(yàn)證提供有關(guān)完整身份驗(yàn)證對(duì)象的信息及其授予的權(quán)限
4.6. hasPermission APIs
如表達(dá)式已經(jīng)設(shè)置在了
Spring Security的ACL系統(tǒng)中,系統(tǒng)是允許我們根據(jù)抽象權(quán)限指定對(duì)各個(gè)域?qū)ο蟮氖跈?quán)約束。讓我們來(lái)看一個(gè)例子。我們有一項(xiàng)服務(wù),允許合作撰寫(xiě)文章,與主編輯,決定其他作者提出的文章應(yīng)該發(fā)表
為了允許使用此類(lèi)服務(wù)??,我們可以使用訪問(wèn)控制方法創(chuàng)建以下方法:
@PreAuthorize("hasPermission(#articleId, 'isEditor')")
public void acceptArticle(Article article) {
…
}
- 只有授權(quán)的用戶(hù)可以在服務(wù)中調(diào)用此方法