Spring Boot项目添加Shiro做权限管理

1.添加shiro依赖

pom.xml

		<!--Shiro框架-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.3</version>
        </dependency>
        <!--Thymeleaf关于Shiro框架-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

2.实体类

User类

@TableName("t_user")
public class User {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    private String username;

    private String password;

    private Integer roleId;

    private Integer isEnable;

    private Date createTime;

    @TableField(exist = false)
    private Role role;
    // SET/GET省略
}

Role类

@TableName("t_role")
public class Role {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @TableField(value = "roleKey")
    private String roleKey;

    @TableField(value = "roleName")
    private String roleName;

    @TableField(exist = false)
    private List<Permission> permissionList;
    // SET/GET省略
}    

Permission类

@TableName("t_permission")
public class Permission {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    private String permissionKey;

    @TableField(value = "permissionName")
    private String title;

    /**
     * 父节点ID
     */
    private Integer pId;

    /**
     * 节点集合
     */
    @TableField(exist = false)
    private List<Permission> children = new ArrayList<>();

    /**
     * 是否被选中
     */
    @TableField(exist = false)
    private Boolean checked = false;
    // SET/GET省略
}    

3.添加UserRealm

UserRealm

public class UserRealm extends AuthorizingRealm {
    @Autowired
    IUserService userService;

    /**
     * 登录后授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取Subject
        Subject subject = SecurityUtils.getSubject();
        User user = (User)subject.getPrincipal();
        // 根据username从数据库中查询角色和权限
        User userRolePermission = userService.getUserRolePermissionByUsername(user.getUsername());

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        List<String> roleList = new ArrayList<>();
        // 往Shiro框架中添加角色集合
        roleList.add(userRolePermission.getRole().getRoleKey());
        simpleAuthorizationInfo.addRoles(roleList);

        // 往Shiro框架中添加权限集合
        List<String> permissionList = new ArrayList<>();
        for (Permission permission:userRolePermission.getRole().getPermissionList()) {
            permissionList.add(permission.getPermissionKey());
        }
        simpleAuthorizationInfo.addStringPermissions(permissionList);

        return simpleAuthorizationInfo;
    }
    /**
     * 登录时身份验证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        // 根据用户名查询用户
        User user = userService.getUserByUsername(token.getUsername());
        if (user == null) {
            // 用户不存在时抛出异常
            throw new UnknownAccountException();
        } else {
            user = userService.getUserById(user.getId());
            // 根据ID二次验证
            if (user == null) {
                // 根据用户ID查询用户不存在时,抛出登录认证异常
                throw new AuthenticationException();
            }
        }
        ByteSource byteSource = ByteSource.Util.bytes(user.getUsername());
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), byteSource, getName());

        return simpleAuthenticationInfo;
    }
}

4.Shiro配置类

ShiroConfig配置类

@Configuration
public class ShiroConfig {

    /**
     * 创建自定义 realm
     *
     * @return
     */
    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }

    /**
     * 创建 securityManager 安全管理对象
     */
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm());
        return securityManager;
    }

    /**
     * Filter工厂, 设置对应的过滤条件和跳转条件
     *
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        /**
         * anon: 匿名用户可访问
         * authc: 认证用户可访问
         * user: 使用rememberMe可访问
         * perms: 对应权限可访问
         * role: 对应角色权限可访问
         */
        Map<String, String> map = new HashMap<>();
        // 静态资源放行
        //map.put("/static/**", "anon");
        //map.put("/css/**", "anon");
        //map.put("/lib/**", "anon");
        //map.put("/js/**", "anon");
        //map.put("/images/**", "anon");
        // 转向登陆页面
        //map.put("/user/toLogin","anon");
        // 登陆动作
        //map.put("/user/login", "anon");
        // 对登录跳转接口进行释放
        //map.put("/error", "anon");
        // 对所有用户认证
        //map.put("/**", "authc");
        // 登出
        //map.put("/logout", "logout");

        // 登录
        // 注意:这里配置的 /toLogin 是指到 @RequestMapping(value="/toLogin")中的 /toLogin
        //shiroFilterFactoryBean.setLoginUrl("/user/toLogin");
        // 首页
        //shiroFilterFactoryBean.setSuccessUrl("/index");
        // 错误页面,认证不通过跳转
        //shiroFilterFactoryBean.setUnauthorizedUrl("/error/unAuth");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        return shiroFilterFactoryBean;
    }

    /**
     * 加入注解的使用,不加这个,注解不生效
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 跟上面的注解配置搭配使用,有时候加了上面的配置后注解不生效,需要加入下面的配置
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 在模板中使用shiro标签
     * @return
     */
    @Bean(name = "shiroDialect")
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }
}

5.登录验证

UserController

@RestController
@RequestMapping("/user")
public class UserController {
	/**
     * 日志
     */
    private static Logger logger = LoggerFactory.getLogger(UserController.class);
	/**
     * 登录
     * @param user
     * @return
     */
    @RequestMapping("/login")
    public Map login(User user) {
        logger.info("执行登录方法 用户名:" + user.getUsername() + "\t" + "密码:" + user.getPassword());
        Map<String, String> map = new HashMap<>(1);
        // 1.获取Subject
        Subject subject = SecurityUtils.getSubject();
        // 2.封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
        // 3.执行shiro的login方法--会自动调用Realm中的认证方法doGetAuthenticationInfo
        try {
            subject.login(token);
            map.put("flag", "1");
        } catch (UnknownAccountException e) {
            logger.info("没有此账号");
            map.put("flag", "-1");
        } catch (IncorrectCredentialsException e) {
            logger.info("密码错误");
            map.put("flag", "-2");
        } catch (AuthenticationException e) {
            logger.info("认证失败");
            map.put("flag", "-3");
        }
        return map;
    }
}

6.统一报错的信息页面

NoPermissionException

/**
 * 全局无权限异常处理类
 * @author:ChenXin
 * @date 2021/2/8 17:20
 */
@ControllerAdvice
public class NoPermissionException {
    /**
     * 授权失败, 就是说没有该权限
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(UnauthorizedException.class)
    public String handleShiroException(Exception e) {
        return "权限不足";
    }

    /**
     * 认证失败
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(AuthorizationException.class)
    public String authorizationException(Exception e) {
        return "权限认证失败";
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ww空ww

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值