springboot集成shiro(包括所出现的问题)

时间:2020-04-07 09:02:51   收藏:0   阅读:152

一,自定义realm,继承授权AuthorizingRealm

package com.dkepay.dkpadmin.common.shiro;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dkepay.dkpadmin.common.config.ApplicationContextRegister;
import com.dkepay.dkpadmin.common.entity.sys.SysUserEntity;
import com.dkepay.dkpadmin.common.utils.ShiroUtils;
import com.dkepay.dkpadmin.dao.SysUserDao;
import com.dkepay.dkpadmin.service.SysMenuService;
import lombok.extern.slf4j.Slf4j;
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 java.util.Set;

/**
 */
@Slf4j
public class SysUserRealm extends AuthorizingRealm {
    /**
     * 获取授权信息
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        log.info("授权信息开始---》");
        Integer uId = ShiroUtils.getUid();
        log.info("获取用户uId:[{}]",uId);
        SysMenuService menuService = ApplicationContextRegister.getBean(SysMenuService.class);
        Set<String> perms = menuService.listPerms(uId);
        log.info("获取用户权限perms:[{}]",perms);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(perms);
        log.info("授权信息结束---》");
        return info;
    }

    /**
     * 获取认证信息
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        log.info("认证信息开始---》");

//        获取用户账号(也就是手机号)
        String accountNumber = (String) token.getPrincipal();
        log.info("获取到的用户账号accountNumber:[{}]",accountNumber);
//        获取密码
        String password = new String((char[]) token.getCredentials());
        log.info("获取到的密码password:[{}]",password);
        SysUserDao sysUserDao = ApplicationContextRegister.getBean(SysUserDao.class);
//        根据用户账号查询数据库
        QueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile",accountNumber);
//        查询用户信息
        SysUserEntity sysUserEntity = sysUserDao.selectOne(queryWrapper);
        log.info("查询到的用户对象sysUserEntity:[{}]",sysUserEntity);
//        账号不存在
        if (sysUserEntity == null) {
            throw new UnknownAccountException("账号或密码不正确");
        }

//        密码错误
        if (!password.equals(sysUserEntity.getPassword())) {
            throw new IncorrectCredentialsException("账号或密码不正确");
        }

//        账号锁定
        if (sysUserEntity.getStatus() == 0) {
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(sysUserEntity, password, getName());
        log.info("认证信息结束---》");
        return info;
    }
}

二,配置shiroConfig(还要给安全管理器指定要连接的realm,代码中有)

package com.dkepay.dkpadmin.common.config;

import com.dkepay.dkpadmin.common.shiro.SysUserRealm;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;

/**
 * @Configuration 声明当前类为配置类,创建对象
 * 相当于@Component
 */
@Configuration
public class ShiroConfig {

    /**
     * 创建一个 ShiroFilterFactoryBean 创建一个过滤器工厂
     * @Bean 所在的方法,如果方法形参中写的对象类型在工厂中恰好有一个对象,会自定装配上
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        //过滤原则 ,要拦截哪些请求
        //配置拦截规则,哪些页面拦截,哪些不拦截,过滤器链
        LinkedHashMap<String, String> map = new LinkedHashMap<>();
        /**
         * anon 代表匿名可访问,就是不用登陆就可以访问
         * authc 代表登陆后才能访问
         * 支持通配符*
         * 注意:拦截规则 一个一个配置
         */
//        拦截接口
//        配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
        map.put("/logout","logout");
        map.put("/sys/**","authc");

//        拦截页面
        map.put("/**","anon");
        map.put("/home/*","authc");
//        被拦截返回登录页面
//        factoryBean.setLoginUrl("/home/login");
//        未授权界面;
//        factoryBean.setUnauthorizedUrl("/500x.html");
        factoryBean.setFilterChainDefinitionMap(map);
        //需要安全管理器
        factoryBean.setSecurityManager(securityManager);
        return factoryBean;
    }

    /**
     * 创建一个安全管理器
     */
     
    @Bean
    public DefaultWebSecurityManager securityManager(SysUserRealm sysUserRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //给安全管理器赋值一个realm,声明使用哪个realm
        securityManager.setRealm(sysUserRealm);
        return securityManager;
    }
    /**
     *创建realm
     */
    @Bean
    public SysUserRealm sysUserRealm(){
        return new SysUserRealm();
    }

    /**
     * Shiro生命周期处理器
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

    /**
     *  开启shiro aop注解支持
     *  使用代理方式;所以需要开启代码支持;否则@RequiresRoles等注解无法生效
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


 }

三,在controller层对应的方法上加注解(@RequiresPermissions("sys:menus"))

认证成功,则会根据注解上的权限字符串进入到授权的方法里(在自定义的realm里),根据认证通过的主体也就是Subject里面的用户id去数据库查询权限字符串,有就封装到info返回.没有就报Subject does not have permission [sys:menus]异常,也就是该用户没有该权限.

四,@RequiresPermissions注解无效

有可能是在shiroConfig中少加了两个配置

 /**
     * Shiro生命周期处理器
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

 

原文:https://www.cnblogs.com/y7023/p/12650676.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!