栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

最全Shiro教程,一篇学会Shiro权限管理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

最全Shiro教程,一篇学会Shiro权限管理

声明:本文是博主观看bilibili上Java涛哥视频学习的Shiro框架所整理笔记,学完思路清晰,原文代码大致相同,原视频链接附上,方便以后学习查看。
本文项目源码加数据库

https://download.csdn.net/download/qq_45299673/69324339

Shiro
    • 一、权限管理
        • 1.1 基于主页的权限管理
        • 1.2 基于用户和权限的权限管理
        • 1.3 基于角色的访问控制(RBAC)
    • 二、Shiro
        • 2.1 认证和授权
        • 2.2 常见的安全框架
        • 2.3 shrio核心功能
        • 2.4 Shiro核心组件
        • 2.5 shiro的使用
        • 2.6 shrio认证流程
    • 三、SpringBoot整合Shiro
        • 3.1 导入依赖
          • application.yml配置
        • 3.2 Shiro配置
        • 3.3 测试
        • 3.4 内置JDBCRealm作为数据源
          • JdbcRealm规定的表结构
        • 3.5 shiro的标签的使用
          • 常用标签
    • 四、自定义Realm实现权限管理
        • 4.1 数据库设计
        • 4.2 创建DAO层
        • 4.3 application.yml
        • 4.4 pom.xml
        • 4.5 自定义Realm配置类
        • 4.6 shiro配置
        • 4.7 shiro业务层
        • 4.8 Controller层
        • 4.9 整合layUI
    • 五、加密
        • 5.1 Shiro加密
        • 5.2 密码认证
    • 六、Shiro的退出登录
    • 七、授权
        • 7.1 HTML授权
        • 7.2 过滤器授权
        • 7.3 注解授权
        • 7.4 手动授权

​ Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境。

一、权限管理

不同身份的人进入系统所完成的操作不同,如下图,当一个系统包含左侧所有菜单功能时,要求不同人员登录展示不同权限下的菜单,这时候就需要学习权限管理,看完本文就可轻松掌握。

1.1 基于主页的权限管理

设计多种页面,当不同权限的用户访问时,跳转不同的用户,如下图,用户1登录跳转到index1.html,用户2登录跳转到index2.html,缺陷比较大且繁琐,不建议使用。

缺点:适用于用户级别较少的,不能动态分配权限

1.2 基于用户和权限的权限管理

利用用户表、用户权限表、权限表三张表,每个用户在中间表分配权限

实现权限的动态分配,但是每个用户对应一个用户权限,10个人就得10个,数据比较冗余,这样就衍生了下面的五张表

1.3 基于角色的访问控制(RBAC)

创建用户表、角色表、权限表和两张中间表用户角色表、角色权限表五张表,每次新加用户时只需要授予角色就可获得相对的权限。

给同类人员的其中一个人授予权限可以再加一张用户权限表,直接授予权限。

二、Shiro 2.1 认证和授权
认证:对用户的身份进行检查(登录验证)
授权:对用户的权限进行检查(是否有对应的操作权限)

2.2 常见的安全框架
shiro:Apache Shrio是功能强大并且易用的Java安全框架
Spring Security:基于Spring的安全框架,依赖Spring
OAuth2:第三方授权框架(QQ、微信)
自定义安全认证中心
2.3 shrio核心功能

Anthentication 认证,验证用户是否有相应的身份 登录认证 Authorization
授权,权限验证,通过认证的用户检查是否有权限或者角色 Session Management
会话管理,用户在认证成功后创建会话,在没有退出之前,当前用户的所有信息都会保存在这个会话中 Cryptograsphy 加密,对敏感信息加密

支持的特性:
1.Web Support Shrio提供了过滤器,可以通过过滤器拦截web请求来处理web应用的访问控制
2.Caching 缓存支持,shiro可以缓存用户信息以及用户的角色权限信息,可以提高执行效率
3.concurrency shiro支持多线程应用
4.Run As 允许一个用户以另一种身份去访问
5.Remeber Me 记住密码
6.Testing 提供测试支持
Shiro是一个安全框架,不提供用户、权限的维护,用户的权限管理需要我们去设计

2.4 Shiro核心组件


Subject、Security Manager、Realms

  • Subject:表示待认证和授权的用户
  • Security Manager:Shiro框架的核心,Shiro就是通过Security Manager来进行内部实例的管理,并通过它来提供安全管理的各种服务
  • Realm:相当于shiro进行认证和授权的数据源
2.5 shiro的使用

1.添加maven依赖


    org.apache.shiro
    shiro-core
    1.4.1

2.创建shiro的配置文件

在resource下创建ini后缀文件

[users]
zhangsan=123456,seller
lisi=123123,ckmgr
admin=admin,admin

[roles]
admin=*
seller=order-add,order-del,order-list
ckmgr=ck-add,ck-del,ck-list

3.使用测试

