SpringBoot+Shiro:实现安全可靠的权限控制

534 阅读3分钟

介绍

在现代的Web应用程序中,安全性是至关重要的。为了保护用户的数据和应用程序的机密性,必须实现一些安全措施。其中之一是权限控制。权限控制是指限制用户可以访问哪些资源和执行哪些操作的过程。在本文中,我们将介绍如何使用SpringBoot和Shiro框架实现安全可靠的权限控制。

环境

  • JDK 1.8
  • SpringBoot 2.5.4
  • Shiro 1.7.1
  • Maven

实现步骤

步骤一:添加依赖

首先,我们需要在pom.xml文件中添加以下依赖:

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-starter</artifactId>
    <version>1.7.1</version>
</dependency>

步骤二:配置Shiro

接下来,我们需要在application.properties文件中添加以下配置:

# Shiro配置
shiro:
  # 登录URL
  loginUrl: /login
  # 登录成功后跳转的URL
  successUrl: /index
  # 未授权的URL
  unauthorizedUrl: /unauthorized
  # Shiro过滤器链配置
  filterChainDefinitions: /login=anon\n/logout=logout\n/**=authc

在这个配置中,我们定义了登录URL、登录成功后跳转的URL、未授权的URL和Shiro过滤器链配置。Shiro过滤器链配置定义了哪些URL需要进行身份验证和授权。

步骤三:实现身份验证

接下来,我们需要实现身份验证。我们可以通过实现Shiro的Realm接口来实现身份验证。Realm是Shiro用来获取安全数据(如用户、角色、权限等)的组件。我们可以通过实现Realm接口来自定义获取安全数据的方式。

public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        User user = (User) principalCollection.getPrimaryPrincipal();
        List<Role> roles = userService.getRolesByUserId(user.getId());
        for (Role role : roles) {
            authorizationInfo.addRole(role.getName());
            List<Permission> permissions = userService.getPermissionsByRoleId(role.getId());
            for (Permission permission : permissions) {
                authorizationInfo.addStringPermission(permission.getName());
            }
        }
        return authorizationInfo;
    }

    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        User user = userService.getUserByUsername(token.getUsername());
        if (user == null) {
            throw new UnknownAccountException("用户名或密码错误");
        }
        return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
    }
}

在这个实现中,我们重写了doGetAuthorizationInfo和doGetAuthenticationInfo方法。doGetAuthorizationInfo方法用于授权,doGetAuthenticationInfo方法用于身份验证。在doGetAuthorizationInfo方法中,我们获取用户的角色和权限,并将它们添加到SimpleAuthorizationInfo对象中。在doGetAuthenticationInfo方法中,我们获取用户的用户名和密码,并将它们添加到SimpleAuthenticationInfo对象中。

步骤四:实现授权

接下来,我们需要实现授权。我们可以通过在Controller中使用@RequiresPermissions注解来实现授权。@RequiresPermissions注解用于指定哪些权限可以访问该方法。

@RestController
public class UserController {

    @RequiresPermissions("user:list")
    @GetMapping("/users")
    public List<User> getUsers() {
        return userService.getUsers();
    }

    @RequiresPermissions("user:add")
    @PostMapping("/users")
    public void addUser(@RequestBody User user) {
        userService.addUser(user);
    }

    @RequiresPermissions("user:delete")
    @DeleteMapping("/users/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }

    @RequiresPermissions("user:update")
    @PutMapping("/users/{id}")
    public void updateUser(@PathVariable Long id, @RequestBody User user) {
        userService.updateUser(id, user);
    }
}

在这个实现中,我们在Controller中使用@RequiresPermissions注解来指定哪些权限可以访问该方法。例如,@RequiresPermissions(“user:list”)表示只有拥有"user:list"权限的用户才能访问getUsers方法。

步骤五:实现登录和注销

最后,我们需要实现登录和注销。我们可以通过在Controller中实现/login和/logout方法来实现登录和注销。

@Controller
public class LoginController {

    @GetMapping("/login")
    public String login() {
        return "login";
    }

    @PostMapping("/login")
    public String doLogin(String username, String password) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token);
            return "redirect:/index";
        } catch (AuthenticationException e) {
            return "redirect:/login?error";
        }
    }

    @GetMapping("/logout")
    public String logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "redirect:/login";
    }
}

在这个实现中,我们在Controller中实现/login和/logout方法来实现登录和注销。在doLogin方法中,我们获取用户名和密码,并使用UsernamePasswordToken对象来进行身份验证。如果身份验证成功,我们将用户重定向到/index页面。如果身份验证失败,我们将用户重定向到/login页面,并在URL中添加一个错误参数。在logout方法中,我们使用Subject对象来注销用户。

总结

在本文中,我们介绍了如何使用SpringBoot和Shiro框架实现安全可靠的权限控制。我们通过添加依赖、配置Shiro、实现身份验证、实现授权和实现登录和注销来实现权限控制。通过这些步骤,我们可以保护用户的数据和应用程序的机密性,使我们的Web应用程序更加安全可靠。