Shiro框架整合springboot 同时使用配置以及注解完成权限管理

springboot pom配置

springboot 版本为2.1.6

    <!--  shiro跟spring的整合依赖-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.0</version>
    </dependency>
    <!--        shiro跟thymeleaf的整合依赖-->
    <dependency>
        <groupId>com.github.theborakompanioni</groupId>
        <artifactId>thymeleaf-extras-shiro</artifactId>
        <version>2.0.0</version>
    </dependency>

编写shiro配置类

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
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.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

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

@Configuration
public class ShiroConfig
{
    /*
    * 1.创建ShiroFilterFactoryBean,核心配置的一部分
    */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultSecurityManager securityManager)
    {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
//        1.anon:无需认证(登录)可以访问
//        2.authc:必须认证才可以访问
//        3.user:如果使用remember me 的功能可以直接访问
//        4.perms:该资源必须得到资源权限才可以访问
//        5.role:该资源必须得到角色权限才可以访问


        Map<String, String> filterMapper = new LinkedHashMap<>();
          /**
         * 放行静态资源
         */
        filterMapper.put("/css/**","anon");
        filterMapper.put("/fonts/**","anon");
        filterMapper.put("/images/**","anon");
        filterMapper.put("/js/**","anon");

        /**
         * 放行公共界面
         */
        filterMapper.put("/reporttable","anon");
        filterMapper.put("/index","anon");
        filterMapper.put("/login","anon");
        filterMapper.put("/","anon");
        filterMapper.put("/reportsearch","anon");
        filterMapper.put("/unauth","anon");

		//这个要放在最后,拦截所有资源,如果放在放行资源前面,放行资源会不生效
        filterMapper.put("/**","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMapper);
        shiroFilterFactoryBean.setLoginUrl("/tologin");
        //如果开启了注解,这个无权限界面是无法进入的,下面会配置一个类专门拦截无权限
        shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
        return shiroFilterFactoryBean;
    }



    /*
     * 2.创建DefalutWebSecurityManager
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm)
    {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //需要关联一个Realm
        defaultWebSecurityManager.setRealm(userRealm);
        return defaultWebSecurityManager;

    }



    /*
     * 3.创建Realm,Realm类是自定义的一个类,用来做用户认证以及权限管理
     */
    @Bean(name = "userRealm")
    public UserRealm getUseRealm()
    {
        return new UserRealm();
    }

    /**
     * 创建shiro跟themeleaf交互的ShiroDialect
     * @return
     */
    @Bean
    public ShiroDialect getShiroDialect()
    {
        return new ShiroDialect();
    }



    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * *
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     * *
     * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
     * * @return
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

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

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }


配置自定义realm类



/**
 * 自定义Realm类,继承于shiro定义的一个类
 */

import com.ht.intergrity.domian.UserLogin;
import com.ht.intergrity.service.UserLoginService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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 java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class UserRealm extends AuthorizingRealm
{
    /**
     * 执行核心授权逻辑
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)
    {
        System.out.println("执行授权逻辑");
        //给资源进行授权
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        /*UserLogin是自定义的一个用户类,用来做用户登录,存放了用户名跟密码,通过下面的方法可以获取当前登录的用户信息,
        **用户来源是由认证逻辑中的return new SimpleAuthenticationInfo(loginuser,loginuser.getPassword(),getName());
        *这段代码存放的
        */
        UserLogin userLogin = (UserLogin) SecurityUtils.getSubject().getPrincipal();
		
		//调用了service层中的方法,通过用户id获取用户的权限,将授权关键字并存放到set列表中,最后放入授权
        List<Map<String, String>> permByUserid = userLoginService.findPermByUserid(userLogin.getId());
        Set<String> stringSet = new HashSet<>();
        for(Map<String,String> map:permByUserid)
        {
            String permsvalue = map.get("permsvalue");
            stringSet.add(permsvalue);
        }
        info.setStringPermissions(stringSet);
        return info;
    }

    @Autowired
    private UserLoginService userLoginService;


    /**
     * 执行认证逻辑
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException
    {
        System.out.println("正在执行认证逻辑");

		/**
		  *token是由用户登录的control层中存放的,可以由此获取到用户名跟密码
		  */
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        UserLogin loginuser = userLoginService.findByUsername(token.getUsername());

        if(loginuser==null)
        {
            //返回null表示用户不存在
            return null;

        }
        //2.判断密码
        return new SimpleAuthenticationInfo(loginuser,loginuser.getPassword(),getName());
    }
}

