SpringBoot集成Shiro实现权限控制

Shiro简介

Apache Shiro是一个功能强大且易于使用的Java安全框架,用于执行身份验证,授权,加密和会话管理。使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序-从最小的移动应用程序到最大的Web和企业应用程序。

SpringBoot常用的权限管理框架主要有Shiro和Spring Security,相对来讲,Shiro的使用要更加简单。本文主要介绍SpringBoot与Shiro的集成与初步使用。

pom.xml引入

<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-spring</artifactId>
	<version>1.5.1</version>
</dependency>

LoginController

@RestController
public class LoginController {

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Results login(String username, String password){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        //是否记住用户
        //token.setRememberMe(true);
        
        // 执行登录方法
        // 无异常则判断为登录成功
        try{
            subject.login(token);
        }catch (UnknownAccountException e){
            return Results.failure(ResponseCode.NULL_USERNAME);
        }catch (IncorrectCredentialsException e){
            return Results.failure(ResponseCode.WRONG_PASSWORD);
        }
        return Results.success();
    }
}

Shiro中Subject代指用户对象,subject.login(token)既用户登录操作,这个方法将执行对应的认证与授权逻辑,它可能抛出两个异常:UnknownAccountException与IncorrectCredentialsException,分别为用户不存在和密码错误,无异常则判断登录成功。在这里我用自己的Results类对结果进行了封装。

ShiroConfig

@Configuration
public class ShiroConfig {

    //创建ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //设置SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        
        Map<String, String> filterMap = new LinkedHashMap<>();
        //无需登录
        filterMap.put("/login", "anon");

        //需要登录
        filterMap.put("/user/**", "authc");

        //需要特定权限
        filterMap.put("/druid/stat", "roles[druid]");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

        //修改认证失败的跳转页面
        shiroFilterFactoryBean.setLoginUrl("/401");
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        return shiroFilterFactoryBean;
    }

    //创建DefaultWebSecurityManager
    @Bean(name="securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    // 创建Realm
    @Bean(name="userRealm")
    public UserRealm getUserRealm(){
        return new UserRealm();
    }
}

Shiro通过ShiroFilterFactoryBean来实现对URL的权限过滤,ShiroFilterFactoryBean允许接收一个Map<String, String>用于设置过滤规则,该Map的键对应需要过滤的URL,可使用通配符。该Map的值对应过滤器,常用的过滤器有:

  1. anno:无需认证
  2. authc:需要认证
  3. user:使用RememberMe功能可以直接访问
  4. perms:该资源必须得到对应资源权限才可以访问
  5. roles:该资源必须得到对应角色权限才可以访问

我们通过传入自定义的Reaml来控制对不同用户的权限管理。

UserRealm

public class UserRealm extends AuthorizingRealm {

    @Autowired
    SysUserService sysUserService;

    private SysUser user;

    @Override
    //执行授权逻辑
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

			//根据用户身份授权
        if(user.getUsername().equals("zzZ")){
            info.addRole("druid");
            // info.addRoles(Permissions.adminPerms);
        }

        // 添加身份权限
//        info.addRole("structure:query");
        return info;
    }

    @Override
    //执行认证逻辑
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token1) throws AuthenticationException {

        UsernamePasswordToken token = (UsernamePasswordToken)token1;

        //查询数据库验证用户身份
        String currentUsername = token.getUsername();
        user = sysUserService.getSimpleUserByName(currentUsername);

        // 用户不存在
        if(user==null){return null; }

        String password = user.getPassword();
        return new SimpleAuthenticationInfo(user, password, "");
    }
}

编写一个自定义的UserRealm类用于执行认证与授权逻辑,这个类继承自AuthorizingRealm,重写了两个方法:

  1. doGetAuthorizationInfo: 用于执行授权逻辑
  2. doGetAuthenticationInfo: 用于执行认证逻辑,通常通过查询数据库实现。

获取当前用户

SysUser user = (SysUser) SecurityUtils.getSubject().getPrincipal();

通过SecurityUtils.getSubject()方法可以获取当前用户,在Service或Controller层中可以通过当前用户身份信息实现相关逻辑。

猜你喜欢

转载自www.cnblogs.com/2511zzZ/p/12654179.html