Spring Security 表达式 Expressions 详解

1. 介绍

  • 本文主要是关注于Spring Security的表达式。会有很多案例给大家演示一下怎么使用这些表达式
  • 掌握了Spring Security表达式,会让你很灵活地实现复杂的ACL控制规则

2. Maven 依赖

  • 想要使用Spring Security,你需要再pom.xml中加入以下的内容。
<dependencies>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>4.1.1.RELEASE</version>
    </dependency>
</dependencies>
  • 最新的版本可以点击这里查看

  • 温馨提示:这里只是包含了Spring Security的依赖,不要忘记把spring-corespring-context的依赖都加进去

3. 配置

  • 首先,我们先新建一个Java配置类SecurityWithoutCsrfConfig

  • 该类需要继承WebSecurityConfigurerAdapter,这里我们就可以使用该基类所提供的方法。具体代码如下:

@Configuration
@EnableAutoConfiguration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityWithoutCsrfConfig extends WebSecurityConfigurerAdapter {
    ...
}
  • 我们也可以通过XML的方式进行配置,不过不推荐。实例代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans ...>
    <global-method-security pre-post-annotations="enabled"/>
</beans:beans>

4. 表达式讲解

  • 下面是我们可能会用到的表达式:

hasRole, hasAnyRole
hasAuthority, hasAnyAuthority
permitAll, denyAll
isAnonymous, isRememberMe, isAuthenticated, isFullyAuthenticated
principal, authentication
hasPermission

  • 接下来我们回详细地介绍每个表达式的使用。

4.1. hasRole, hasAnyRole

  • 这些表达式负责定义应用程序中特定URL或方法的访问控制或授权。
  • 下面是具体的写法:
@Override
protected void configure(final HttpSecurity http) throws Exception {
    ...
    .antMatchers("/auth/admin/*").hasRole("ADMIN")
    .antMatchers("/auth/*").hasAnyRole("ADMIN","USER")
    ...
}
  • 在此示例中,我们指定对以/auth/开头的所有链接进行访问权限的限制,只有角色USER或角色ADMIN登录的用户有访问权限。此外,要访问以/auth/admin/开头的链接,我们需要在系统中具有ADMIN角色。

  • 在XML中可以进行一下的配置:

<http>
    <intercept-url pattern="/auth/admin/*" access="hasRole('ADMIN')"/>
    <intercept-url pattern="/auth/*" access="hasAnyRole('ADMIN','USER')"/>
</http>

4.2. hasAuthority, hasAnyAuthority

  • RolesAuthoritiesSpring中是很相似的

  • 主要区别在于,角色具有特殊的语义 - 从Spring Security 4开始,任何与角色相关的方法都会自动添加ROLE_前缀。

  • hasAuthority('ROLE_ADMIN')类似于hasRole('ADMIN'),因为ROLE_前缀会自动添加。

  • 我们使用authorities来赋予用户权限的时候,比较大的好处是我们不必使用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表达式来限定权限
@Override
protected void configure(final HttpSecurity http) throws Exception {
    ...
    .antMatchers("/auth/admin/*").hasAuthority("ADMIN")
    .antMatchers("/auth/*").hasAnyAuthority("ADMIN", "USER")
    ...
}
  • 我们可以看到,这里是没有出现到roles相关的配置。
  • 可以通过一下方式来配置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

  • 这是两个比较简单的方法,要么就是拒绝指定的所有请求,要么就是允许指定的所有请求。

  • 示例:

...
.antMatchers("/*").permitAll()
...
  • 使用此配置,我们将授权所有用户(匿名用户和登录用户)访问以'/'开头的页面。

  • 我们也可以拒绝访问整个网站,代码如下:

...
.antMatchers("/*").denyAll()
...
  • 以下的XML配置可以达到同样的效果。
<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

  • 在本小节中,我们将重点关注与用户登录状态相关的表达式。我们从没有登录页面的用户开始。通过在Java配置中指定以下内容,我们允许所有未经授权的用户访问我们的主页:
...
.antMatchers("/*").anonymous()
...
  • XML配置如下:
<http>
    <intercept-url pattern="/*" access="isAnonymous()"/>
</http>
  • 如果希望访问网站的都需要登录,那么我们可以使用isAuthenticated()方案进行以下的配置:
...
.antMatchers("/*").authenticated()
...
  • or XML version:
  • XML版本如下:
<http>
    <intercept-url pattern="/*" access="isAuthenticated()"/>
</http>
  • 此外,我们还有两个表达式,isRememberMe()和isFullyAuthenticated()。通过使用cookie,Spring可以实现存储功能,因此无需每次都登录系统。
  • 为了能够访问仅通过记住我的功能登录的用户,我们可以使用:
...
.antMatchers("/*").rememberMe()
...
  • XML版本如下:
<http>
    <intercept-url pattern="*" access="isRememberMe()"/>
</http>
  • 最后,即使用户已经登录,我们有时候想要求用户再次进行身份验证。例如,用户想要更改设置或付款信息。

  • 为了做到这一点,我们可以指定isFullyAuthenticated(),如果用户不是匿名用户或记住我的用户,则返回true:

...
.antMatchers("/*").fullyAuthenticated()
...
  • XML版本
<http>
    <intercept-url pattern="*" access="isFullyAuthenticated()"/>
</http>

4.5. principal, authentication

  • 这些表达式允许分别从SecurityContextrespectively表示当前授权(或匿名)用户的principal对象和当前的Authentication对象

  • 例如,我们可以使用委托人来加载用户的电子邮件,头像或登录用户可访问的任何其他数据。

  • 身份验证提供有关完整身份验证对象的信息及其授予的权限

4.6. hasPermission APIs

  • 如表达式已经设置在了Spring Security的ACL系统中,系统是允许我们根据抽象权限指定对各个域对象的授权约束。

  • 让我们来看一个例子。我们有一项服务,允许合作撰写文章,与主编辑,决定其他作者提出的文章应该发表

  • 为了允许使用此类服务​​,我们可以使用访问控制方法创建以下方法:

@PreAuthorize("hasPermission(#articleId, 'isEditor')")
public void acceptArticle(Article article) {
   …
}
  • 只有授权的用户可以在服务中调用此方法
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容