方法级别的安全

我们在hello-world-test的基础上,我们新建了一个名为method-security的 Gradle 项目。

本项目用于演示方法级别的安全设置。

build.gradle

修改 build.gradle 文件,让我们的method-security项目成为一个新的项目。

修改内容也比较简单,修改项目名称及版本即可。

jar {
    baseName = 'method-security'
    version = '1.0.0'
}

编写服务类

创建com.waylau.spring.boot.security.service包,用于放置服务类。创建了 UserService 接口。接口比较简单,主要是用于查询和删除:

public interface UserService {
    void removeUser(Long id);
    List<User> listUsers();
}

UserServiceImpl 是 UserService 接口的实现,在内存里面模拟了 User 的存储库。

@Service
public class UserServiceImpl implements UserService {
    private static final Map<Long,User> userRepository = new ConcurrentHashMap<>();
    public UserServiceImpl(){
        userRepository.put(1L, new User(1L, "waylau", 30));
        userRepository.put(2L, new User(2L,"老卫", 29));
        userRepository.put(3L, new User(3L,"doufe", 109));
    }
    @Override
    public void removeUser(Long id) {
        userRepository.remove(id);
    }
    @Override
    public List<User> listUsers() {
        List<User> users = null;
        users = new ArrayList<User>(userRepository.values());
        return users;
    }
}

控制器

在 UserController 中,增加了删除用户的方法:

@PreAuthorize("hasAuthority('ROLE_ADMIN')")  // 指定角色权限才能操作方法
@GetMapping(value = "delete/{id}")
public ModelAndView delete(@PathVariable("id") Long id, Model model) {
    userService.removeUser(id);
    model.addAttribute("userList", userService.listUsers());
    model.addAttribute("title", "删除用户");
    return new ModelAndView("users/list", "userModel", model);
}

其中,我们使用了 @PreAuthorize注解。

配置类

在配置类上,我们加上了一个注解 @EnableGlobalMethodSecurity

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)  // 启用方法安全设置
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    ......
}

注意:@EnableGlobalMethodSecurity 可以配置多个参数:

  • prePostEnabled :决定 Spring Security 的前注解是否可用@PreAuthorize@PostAuthorize
  • secureEnabled : 决定是否Spring Security的保障注解 @Secured是否可用
  • jsr250Enabled :决定 JSR-250 注解@RolesAllowed等是否可用.

配置方式分别如下:

@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig {
// ...
}
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class MethodSecurityConfig {
// ...
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
// ...
}

在同一个应用程序中,可以启用多个类型的注解,但是只应该设置一个注解对于行为类的接口或者类。如果将2个注解同事应用于某一特定方法,则只有其中一个将被应用。

@Secured

此注释是用来定义业务方法的安全配置属性的列表。您可以在需要安全角色/权限等的方法上指定 @Secured,并且只有那些角色/权限的用户才可以调用该方法。如果有人不具备要求的角色/权限但试图调用此方法,将会抛出 AccessDenied 异常。

@Secured 源于 Spring之前版本.它有一个局限就是不支持 Spring EL 表达式。可以看看下面的例子:

如果你想指定AND(和)这个条件,我的意思说deleteUser 方法只能被同时拥有ADMIN & DBA 。但是仅仅通过使用@Secured注解是无法实现的。

但是你可以使用Spring的新的注解@PreAuthorize/@PostAuthorize(支持Spring EL),使得实现上面的功能成为可能,而且无限制。

@PreAuthorize/@PostAuthorize

Spring的 @PreAuthorize/@PostAuthorize 注解更适合方法级的安全,也支持Spring EL 表达式语言,提供了基于表达式的访问控制。

  • @PreAuthorize 注解:适合进入方法前的权限验证, @PreAuthorize 可以将登录用户的角色/权限参数传到方法中。
  • @PostAuthorize 注解:使用并不多,在方法执行后再进行权限验证。

运行

运行项目,我们查看下最终的效果:

fangfajibiedeanquan\_1.png

我们用“USER”角色权限可以查看用户列表,但如果想删除用户,则提示“访问拒绝”。

根据权限来显示或者隐藏操作

实际上,如果用户不具备某个操作的权限,那么那个操作按钮就不应该显示出来。我们可以使用sec:authorize属性能达到这个目的。

修改list.html 中的表格:

......
<table class="table table-hover">
    <thead>
    <tr>
        <td>ID</td>
        <td>Age</td>
        <td>Name</td>
        <td sec:authorize="hasRole('ADMIN')">Operation</td>
    </tr>
    </thead>
    <tbody>
    <tr th:if="${userModel.userList.size()} eq 0">
        <td colspan="3">没有用户信息!!</td>
    </tr>
    <tr th:each="user : ${userModel.userList}">
        <td th:text="${user.id}">1</td>
        <td th:text="${user.age}">11</td>
        <td th:text="${user.name}">waylau</a></td>
        <td sec:authorize="hasRole('ADMIN')">
            <div >
                <a th:href="@{'/users/delete/' + ${user.id}}">
                    <i class="fa fa-times" aria-hidden="true"></i>
                </a>
               </div>
        </td>
    </tr>
    </tbody>
</table>
......

我们使用了<td sec:authorize="hasRole('ADMIN')">这样,只要是具备“ADMIN”权限的用户就能看到删除操作列,否则就看不到那一列的删除操作。效果如下:

不具备“ADMIN”权限的用户:

fangfajibiedeanquan\_2.png

具备“ADMIN”权限的用户:

fangfajibiedeanquan\_3.png

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「方志朋」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

results matching ""

    No results matching ""