Shiro学习

单词概念

Authentication:身份认证 / 登录,验证用户是不是拥有相应的身份;

Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通 JavaSE 环境的,也可以是如 Web 环境的;

Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

Web Support:Web 支持,可以非常容易的集成到 Web 环境;

Caching:缓存,比如用户登录后,其用户信息、拥有的角色 / 权限不必每次去查,这样可以提高效率;

Concurrency:shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

Testing:提供测试支持;

Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

记住一点,Shiro 不会去维护用户、维护权限;这些需要我们自己去设计 / 提供;然后通过相应的接口注入给 Shiro 即可。

原生 shiro 基本使用 - 认证

helloworld

代码路径

导入shiro依赖

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

编写shiro配置文件 shiro.ini 编写权限数据

[users]
zhangsan=123
zhaoxingyu=123456

认证测试

public class TestAuthenticator {
  public static void main(String[] args) {
    //1.创建安全管理器对象
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    //2.给安全管理器设置realm
    securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
    //3.使用SecurityUtils 给全局工具类设置安全管理器
    SecurityUtils.setSecurityManager(securityManager);
    //4.关键对象 subject 主体
    Subject subject = SecurityUtils.getSubject();
    //5.创建令牌
    UsernamePasswordToken token = new UsernamePasswordToken("zhaoxingyu", "123456");
    //6.用户认证
    try {
      //认证成功  subject.isAuthenticated()
      System.out.println("认证状态:" + subject.isAuthenticated());
      //验证令牌
      subject.login(token);
      System.out.println("认证状态:" + subject.isAuthenticated());
    } catch (UnknownAccountException e) { //认证用户不存在,抛出UnknownAccountException异常
      System.out.println("用户名不存在:");
    } catch (IncorrectCredentialsException e) {//密码不正确,抛出IncorrectCredentialsException异常
      System.out.println("密码错误。。。");
    } catch (Exception e){
      e.printStackTrace();
      System.out.println("未知异常");
    }
  }
}

自定义 Realm

  • 默认使用的 org.apache.shiro.realm.SimpleAccountRealm 继承的 AuthorizingRealm
  • 自定义的要继承AuthorizingRealm
public class CustomerRealm extends AuthorizingRealm {
  //授权
  @Override
  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    return null;
  }

  //认证
  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    //获取token用户名
    String principal = (String) token.getPrincipal();
    System.out.println(principal);
    //根据信息  , 可以去真实数据库查询
    if("zhaoxingyu".equals(principal)){
      SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, "123456",this.getName());
      return simpleAuthenticationInfo;
    }
    return null;
  }
}
  • 使用自定义的 认证授权
//设置自定义的Realm  ,其他都一样
securityManager.setRealm(new CustomerRealm());

MD5 使用

使用这个 md5+ 盐值 + hash散列 规则解锁时,也需要使用这个规则

//md5 + 盐值 + hash散列次数  
Md5Hash md5Hash = new Md5Hash("123456","Xz#p",1024);
System.out.println(md5Hash.toHex());

自定义 Realm + md5

使用md5 + 盐值 + 松散hash

//使用 md5 + 盐值 + hash散列 进行加密
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  String principal = (String) token.getPrincipal();
  if("zhaoxingyu".equals(principal)){
      SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,
     "64845a31af89f20715438ea1793a4246",  //数据库密码
  	  ByteSource.Util.bytes("Xz#p"), //盐值
      this.getName());
    return info;
  }
  return null;
}
public class TestCustomerMD5Realm {
    public static void main(String[] args) {
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        //注入的realm
        CustomerMD5Realm realm = new CustomerMD5Realm();
        //设置加密凭证
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //使用md5方式加密
        credentialsMatcher.setHashAlgorithmName("md5");
        //松散次数
        credentialsMatcher.setHashIterations(1024);
        //设置进 CustomerMD5Realm 需要的加密规则
        realm.setCredentialsMatcher(credentialsMatcher);
        securityManager.setRealm(realm);
        SecurityUtils.setSecurityManager(securityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("zhaoxingyu","123456");
        try {
            subject.login(token);
            System.out.println("任证状态:"+subject.isAuthenticated());
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.err.println("==用户名不存在==");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.err.println("==密码错误==");
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("==未知异常==");
        }
    }
}

原生 shiro 基本使用 - 授权

满足认证 (subject.isAuthenticated()==true) 后,进行授权

System.out.println("==========   角色   ===========");
//具有那个角色
System.out.println("hasRole:" + subject.hasRole("user"));  //true
//同时具有哪些角色,全部满足
System.out.println("hasAllRoles:" + subject.hasAllRoles(Arrays.asList("user", "admin")));//true
//返回boolean数组  有哪个角色  那个就是true
for (boolean b : subject.hasRoles(Arrays.asList("admin", "super"))) {
  System.out.println("hasRoles:" + b);  //true , false
}
System.out.println("==========   权限   ===========");
//基于权限字符串的访问控制   资源标识:操作:资源类型 (:分隔符)
//具有的权限
System.out.println("isPermitted:"+subject.isPermitted("user:update:01"));  //true 
//分别具有的权限
for (boolean b : subject.isPermitted("user:*", "order:*")) {  //true  false
  System.out.println("isPermitted:"+b);
}
//同时具有哪些权限
System.out.println("isPermittedAll:"+subject.isPermittedAll("user:*", " product:*")); //true

使用自定义的继承AuthorizingRealm 类,授权

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  String primaryPrincipal = (String) principals.getPrimaryPrincipal();
  //就是登陆时候的用户名
  System.out.println("身份信息:"+primaryPrincipal);
  //为我当前登录用户进行的授权
  SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
  //将数据库中的查新角色复制给权限对象
  simpleAuthorizationInfo.addRoles(Arrays.asList("admin","user"));
  //将数据库中的查新权限复制给权限对象       //user,product 下所有资源都有权限  
  simpleAuthorizationInfo.addStringPermissions(Arrays.asList("user:*","product:*")); 
  return simpleAuthorizationInfo;
}