public class ShiroTest {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入账号:");
        String username = sc.next();
        System.out.println("请输入密码:");
        String password = sc.next();

        //1.创建安全管理器
        DefaultSecurityManager securityManager=new DefaultSecurityManager();
        //2.创建realm
        IniRealm iniRealm=new IniRealm("classpath:shiro.ini");
        //3.将realm设置给安全管理器
        securityManager.setRealm(iniRealm);
        //4.将Realm设置给SecurityUtil工具
        SecurityUtils.setSecurityManager(securityManager);
        //5.通过SecurityUtil工具类获取subject对象
        Subject subject=SecurityUtils.getSubject();

        //认证流程
        //将认证账号和密码封装到token中
        UsernamePasswordToken token=new UsernamePasswordToken(username,password);
        //通过subject对象调用login方法进行认证
        boolean flag=false;
        try{
            subject.login(token);
            flag=true;
        }catch (IncorrectCredentialsException e){
            flag=false;
        }
        System.out.println(flag?"登录成功":"登录失败");

        //授权
        //判断是否有某个角色
        System.out.println(subject.hasRole("seller"));

        //判断是否有某个权限
        System.out.println(subject.isPermitted("order-del"));
    }
}
2.6 shrio认证流程

三、SpringBoot整合Shiro 3.1 导入依赖
 
        org.springframework.boot
        spring-boot-starter-parent
        2.0.1.RELEASE
    
    
        
            com.alibaba
            druid-spring-boot-starter
            1.1.10
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            1.1.1
        
        
        
            mysql
            mysql-connector-java
        

        
            org.apache.shiro
            shiro-spring
            1.4.1
        

    
application.yml配置
spring:
  datasource:
    druid:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8
      username: root
      password: 123456
      initial-size: 1
      min-idle: 1
      max-active: 20
