分类
Spring Security

Spring Security 表达式 – hasRole 简介

Spring Security Expressions – hasRole Example

1. 概述

Spring Security使用强大的Spring Expreession Language(SpEL)提供了多种表达式。这些表达式大多都是围绕应用上下文(当前的登录用户)实现的。

Spring Security表达式均是由SecurityExpressionRoot实现的,它是web安全以及在方法上加入验证的基础。

Spring Security 3.0的授权机制中开始使用了SpEL表达式,Spring Security 4.x中沿用了这一机制。你可以在本文中找到关于Spring Security表达式的更多内容。

2. 网站授权(Web Authorization)

Spring Security提供了两个web授权方法:基于URL对整个页面进行授权以及基于安全规则对某个页面的部分内容进行授权。

2.1 对整个页面授权

使用JAVA的配置方式如下:

@Configuration
@EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .authorizeRequests()
          .antMatchers("/admin/**").hasRole("ADMIN");
    }
    ...
}

注意:Spring Security将为hasRole中的ADMIN自动添加ROLE_前缀。

当用户访问的URL匹配到/admin/**hasRole表达式将校验当前登录用户是否拥有ROLE_ADMIN角色。

2.2 对页面中的部分进行授权

第二种授权方式是基于安全表达式对页面的部分进行授权。

2.2.1 JSP

如果使用的JSP技术,则该功能需要以下 Spring Security JSP taglib依赖的支持:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>

使用以下代码来启用taglib支持:

<%@ taglib prefix="security"
  uri="http://www.springframework.org/security/tags" %>

此时便可以在当前页面中使用hasRole表达式了。以下代码展示了:当认证用户拥有ROLE_USER时,将显示第一段文字;拥有ROLE_ADMIN时,将显示第二段文字:

<security:authorize access="hasRole('ROLE_USER')">
    This text is only visible to a user
    <br/>
</security:authorize>
<security:authorize access="hasRole('ROLE_ADMIN')">
    This text is only visible to an admin
    <br/>
</security:authorize>

由于笔者没有使用JSP技术的相关经验,所以以上代码未验证。同时,笔者也没有能力在github仓库中提供相应的JSP示例。

2.2.2 thymeleaf

thymeleaf启用页面部分认证需要加入以下依赖:

		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-springsecurity5</artifactId>
		</dependency>

在模板中的使用方法如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>hasRole在Thymeleaf中的应用</title>
</head>
<body>
<h2>Welcome</h2>
<p>hasRole在Thymeleaf中的应用</p>
<div sec:authorize="hasRole('USER')">user 角色能够查看到此信息</div>
<div sec:authorize="hasRole('ADMIN')">admin 用户能够看到此信息.</div>
<div sec:authorize="isAuthenticated()">
    登录用户能看到此信息
</div>
当前登录的用户是:
<div sec:authentication="name"></div>
如未登录,可以通过访问/admin/test来模拟登录,如想变更登录用户需要重新打开浏览器并重新启动后台。
</body>
</html>

上述代码在模板中应用了hasRole表达式,达到了特定的用户显示特定的信息的目的。

3. 方法级别的授权 - @PreAuthorize

能过特定的注解,Security表达式能够对特定的方法进行授权

@PreAuthorize以及@PostAuthorize (还包含@PreFilter 和 @PostFilter) 注解支持Spring Expression Language(SpEL)并实现了认证授权。

预使上述注解生效,需要使用@EnableGlobalMethodSecurity对Spring Security进行如下配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    ...
}

XML配置如下:

<global-method-security pre-post-annotations="enabled" />

接下来,便可以在方法中使用 @PreAuthorize 注解了:

@Service
public class FooService {
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public List<Foo> findAll() { ... }
    ...
}

如此以来,只有拥有ROLE_ADMIN的登录用户才能够成功的访问findAll方法。

注意:@PreAuthorize 以及 @PostAuthorize 是基于代理机制生效的,这意味着使用该注解的方法不能够被声明为final,并且其类型必须为public。

4. 在代码中校验角色

可以在JAVA代码直接对当前登录用户的角色进行判断:

@RequestMapping
public boolean someControllerMethod(HttpServletRequest request) {
    return request.isUserInRole("ROLE_ADMIN");
}

上述代码实现了将接收到一个当前登录用户是否拥有ROLE_ADMIN角色的boolean值。

5. 总结

本文对hasRole表达式的几种使用方法进行了介绍,你学会了吗?