Shiro+Springboot+Vue前后端分离实现权限管理

Shiro介绍就跳过了,这里记录怎么在项目中使用

1 添加maven依赖

<shiro.version>1.4.0</shiro.version>
<druid.version>1.1.20</druid.version>
<shiro-redis.version>3.2.3</shiro-redis.version>

   

<dependency>
    <!--session持久化插件-->
    <groupId>org.crazycake</groupId>
    <artifactId>shiro-redis</artifactId>
    <version>${shiro-redis.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>${druid.version}</version>
</dependency>
<!-- shiro-core -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>${shiro.version}</version>
</dependency>

2 建好 用户表(我这里是whaccount),角色表(role),用户角色中间表,权限表(或者叫菜单表,menu),角色-权限(菜单)中间表这5张表

   具体的RBAC概念这里我就不细说了 网上一大堆解释,用户对应角色,角色对应权限

3 实现自定义Realm

   

package com.hy.bjggwhy.config;

import com.hy.bjggwhy.entity.WhyMenu;
import com.hy.bjggwhy.entity.WhyRole;
import com.hy.bjggwhy.entity.WhyWhaccount;
import com.hy.bjggwhy.service.WhyMenuService;
import com.hy.bjggwhy.service.WhyRoleService;
import com.hy.bjggwhy.service.WhyWhaccountService;
import com.hy.bjggwhy.util.Utils;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

/**
 * @author zhangmy
 * @date 2019-12-24 15:57
 * @description 配置Realm类(shiro框架手动配置的关键,用来登陆和权限认证)
 */
public class WhyShiroRealm extends AuthorizingRealm {

    private static final Logger LOGGER = LoggerFactory.getLogger(WhyShiroRealm.class);

    @Autowired
    private WhyWhaccountService whaccountService;

    @Autowired
    private WhyRoleService roleService;

    @Autowired
    private WhyMenuService menuService;

    //授权配置
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        LOGGER.info("权限配置-->WhyShiroRealm.doGetAuthorizationInfo:");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        WhyWhaccount whaccount = (WhyWhaccount)principals.getPrimaryPrincipal();
        try {
            List<WhyRole> roles = roleService.getRoleByWhaccountId(whaccount.getId());
            for (WhyRole role : roles) {
                authorizationInfo.addRole(role.getName());//角色存储
            }
            //此处如果多个角色都拥有某项权限,不会数据重复,内部用的是Set
            List<WhyMenu> menus = menuService.getMenuByRoleList(roles);
            for (WhyMenu menu : menus) {
                authorizationInfo.addStringPermission(menu.getUrl());//权限存储
            }
        } catch (Exception e) {
            Utils.getExceptionDetail(e);
        }
        return authorizationInfo;
    }

    //认证配置
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        LOGGER.info("Shiro认证-->WhyShiroRealm.doGetAuthenticationInfo:");
        //获取用户的输入的账号.
        String username = (String) token.getPrincipal();
        WhyWhaccount whaccount = whaccountService.findWhaccountByUsername(username);
        if (whaccount == null) {
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                whaccount, //用户名
                whaccount.getPassword(), //密码
                null,//salt
                getName()  //realm name
        );
        return authenticationInfo;
    }
}

  4 添加Shiro配置,通过ShiroConfig类实现

    

package com.hy.bjggwhy.config;

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.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

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

/**
 * @author zhangmy
 * @date 2019-12-24 16:46
 * @description
 */
@Configuration
//@ComponentScan
public class ShiroConfig {


    @Bean
    public FilterRegistrationBean delegatingFilterProxy() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName("shiroFilter");
        filterRegistrationBean.setFilter(proxy);
        return filterRegistrationBean;
    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
        // shiroFilterFactoryBean.setLoginUrl("/login");
        //设置成功跳转的页面
        //shiroFilterFactoryBean.setSuccessUrl("/index");
        // 设置无权限时跳转的 url;
        //shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");

        // 设置拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        //开放接口
//        filterChainDefinitionMap.put("/**", "anon");//放开全部

        filterChainDefinitionMap.put("/whaccount/whaccountLogin", "anon");  //放开登录
        filterChainDefinitionMap.put("/*/get*", "anon"); //放开查询
        filterChainDefinitionMap.put("/upload/*", "anon"); //放开资源上传
        filterChainDefinitionMap.put("/search/*", "anon"); //放开资源搜索
        filterChainDefinitionMap.put("/user/*", "anon"); //放开普通用户操作


        filterChainDefinitionMap.put("/swagger-ui.html", "anon"); //放开swagger
        filterChainDefinitionMap.put("/swagger-resources/**", "anon"); //放开swagger
        filterChainDefinitionMap.put("/v2/**", "anon"); //放开swagger
        filterChainDefinitionMap.put("/webjars/**", "anon"); //放开swagger

        filterChainDefinitionMap.put("/**", "authc");//其余接口一律拦截,这行代码必须放在所有权限设置的最后,不然都被拦截

        //配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
        //shiroFilterFactoryBean.setLoginUrl("/unauth");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        System.out.println("Shiro拦截器工厂类注入成功");
        return shiroFilterFactoryBean;
    }

    /*
    自定义身份认证realm
    必须写上这个类,并加上@Bean注解,目的是注入CustomRealm
    否则会影响CustomRealm类中其他类的依赖注入
     */
    @Bean
    public WhyShiroRealm customRealm(){
        WhyShiroRealm shiroRealm = new WhyShiroRealm();
        //shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());// 将md5密码比对器传给realm
        return  shiroRealm;
    }

    /*
    注入securityManager
     */
    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置REALM
        securityManager.setRealm(customRealm());
        return securityManager;
    }

    /*
   开启注解支持
    */
    @Bean
    //@DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }
}

5 登录接口做shiro认证

   

private Response login(String username, String password){
    //shiro登录验证
    Subject subject = SecurityUtils.getSubject();
    String realPassword = MD5Utils.GetMD5Code(password);
    UsernamePasswordToken token = new UsernamePasswordToken(username, realPassword);
    subject.login(token);
    //用户基本信息
    WhyWhaccount whyWhaccount = this.getWhaccountByUsername(username);
    Jedis jedis = RedisUtil.getJedis();
    String key = MD5Utils.GetMD5Code(Constant.REDIS_WHACCOUNT_USER_KEY_PREFIX + whyWhaccount.getId());
    String sessionValue = MD5Utils.GetMD5Code(whyWhaccount.getId() + whyWhaccount.getUserName() + whyWhaccount.getPassword());
    jedis.set(key, sessionValue);
    jedis.expire(key, Constant.REDIS_SESSION_MAX_INACTIVE_INTERNAL);
    Map<String, Object> loginMap = new HashMap<>();
    whyWhaccount.setPassword(null);
    loginMap.put("whaccount",whyWhaccount);
    loginMap.put("session",sessionValue);
    //拥有的角色
    List<WhyRole> roles = roleService.getRoleByWhaccountId(whyWhaccount.getId());
    loginMap.put("roles", roles);
    //拥有的菜单权限
    List<WhyMenu> menus = menuService.getMenuByRoleList(roles);
    loginMap.put("menus", menus);
    return new Response(Constant.RES_SUCCESS, "登录成功", loginMap);
}

6 Shiro授权

   授权方式比较多,我这里使用注解方式,即在需要授权验证的controller上面使用

   @RequiresPermissions({"权限的url"})

    shiro会根据需要的权限url再去subject的权限中去对比,有就通过,没有就不通过

       

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值