shiro整合springboot – jsp

  • 使用jsp模板

代码详细

###pom

<!-- 整合的shiro的 starter -->
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring-boot-starter</artifactId>
  <version>1.5.3</version>
</dependency>

配置类

1.创建 shiroFilter 负责拦截所有请求

@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
  ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  //给filter 设置安全管理器
  shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

  System.out.println("拦截了请求");
  //配置访问资源受限规则
  Map<String, String> maps = new HashMap<>();
  maps.put("/index.jsp", "authc");  //访问/index.jsp  要有authc权限
  //将 /login.jsp 设置为拦截请求跳转页面 默认就是 /login.jsp
  shiroFilterFactoryBean.setLoginUrl("/login.jsp");
  shiroFilterFactoryBean.setFilterChainDefinitionMap(maps);
  return shiroFilterFactoryBean;
}

2.创建安全管理器

@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("getRealm") Realm realm) {
  DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
  //给安全管理器设置
  defaultWebSecurityManager.setRealm(realm);
  return defaultWebSecurityManager;
}

3.创建自定义realm 加入spring 类要继承AuthorizingRealm

@Bean
public Realm getRealm() {
  CustomerRealm customerRealm = new CustomerRealm();
  //修改凭证匹配器
  HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
  //设置加密算法位md5
  credentialsMatcher.setHashAlgorithmName("MD5");
  //设置散列次数
  credentialsMatcher.setHashIterations(1024);
  customerRealm.setCredentialsMatcher(credentialsMatcher);
  return customerRealm;
}

其他内置过滤器缩写