control层认证用户登录

	/**
	 *所有登录由此进入
	 */
	@RequestMapping(value = "/tologin",method = RequestMethod.GET)
    public String tologin()
    {
        return "login";
    }

	/**
	 *通过登录界面发送过来的post请求来进行shiro认证
	 */
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String toLogin(String username, String password, Model model)
    {
        /**
         * 使用shiro编写认证
         */

        //1,获取subject
        Subject subject = SecurityUtils.getSubject();
        //2,封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        //3,执行登录方法
        try
        {
            subject.login(token);
            //登录成功
            //登录成功,重定向到表单页面
            return "redirect:reportcheck";
        }
        catch (UnknownAccountException e)
        {
            //登录失败,用户名不存在
            model.addAttribute("subinfo", "用户名不存在!");
            return "login";
        }
        catch (IncorrectCredentialsException e)
        {
            //登录失败,密码错误
            model.addAttribute("subinfo", "密码错误!");
            return "login";
        }
    }

需要做认证的controller

    /**
     * 查询所有单据
     *此control只有单权限认证
     * @param model
     * @return
     */
    @RequiresPermissions("user:all")
    @RequestMapping("/reportcheck/all/{status}")
    public String reportcheckall(Model model, @PathVariable("status") String status)
    {
        String type = "all";
        List<ReportTable> reportTables = reportService.findReportsByStatusAndReportType(STATUS_MAP.get(status), TYPES_MAP.get(type));
        model.addAttribute("reporttables", reportTables);
        model.addAttribute("status", status);
        model.addAttribute("statustext", STATUS_MAP.get(status));
        model.addAttribute("type", type);
        model.addAttribute("typetext", TYPES_MAP.get(type));
        return "report_check";
    }


/**
     * 查询表单
     *这个是多权限的查询
     * @param model
     * @return
     */
     ***==这边千万注意,value中的值必须写成下面列表的形式,如果写错了权限无法赋予,老子为了2个引号浪费了2个小时在查原因,最后发现写成了value = {"user:tstable,user:all"},总是提示权限不足==***
     //logical = Logical.OR 只要有其中一个权限就可以访问,and是两个需要同时具备
    @RequiresPermissions(value = {"user:tstable","user:all"},logical = Logical.OR)
    @RequestMapping("/reportcheck/ts/{status}")
    public String reportcheckts(Model model, @PathVariable("status") String status)
    {
        String type = "ts";
        List<ReportTable> reportTables = reportService.findReportsByStatusAndReportType(STATUS_MAP.get(status), TYPES_MAP.get(type));
        model.addAttribute("reporttables", reportTables);
        model.addAttribute("status", status);
        model.addAttribute("statustext", STATUS_MAP.get(status));
        model.addAttribute("type", type);
        model.addAttribute("typetext", TYPES_MAP.get(type));
        return "report_check";
    }

前端隐藏没有权限的标签代码

这段代码为shiro跟thymeleaf整合的代码 shiro:hasPermission="user:all"
表示如果全下为user:all就可以看到这个空间,否则就看不到这个li标签
<ul class="nav nav-justified ulli">
     <li shiro:hasPermission="user:all" class="badtype"><a href="reportcheck/all/all/">所有表单</a></li>
     <li shiro:hasPermission="user:tstable" class="badtype"><a href="reportcheck/ts/all/">ts</a></li>
     <li shiro:hasPermission="user:jbtable" class="badtype"><a href="reportcheck/jb/all/">jb</a></li>
     <li shiro:hasPermission="user:sstable" class="badtype"><a href="reportcheck/ss/all/">ss</a></li>
 </ul>

拦截没有权限的类,放到spring可以扫描到的包中即可

import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 描述:
 *
 * @author caojing
 * @create 2019-01-27-17:12
 */
@ControllerAdvice
public class NoPermissionException {
    @ResponseBody
    @ExceptionHandler(UnauthorizedException.class)
    public String handleShiroException(Exception ex) {
        return "<h1>亲,你没有权限噢!</h1>";
    }
}

小白笔记,大神勿喷

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值