SpringBoot 集成 Shiro、MybatisPLUS

引入Shiro依赖

        <!--Shiro核心依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.0</version>
        </dependency>

Shiro功能分为认证授权 其中认证是在登录的方法中进行逻辑认证 如下:

@RequestMapping("/login")
    @ResponseBody
    ResultApi login(User user){
        System.out.println("UserMame:-------------------"+user.getUserName());
        System.out.println("PassWord:-------------------"+user.getPassWord());
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassWord());
        try{
            // 开始认证,这一步会跳到我们自定义的 Realm 中
            subject.login(token);

            System.err.println("认证成功之后就会回到Controller层啦");
            return new ResultApi(200,null,"登录成功");
        }catch(Exception e){
            e.printStackTrace();
            System.err.println("认证失败之后也会回到Controller层啦");
            return new ResultApi(200,null,"登录失败");
        }

subject.login(token);底层会调用 自定义Realm中的认证方法

而授权则是在实际访问接口时触发 在自定义访问规则例如 authc需要授权访问

自定义Realm

我的数据库表为 用户表 权限表 角色表 用户权限关联表 角色权限关联表 可以根据注释来调整自己的代码

package com.gzc.test.shiro;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gzc.test.shiro.entity.*;
import com.gzc.test.shiro.service.*;
import org.apache.shiro.SecurityUtils;
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 javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MyRealm extends AuthorizingRealm {
    @Resource
    private UserService userService;
    @Resource
    private UserRoleService userRoleService;

    @Resource
    private RoleService roleService;
    @Resource
    private RolePermissionsService rolePermissionsService;

    @Resource
    private PermissionsService permissionsService;

    @Override  //授权
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取用户名
        String username = (String) principalCollection.getPrimaryPrincipal();
        //根据UserName找到该用户对象
        User user = userService.getOne(new QueryWrapper<User>().lambda().eq(User::getUserName, username));
        System.err.println("进入自定义的Realm层的授权层了哦,并且用户名为:"+username);
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        /**
         * 给该用户设置角色,角色信息存在 t_role 表中取
         *  authorizationInfo.setRoles(userService.getRoles(username));
         */
        //1.找到该用户一共有对少角色
        Set<String> roles = new HashSet<>();
        //权限集合
        Set<String> permissionses = new HashSet<>();
        List<UserRole> userRoleList = userRoleService.list(new QueryWrapper<UserRole>().lambda().eq(UserRole::getUserId, user.getId()));
        userRoleList.forEach(userRole
                ->
        {
            Role role = roleService.getOne(new QueryWrapper<Role>().lambda().eq(Role::getId, userRole.getRoleId()));
            roles.add(role.getRoleName());

        });
        authorizationInfo.setRoles(roles);
        /**
         * 给该用户设置权限,权限信息存在 t_permission 表中取
         * authorizationInfo.setStringPermissions(userService.getPermissions(username));
         */
        userRoleList.forEach(userRole
                ->
        {
            List<RolePermissions> rolePermissionsList = rolePermissionsService.list(new QueryWrapper<RolePermissions>().lambda().eq(RolePermissions::getRoleId, userRole.getRoleId()));
            rolePermissionsList.forEach(rolePermissions
                    ->
                    {
                        Permissions permissions = permissionsService.getOne(new QueryWrapper<Permissions>().lambda().eq(Permissions::getId, rolePermissions.getPermissionsId()));
                        permissionses.add(permissions.getPermissionsName());
                    });
        });
        authorizationInfo.setStringPermissions(permissionses);
        System.out.println("授权信息为:"+authorizationInfo);
        return authorizationInfo;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 根据 Token 获取用户名,如果您不知道该 Token 怎么来的,先可以不管,下文会解释
        String username = (String) authenticationToken.getPrincipal();
        System.err.println("进入自定义的Realm层的认证层了哦,并且用户名为:"+username);
        // 根据用户名从数据库中查询该用户
        User user = userService.getOne(new QueryWrapper<User>().lambda().eq(User::getUserName,username));
        System.err.println("该用户为"+user);
        if(user != null) {
            // 把当前用户存到 Session 中
            SecurityUtils.getSubject().getSession().setAttribute("user", user);
            // 传入用户名和密码进行身份认证,并返回认证信息
            AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUserName(), user.getPassWord(), "myRealm");
            System.err.println("认证信息为 :"+authcInfo);
            return authcInfo;
        } else {
            return null;
        }
    }
}

