SpringBoot整合Shiro

SpringBoot整合Shiro,第1张

最近分配到一个新项目需要做用户角色权限这些模块所以来系统的学习了一下Shiro…

简介

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

Shiro

shiro是Apache下的一个开源项目,相较于SpringSecurity是一个轻量级的框架,主要特点是使用简单,对比SpringSecurity虽然功能没有那么的强大但也满足了基本的使用,我们可以不用一味的追求spring体系,而是可以根据项目的需求和学习成本做出选择。

核心架构

如下图片是官方架构图:

这里简述一下shiro的三大核心:
1、Subject 主体,可以把主体理解为用户
2、SecurityManager 安全管理器,它的作用就是管理所有的subject
3、Realm 域,它的作用就是做认证和授权 一般是有我们自定义实现
主要功能:
前面说到了shiro主要是做权限认证的,除此之外shiro还在密码加密、会话管理、缓存都用应用 有感兴趣的小伙伴可以自己去了解下,这里就不多做赘述…

Shiro的使用

引入shiro的依赖 这里我使用的版本是1.4.1,项目的框架是这样生成出来的,也是比较老的一个版本了 还是推荐大家使用新版本吧…

  			
            <dependency>
                <groupId>org.apache.shirogroupId>
                <artifactId>shiro-springartifactId>
                <version>${shiro-spring.version}version>
            dependency>
自定义 Realm和Shiro配置类
  • 自定义 Realm
package com.ych.service.shiro;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ych.pojo.entity.Permission;
import com.ych.pojo.entity.Role;
import com.ych.pojo.entity.RolePermissionRelation;
import com.ych.pojo.entity.User;
import com.ych.service.ych.PermissionService;
import com.ych.service.ych.RolePermissionRelationService;
import com.ych.service.ych.RoleService;
import com.ych.service.ych.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author 
 * date 2022-04-26
 */

public class CustomRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;
    @Autowired
    RoleService roleService;
    @Autowired
    PermissionService permissionService;
    @Autowired
    RolePermissionRelationService rolePermissionRelationService;

    /**
     * 权限配置
     * @param principalCollection  principalCollection
     * @return AuthorizationInfo
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取登录用户名
        String name = (String) principalCollection.getPrimaryPrincipal();
        //查询用户名称
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUserName,name);
        User user = userService.getOne(wrapper);
        //添加角色和权限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        String roleName = user.getRoleName();
        LambdaQueryWrapper<Role> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(Role::getName,roleName);
        Role role = roleService.getOne(roleWrapper);
        simpleAuthorizationInfo.addRole(role.getName());
        //添加权限
        BaseMapper<RolePermissionRelation> baseMapper = rolePermissionRelationService.getBaseMapper();
        LambdaQueryWrapper<RolePermissionRelation> relationWrapper = new LambdaQueryWrapper<>();
        relationWrapper.eq(RolePermissionRelation::getRid,role.getId());
        List<RolePermissionRelation> relations = baseMapper.selectList(relationWrapper);
        Set<String> permissions = new HashSet<>();
        relations.forEach(data->{
            LambdaQueryWrapper<Permission> permissionWrapper = new LambdaQueryWrapper<>();
            permissionWrapper.eq(Permission::getId,data.getPid());
            Permission permission = permissionService.getOne(permissionWrapper);
            permissions.add(permission.getName());
        });
        simpleAuthorizationInfo.setStringPermissions(permissions);
        return simpleAuthorizationInfo;
    }

    /**
     * 认证配置
     * @param authenticationToken authenticationToken
     * @return AuthenticationInfo
     * @throws AuthenticationException e
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        if (StringUtils.isEmpty(authenticationToken.getPrincipal())) {
            return null;
        }
        String username = (String) authenticationToken.getPrincipal();

        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUserName,username);
        User user = userService.getOne(wrapper);
        if (user == null) {
            //这里返回后会报出对应异常
            return null;
        } else {
            //这里验证authenticationToken和simpleAuthenticationInfo的信息
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, user.getPassword(), getName());
            return simpleAuthenticationInfo;
        }

    }
}

我们需要编写个自定义的Realm去继承AuthorizingRealm这个抽象类 并根据我们的需求重写doGetAuthorizationInfo(权限配置)和doGetAuthenticationInfo(认证)这个两个方法

  • ShiroConfig
package com.ych.service.shiro;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 
 * date 2022-04-26
 */
@Configuration
public class ShiroConfig {
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    //将自己的验证方式加入容器
    @Bean
    public CustomRealm myShiroRealm() {
        CustomRealm customRealm = new CustomRealm();
        return customRealm;
    }

    //权限管理,配置主要是Realm的管理认证
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }

    //Filter工厂,设置对应的过滤条件和跳转条件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> map = new HashMap<>();
        //登出
        //map.put("/user/logout", "logout");
        //对所有用户认证
        map.put("/**", "authc");
        //登录
        shiroFilterFactoryBean.setLoginUrl("/user/login");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }


    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

编写一个简单的登录方法进行测试
 @Override
    public ResponseResult login(User user) {
        if (StringUtils.isEmpty(user.getUserName()) || StringUtils.isEmpty(user.getPassword())) {
            return ResponseResult.error(ResponseType.REQUEST_FAIL, "请输入用户名和密码!");
        }
        //用户认证信息
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
                user.getUserName(),
                user.getPassword()
        );
        try {
            //进行验证,这里可以捕获异常,然后返回对应信息
            subject.login(usernamePasswordToken);
        } catch (UnknownAccountException e) {
            log.error("用户名不存在!", e);
            return ResponseResult.error(ResponseType.REQUEST_FAIL, "用户名不存在!");
        } catch (AuthenticationException e) {
            log.error("账号或密码错误!", e);
            return ResponseResult.error(ResponseType.REQUEST_FAIL, "账号或密码错误!");
        } catch (AuthorizationException e) {
            log.error("没有权限!", e);
            return ResponseResult.error(ResponseType.REQUEST_FAIL, "没有权限!");
        }
        return ResponseResult.success("login success");
    }


到这里我们的认证工作就已经完成

测试权限


我的olh用户是有admin权限,然后去请求当前类中的查询方法

可以看到是成功的查询到了数据

然后我们切换用户

当前的test是没有admin的权限

至此权限认证也完成了…

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/756301.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-30
下一篇 2022-04-30

发表评论

登录后才能评论

评论列表(0条)

保存