Shiro安全框架整合SpringBoot

Shiro安全框架整合

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

关于Shiro与SpringBoot应用的关联关系图如下

Alt

springBoot项目中加入依赖

在原有的springBoot项目中加入依赖,版本看官网,一般都可以.当然版本越新功能越多,我使用的是1.5.3版本的。

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.5.3</version>
</dependency>

导入依赖后,我们需要配置相关的Shiro基本设置

Shiro的配置类 一般放在配置文件夹下conifg名的文件下,为了规范配置文件单独放置配置文件取名未ShiroConfig.java。相关的配置代码我也放在下面提供参考

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

@Configuration
public class ShiroConfig {
    负责拦截所有的请求 创建 shiroFilter
    @Bean
    public ShiroFilterFactoryBean getShiroFilterBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
        //给filter 设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        //配置系统受限资源
        Map<String,String> map =new HashMap<>();
        map.put("/index","authc");
        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        //配置系统公共资源
        map.put("/login","anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
//        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        return shiroFilterFactoryBean;
    }
    //创建安全管理器
//DefaultWebSecurityManager (第二步)
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){
        DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
        //给安全管理器设置
        defaultWebSecurityManager.setRealm(realm);
        return defaultWebSecurityManager;
    }
    //自定义realm
//创建Realm对象,需要自定义 (第一步)
    @Bean
    public Realm getRealm(){
        UserRealm userRealm=new UserRealm();
        return userRealm;
    }
}

创建一个 UserRealm的类

并需要创建一个 UserRealm的类 是一个实体类,继承AuthorizingRealm
自定义的realm实现 目的是讲授权或者认证的数据来源转为数据库的实现

public class UserRealm extends AuthorizingRealm {
    //控制权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
    //控制登录
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        return null;
    }
}

关于拦截器

拦截器在使用中很常用,可以过滤未登录的用户,未授权的页面不可访问,那些公共资源放行,关于过滤的条件代码含义如图。可看图参考使用。
Alt

身份的认证

当完成这几步骤时 基础环境就配置好了下面需要进行身份的认证
身份认证需要在controller 里定义访问路径 则需要在拦截器中放行相关的路径操作内容如下

@RequestMapping("/loginAction")
 public String loginAction(String username){
//        UsernamePasswordToken token1=new UsernamePasswordToken(username,"");
//通常我们会将Subject对象理解为一个用户,同样的它也有可能是一个三方程序,它是一个抽象的概念,可以理解为任何与系统交互的“东西”都是Subject。
//通过SecurityUtils.getSubject()可以获得当前的Subject
        Subject subject=SecurityUtils.getSubject();
//创建一个用户
        AuthenticationToken token= new UsernamePasswordToken(username,"");
        try {
//登录用户
            subject.login(token);
            return "loginPage";
        }catch (Exception e){
            return "登录失败";
        }

    };

对于需要加密密码的传输认证如下
Alt
通常我们会将Subject对象理解为一个用户,同样的它也有可能是一个三方程序,它是一个抽象的概念,可以理解为任何与系统交互的“东西”都是Subject。

public void testSubject() {
        //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
        Factory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //2、得到SecurityManager实例 并绑定给SecurityUtils
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);


        //获得当前正在执行的subject
        Subject subject = SecurityUtils.getSubject();
        //获得shiro sessino实例
        Session session = subject.getSession();

        //创建一个用户
        UsernamePasswordToken token = new UsernamePasswordToken("root","123");
        //是否记住用户
        token.setRememberMe(true);
        //登录
        try {
            subject.login(token);
            //没有抛异常则登录成功
            String currentUser = subject.getPrincipal().toString();
            System.out.println("当前登录的用户是:"+currentUser);
            //判断用户是否是拥有某种角色
            boolean isRole = subject.hasRole( "admin" );
            //是否拥有某种功能
            boolean isPer = subject.isPermitted("xiaoming:run");
            //退出登录
            subject.logout();
        } catch ( UnknownAccountException uae ) {
            System.out.println("用户名不存在");
        } catch ( IncorrectCredentialsException ice ) {
            System.out.println("密码错误");
        } catch ( LockedAccountException lae ) {
            System.out.println("用户被锁定,不能登录");
        } catch ( AuthenticationException ae ) {
            System.out.println("严重的错误");
        }
    }

完成controller 的创建用户后逻辑结构后

到 UserRealm类中去做数据的对比认证

UsernamePasswordToken创建的对象在UserRealm中的方法会自动引用

//控制登录
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    AuthenticationInfo authenticationInfo; //构造一个对象
//从 UsernamePasswordToken 中取得username 的值
    String username=(String)authenticationToken.getPrincipal();
//在 UserRealm 中配置 UserServie 进行查询
    User user =userServie.selectUserByUsername(username);
    if (user!=null){
//进行验证参数1是返回数据库中正确的用户名,参数2 返回数据库中正确的密码 参数3提供当前realm的名字 this.getName
        authenticationInfo=new SimpleAuthenticationInfo(username,"","realmName");
        return authenticationInfo;
    }
    return null;
}

在实现类中实现方法

    @Override
    public User selectUserByUsername(String username) {
        Wrapper wrapper=new EntityWrapper<>();
        wrapper.eq(User.USERNAME,username);
        List selectList=userMapper.selectList(wrapper);
        if (selectList.size()>0){
            return selectList.get(0);//     取第一个  或者直接使用userMapper.selectOne()
        }

        return null;
    }

完成后效果为 没有认证不能访问拦截的网址,认证后则可以访问

数据访问权限的管理

//配置系统受限资源
//添加shiro内置过滤器
     /*
      *  anno: 无需认证即可访问
      *  authc: 必须认证才可访问
      *  user: 必须拥有记住我功能
      *  perms: 拥有对某个资源的权限才可访问
      *  role: 拥有某个角色权限
      */
        Map<String,String> map =new HashMap<>();
        map.put("/index","authc");
        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        //配置系统公共资源
        map.put("/login","anon");
//把规则添加进去
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);


        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
//        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

授权方法

//权限管理
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    SimpleAuthorizationInfo info =new SimpleAuthorizationInfo();
    String username=(String)principalCollection.getPrimaryPrincipal();
    //将当前的用户的角色和权限复制进来
    User user=userServie.selectUserByUsername(username);
    Integer roleid = user.getRoleid();
    Role role =roleMapper.selectById(roleid);
    info.addRole(role.getRolename());

    //当前用户拿到role的ID去查 rolename 然后复制给info
    Wrapper<Permission> wrapper=new EntityWrapper<>();
    wrapper.eq("roleid",role.getId());
    List<Permission> selectList=permissionMapper.selectList(wrapper);
    List<String>perlist=new ArrayList<>();
    selectList.forEach(per->{
        perlist.add(per.getPername());
    });
    info.addStringPermissions(perlist);

    return info;

}

测试时 认证可通过 数据权限不能正常使用 上面那一段不行可以试试下面一段原理差不多

//授权中获取认证方法传来的principal
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("执行了 授权doGetAuthorizationInfo");
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //info.addStringPermission("user:add"); 可以这样添加权限标识,但一般从数据库从取出
    //获取登录对象
    Subject subject = SecurityUtils.getSubject();
  
    //这个是从认证return的第一个参数(principal)获取
    User user = (User)subject.getPrincipal();	
  
    info.addStringPermission(user.getPerms()); //设置从数据库获取到的权限
    return info;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AH?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值