ShiroConfig

配置完ShiroConfig就可以进行测试了 我这里用的是注解的方法 之前我因为少两个方法导致访问注解下的方法不触发权限验证 具体代码的方法我在下方写出 遇到这个问题的小伙伴可以参考一下

DefaultAdvisorAutoProxyCreator方法
AuthorizationAttributeSourceAdvisor方法
方法内容下方的代码块中有 这里只是单独罗列出来

package com.gzc.test.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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);

    /**
     * 注入自定义的 Realm
     * @return MyRealm
     */
    @Bean
    public MyRealm myAuthRealm() {
        MyRealm myRealm = new MyRealm();
        logger.info("====myRealm注册完成=====");
        return myRealm;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    /**
     * 注入安全管理器
     * @return SecurityManager
     */
    @Bean
    public DefaultWebSecurityManager securityManager() {
        // 将自定义 Realm 加进来
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(myAuthRealm());
        logger.info("====securityManager注册完成====");
        return securityManager;
//        return null;
    }

    /**
     * 注入 Shiro 过滤器
     * @param securityManager 安全管理器
     * @return ShiroFilterFactoryBean // SecurityManager securityManager
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
        // 定义 shiroFactoryBean
        ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();

        // 设置自定义的 securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 设置默认登录的 URL,身份认证失败会访问该 URL
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 设置成功之后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/success");
        // 设置未授权界面,权限认证失败会访问该 URL
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");

        // LinkedHashMap 是有序的,进行顺序拦截器配置
        Map<String,String> filterChainMap = new LinkedHashMap<>();

        // 配置可以匿名访问的地址,可以根据实际情况自己添加,放行一些静态资源等,anon 表示放行
        filterChainMap.put("/css/**", "anon");
        filterChainMap.put("/imgs/**", "anon");
        filterChainMap.put("/js/**", "anon");
        filterChainMap.put("/swagger-*/**", "anon");
        filterChainMap.put("/swagger-ui.html/**", "anon");
        // 登录 URL 放行
        filterChainMap.put("/login", "anon");

        // 以“/user/admin” 开头的用户需要身份认证,authc 表示要进行身份认证
        filterChainMap.put("/user/*", "authc");
        // “/user/student” 开头的用户需要角色认证,是“admin”才允许
        filterChainMap.put("/user/student*/**", "roles[admin]");
        // “/user/teacher” 开头的用户需要权限认证,是“user:create”才允许
        filterChainMap.put("/user/teacher*/**", "perms[\"user:create\"]");

        // 配置 logout 过滤器
        filterChainMap.put("/logout", "logout");

        // 设置 shiroFilterFactoryBean 的 FilterChainDefinitionMap
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
        logger.info("====shiroFilterFactoryBean注册完成====");
        return shiroFilterFactoryBean;
    }

}

注解式访问验证

    @RequestMapping("/user/testPermission")
    @ResponseBody
    @RequiresRoles("student")
    ResultApi testPermissiom(){
        System.out.println("访问成功");
        return null;
    }

因为我在上方配置了访问路径/user/*下需要权限验证 @RequiresRoles(“权限名称”)注解为需要此权限才能访问

全局异常捕获

在没有权限的情况下会报一个异常 如下
SpringBoot 集成 Shiro、MybatisPLUS_第1张图片
这个其实他不影响正常使用 但是 想处理的小伙伴可以写一个全局异常捕获 代码如下:

package com.gzc.test.utils;

import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class ExceptionsHandler {

    //对没权限的进行结果进行拦截
    @ExceptionHandler(AuthorizationException.class)
    public ResultApi authorizationExceptionHandler(AuthorizationException authorizationException) {
        return new ResultApi(403,null,"没有访问权限");
    }
}


之后就可以再次重启访问 再次测试了

你可能感兴趣的:(MyBatis-PLUS,Shiro,SpringBoot,shiro)