配置缩写对应的过滤器功能
身份验证相关的
anonAnonymousFilter指定url可以匿名访问
authcFormAuthenticationFilter基于表单的拦:usernameParam:表单提交的用户名参数名( username); passwordParam:表单提交的密码参数名(password); rememberMeParam:表单提交的密码参数名(rememberMe); loginUrl:登录页面地址(/login.jsp);successUrl:登录成功后的默认重定向地址; failureKeyAttribute:登录失败后错误信息存储key(shiroLoginFailure)
authcBasicBasicHttpAuthenticationFilterBasic HTTP身份验证拦截器,主要属性: applicationName:弹出登录框显示的信息(application)
logoutauthc.LogoutFilter退出拦截器,主要属性:redirectUrl:退出成功后重定向的地址(/)
userUserFilter用户拦截器,用户已经身份验证/记住我登录的都可
授权相关的
rolesRolesAuthorizationFilter角色授权拦截器,验证用户是否拥有所有角色;主要属性: loginUrl:登录页面地址(/login.jsp);unauthorizedUrl:未授权后重定向的地址;示例“/admin/**=roles[admin]”
permsPermissionsAuthorizationFilter权限授权拦截器,验证用户是否拥有所有权限;属性和roles一样;示例“/user/**=perms[“user:create”]”
portPortFilter端口拦截器,主要属性:port(80):可以通过的端口;示例“/test= port[80]”,如果用户访问该页面是非80,将自动将请求端口改为80并重定向到该80端口,其他路径/参数等都一样
restHttpMethodPermissionFilterrest风格拦截器,自动根据请求方法构建权限字符串(GET=read, POST=create,PUT=update,DELETE=delete,HEAD=read,TRACE=read,OPTIONS=read, MKCOL=create)构建权限字符串;示例“/users=rest[user]”,会自动拼出“user:read,user:create,user:update,user:delete”权限字符串进行权限匹配(所有都得匹配,isPermittedAll)
sslSslFilterSSL拦截器,只有请求协议是https才能通过;否则自动跳转会https端口(443);其他和port拦截器一样
noSessionCreationNoSessionCreationAuthorizationFilter需要指定权限才能访问

CustomerRealm 授权 ,登录成功就有 user:* , order:save 权限

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
  //给予权限
  simpleAuthorizationInfo.addStringPermissions((Arrays.asList("user:*","order:save")));
  return simpleAuthorizationInfo;
}

###jsp

shrio整个jsp标签 shiro:hasPermission :是否哟这个权限字符串 shiro:hasRole这个用户 是否有这个角色

<shiro:hasPermission name="user:*">
  <li><a href="">用户管理</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="order:*">
  <li><a href="">订单管理</a></li>
</shiro:hasPermission>
<shiro:hasRole name="admin">
  <li><a href="">商品管理</a></li>
  <li><a href="">订单管理</a></li>
  <li><a href="">物流管理</a></li>
</shiro:hasRole>

Controller

@Controller
@RequestMapping("order")
public class OrderController {
  
    @GetMapping("/list")		//有order:list  权限就可以访问 否则抛出异常 :UnauthorizedException
    @RequiresPermissions(value = {"order:list"})
    @ResponseBody
    public String list(){
        return "访问order list...";
    }
  
    @GetMapping("/save")
    @RequiresPermissions(value = {"order:save"})
    @ResponseBody
    public String save() {
        return "访问order save...";
    }
}

更多注解

  • @RequiresAuthentication

    ​验证用户是否登录,等同于方法subject.isAuthenticated() 结果为true时。

  • @RequiresUser

    ​验证用户是否被记忆,user有两种含义:

    ​一种是成功登录的(subject.isAuthenticated() 结果为true);

    ​另外一种是被记忆的(subject.isRemembered()结果为true)。

  • @RequiresGuest

    ​验证是否是一个guest的请求,与@RequiresUser完全相反。

    ​ 换言之,RequiresUser == !RequiresGuest。

    ​此时subject.getPrincipal() 结果为null.

  • @RequiresRoles

    ​例如:@RequiresRoles(“aRoleName”);

    ​ void someMethod();

    ​如果subject中有aRoleName角色才可以访问方法someMethod。如果没有这个权限则会抛出异常AuthorizationException

  • @RequiresPermissions

    ​例如: @RequiresPermissions({“file:read”, “write:aFile.txt”} )
    ​ void someMethod();

    ​要求subject中必须同时含有file:read和write:aFile.txt的权限才能执行方法someMethod()。否则抛出异常AuthorizationException

权限基本sql

/*
 Navicat Premium Data Transfer

 Source Server         : localhost_mysql_3306
 Source Server Type    : MySQL
 Source Server Version : 50731
 Source Host           : localhost:3306
 Source Schema         : shiro

 Target Server Type    : MySQL
 Target Server Version : 50731
 File Encoding         : 65001

 Date: 23/08/2020 18:27:15
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for tb_pers
-- ----------------------------
DROP TABLE IF EXISTS `tb_pers`;
CREATE TABLE `tb_pers`  (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for tb_role
-- ----------------------------
DROP TABLE IF EXISTS `tb_role`;
CREATE TABLE `tb_role`  (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for tb_role_pers
-- ----------------------------
DROP TABLE IF EXISTS `tb_role_pers`;
CREATE TABLE `tb_role_pers`  (
  `id` int(6) NOT NULL,
  `roleid` int(6) NULL DEFAULT NULL,
  `persid` int(6) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user`  (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `salt` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for tb_user_role
-- ----------------------------
DROP TABLE IF EXISTS `tb_user_role`;
CREATE TABLE `tb_user_role`  (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `userid` int(6) NULL DEFAULT NULL,
  `roleid` int(6) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

加入ehCache

pom

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

配置中开启缓存管理

@Bean
public Realm getRealm() {
  CustomerRealm customerRealm = new CustomerRealm();
  //修改凭证匹配器
  HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
  //设置加密算法位md5
  credentialsMatcher.setHashAlgorithmName("MD5");
  //设置散列次数
  credentialsMatcher.setHashIterations(1024);
  //================================缓存设置begin======================================
  //开启缓存管理
  customerRealm.setCacheManager(new EhCacheManager());
  //开启全局缓存
  customerRealm.setCachingEnabled(true);
  //认证缓存
  customerRealm.setAuthenticationCachingEnabled(true);
  //认证缓存名字
  customerRealm.setAuthenticationCacheName("authenticationCache");
  //开启授权缓存
  customerRealm.setAuthorizationCachingEnabled(true);
  //授权缓存名字
  customerRealm.setAuthorizationCacheName("authorizationCache");
  //================================缓存设置end======================================
  customerRealm.setCredentialsMatcher(credentialsMatcher);
  return customerRealm;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

明明吃了饭

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

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

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

打赏作者

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

抵扣说明:

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

余额充值