mybatis:
  type-aliases-package: com.zx.entity
  mapper-locations: classpath:com/zx/dao/*Mapper.xml
3.2 Shiro配置

SpringBoot没有提供对Shiro的自动配置,因为Spring家族有自己的安全框架

  • config/shiroConfig.java
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
    @Bean
    public IniRealm getIniRealm(){
        IniRealm iniRealm=new IniRealm("classpath:shiro.ini");
        return iniRealm;
    }
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(IniRealm iniRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        //securityManager要完成校验,需要realm
        securityManager.setRealm(iniRealm);
        return securityManager;
    }
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean filter=new ShiroFilterFactoryBean();
        filter.setSecurityManager(defaultWebSecurityManager);
        //设置shiro的拦截规则
        //anon 匿名用户可访问   authc  认证用户可访问
        //user 使用RemeberMe的用户可访问  perms  对应权限可访问
        //role  对应的角色可访问
        Map filterMap=new HashMap<>();
        filterMap.put("/","anon");
        filterMap.put("/login.html","anon");
        filterMap.put("/register.html","anon");
        filterMap.put("/user/login","anon");
        filterMap.put("/user/register","anon");
        filterMap.put("/static
public class MyRealm extends AuthorizingRealm {

    @Resource
    private UserDao userDao;
    @Resource
    private RoleDao roleDao;
    @Resource
    private PermissionDao permissionDao;

    @Override
    public String getName() {
        return "myRealm";
    }

    
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取用户的用户名
        String username  = (String) principalCollection.iterator().next();
        //根据用户名查询用户角色
        Set roles = roleDao.getRoleNamesByUsername(username);
        //根据用户名查询用户权限
        Set permissions = permissionDao.getPermissionByUsername(username);
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        info.setRoles(roles);
        info.setStringPermissions(permissions);
        return info;
    }

    
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //参数authenticationToken就是传递的 subject.login(token)
        UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
        //从token中获取用户名
        String username = token.getUsername();
        //根据用户名从数据库查询用户安全数据
        User user = userDao.getUserByUsername(username);
        AuthenticationInfo info=new SimpleAuthenticationInfo(username,user.getPassword(),getName());
        return info;
    }
}
4.6 shiro配置

ShiroConfig.java

@Configuration
public class ShiroConfig {
    //Shiro的方言
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
    //自定义Realm
    @Bean
    public MyRealm getMyRealm(){
        MyRealm myRealm=new MyRealm();
        return myRealm;
    }
    //SecurityManager安全管理器
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        //securityManager要完成校验,需要realm
        securityManager.setRealm(myRealm);
        return securityManager;
    }
    //过滤器
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean filter=new ShiroFilterFactoryBean();
        filter.setSecurityManager(defaultWebSecurityManager);
        //设置shiro的拦截规则
        //anon 匿名用户可访问   authc  认证用户可访问
        //user 使用RemeberMe的用户可访问  perms  对应权限可访问
        //role  对应的角色可访问
        Map filterMap=new HashMap<>();
        filterMap.put("/","anon");
        filterMap.put("/login.html","anon");
        filterMap.put("/register.html","anon");
        filterMap.put("/user/login","anon");
        filterMap.put("/user/register","anon");
        filterMap.put("/static/**","anon");
        filterMap.put("/**","authc");
        filter.setFilterChainDefinitionMap(filterMap);

        filter.setLoginUrl("/login.html");
        //设置未授权页面跳转到登录页面
        filter.setUnauthorizedUrl("/login.html");
        return filter;
    }
}
4.7 shiro业务层
@Service
public class UserServiceImpl {
    public void checkLogin(String username,String Password){
        Subject subject= SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken(username,Password);
        subject.login(token);
    }
}
4.8 Controller层
@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserServiceImpl userService;
    @RequestMapping("/login")
    public String login(String username,String password){
        try {
            userService.checkLogin(username,password);
            return "index";
        } catch (Exception e) {
            System.out.println("密码错误");
            return "login";
        }
    }
}
4.9 整合layUI

导入layui包,官网复制后台框架代码




    
    
    Shiro管理系统
    







实现不同权限的管理员登录,展示的菜单不同

zhangsan 超级管理员 显示全部菜单

wangwu xmanager管理员,对仓库管理只有查看的权限

layui实现点击左边菜单,内容右边显示

五、加密

用户密码在存储到数据库之前根据一定的加密规则加密为密文。加密规则可以自定义,在项目开发中通常使用base64和MD5编码方式进行加密

​ base64:可以反编码的编码方式。

​ MD5:不可逆的编码方式(网站上常见的MD5解密,只不过是列出常见密码的密文进行查询,密码一旦复杂就解密不出来了,为了防止暴力穷举破解,可以加盐加密)

Shiro提供了加密功能,对输入的密码进行加密后再认证
5.1 Shiro加密
```java
@RequestMapping("/register")
public String register(String username,String password){
    //注册时对密码进行加密
    Md5Hash md5Hash=new Md5Hash(password);
            //加盐加密
    int salt=new Random().nextInt(90000)+10000;  //10000-99999
    Md5Hash md5Hash1=new Md5Hash(password,salt+"");
   //加盐加密+Hash次数
    Md5Hash md5Hash2=new Md5Hash(password,salt+"",1);
    //TODO 此处省略存储到数据库代码
    return "login";
}
```
5.2 密码认证

在ShiroConfig中配置加密规则

修改上文的ShiroConfig.java,设置加密规则认证时就生效,没有设置加密规则,默认明文校验

	.
    .
    .

@Bean
    public HashedCredentialsMatcher getHashedCredentialsMatcher(){
        HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
        //matcher就是用来指定加密规则
        //加密方式
        matcher.setHashAlgorithmName("md5");
        //hash次数,这里的hash次数要与存储时加密的hash次数保持一致
        matcher.setHashIterations(1);
        return matcher;
    }

    //自定义Realm
    @Bean
    public MyRealm getMyRealm(HashedCredentialsMatcher matcher){
        MyRealm myRealm=new MyRealm();
        //设置加密规则
        myRealm.setCredentialsMatcher(matcher);
        return myRealm;
    }
	.
    .
    .

可以正常登录,如果密码加盐了,Realm在返回认证信息时需要返回盐数据,在自定义Realm中修改

  ByteSource.Util.bytes(user.getPasswordSalt()),

六、Shiro的退出登录
  • 在Shiro过滤器中进行配置,配置logout对应的路径
  • 在页面的退出按钮上添加路径/logout

    当点击退出登录按钮时,shiro会拦截logout的路径调用subject.logout()登出。
七、授权

​ 一般的授权方式有两种:一、HTML授权,即用户登录只显示自己权限的菜单,没有权限的菜单不显示。二、过滤器授权,对所有用户显示所有菜单功能,当用户点击菜单后再验证是否有此权限,无权限提示权限不足。

7.1 HTML授权
  • shiro标签
入库
7.2 过滤器授权

7.3 注解授权
  • 配置Spring对Shiro的注解支持
//使Shiro的注解可以加载执行
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator autoProxyCreator=new DefaultAdvisorAutoProxyCreator();
        autoProxyCreator.setProxyTargetClass(true);
        return autoProxyCreator;
    }
    //权限注解加载
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager){
        AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(defaultWebSecurityManager);
        return advisor;
    }
  • 在请求的控制器添加权限注解
//没有sys:k:find权限不允许访问
@RequiresPermissions("sys:k:find")
@RequestMapping("/list")
public String list(){
    return "list";
}

当无权人员访问时会抛出AuthorizationException异常,可以配置全局异常类。

@ControllerAdvice
public class GlobalException {
    @ExceptionHandler
    public String doException(Exception e){
        if(e instanceof AuthorizationException){
            return "error";
        }
        return null;
    }
}
7.4 手动授权

在代码中进行权限校验,一般写在业务层

Subject subject=SecurityUtils.getSubject();
if(subject.isPermitted("sys:k:find")){
    //业务逻辑
}else{
    //无权限处理
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/677280.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号