# 14.1.1　使用 @Secured 注解限制方法调用

在 Spring 中，如果要启用基于注解的方法安全性，关键之处在于要在配置类上使用 @EnableGlobalMethodSecurity，如下所示：

```java
@Configuration
@EnableGlobalMethodSecurity(securedEnabled=true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
```

除了使用 @EnableGlobalMethodSecurity 注解，我们可能也注 意到配置类扩展了 GlobalMethodSecurityConfiguration。在第 9 章中，Web 安全的配置类扩展了 WebSecurityConfigurerAdapter，与之类似，这个类能够为方法级别的安全性提供更精细的配置。

例如，如果我们在 Web 层的安全配置中设置认证，那么可以通过重载 GlobalMethodSecurityConfiguration 的 configure() 方法实现该功能：

```java
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  auth.inMemoryAuthentication()
      .withUser("user").password("password").role("USER");
}
```

在本章稍后的 14.2.2 小节中，我们将会看到如何重载 GlobalMethodSecurityConfiguration 的 createExpressionHandler() 方法，提供一些自定义的安全表达式处理行为。

让我们回到 @EnableGlobalMethodSecurity 注解，注意它的 securedEnabled 属性设置成了 true。如果 securedEnabled 属性的值为 true 的话，将会创建一个切点，这样的话 Spring Security 切面就会包装带有 @Secured 注解的方法。例如，考虑如下这个带有 @Secured 注解的 addSpittle() 方法：

```java
@Secured("ROLE_SPITTER")
public void addSpittle(Spittle spittle) {
  // ...
}
```

@Secured 注解会使用一个 String 数组作为参数。每个 String 值是一个权限，调用这个方法至少需要具备其中的一个权限。通过传递进来 ROLE\_SPITTER，我们告诉 Spring Security 只允许具有 ROLE\_SPITTER 权限的认证用户才能调用 addSpittle() 方法。

如果传递给 @Secured 多个权限值，认证用户必须至少具备其中的一个才能进行方法的调用。例如，下面使用 @Secured 的方式表明用户必须具备 ROLE\_SPITTER 或 ROLE\_ADMIN 权限才能触发这个方法：

```java
@Secured({"ROLE_SPITTER", "ROLE_ADMIN"})
public void addSpittle(Spittle spittle) {
  // ...
}
```

如果方法被没有认证的用户或没有所需权限的用户调用，保护这个方法的切面将抛出一个 Spring Security 异常（可能是 AuthenticationException 或 AccessDeniedException 的子类）。它们是非检查型异常，但这个异常最终必须要被捕获和处理。如果被保护的方法是在 Web 请求中调用的，这个异常会被 Spring Security 的过滤器自动处理。否则的话，你需要编写代码来处理这个异常。

@Secured 注解的不足之处在于它是 Spring 特定的注解。如果更倾向于使用 Java 标准定义的注解，那么你应该考虑使用 @RolesAllowed 注解。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://potoyang.gitbook.io/spring-in-action-v4/untitled-8/untitled-2/untitled-1.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
