zoukankan      html  css  js  c++  java
  • shrio 第二天

    认证和策略

    简介

    针对多个reaml,可以进行realm个数进行配置
    默认有三个策略

    • AllSuccessfulStrategy
      所有认证成功
    • AtLeastOneSuccessfulStrategy (默认)
      最少有一个Realm验证成功即可,返回所有Realm身份验证成功的验证消息。与FirstSuccessfulStrategy区别在于它只返回一个认证成功的数据。
    • FirstSuccessfulStrategy,返回第一个Realm身份验证成功的消息。

    main:

    
    public static void main(String[] args) {
    
     Subject subject= ShiroUtils.getSubject("classpath:shiro03/shiro.ini");
        // 第四步登录
        UsernamePasswordToken token=new UsernamePasswordToken("admin","111");
    
    
        //第五步 身份认证 认证成功返回true,认证失败抛出异常
        try {
            //认证前
             // System.out.println("认证之前-是否认证:"+subject.isAuthenticated());
            subject.login(token);
             // System.out.println("认证之后-是否认证:"+subject.isAuthenticated());
            //  System.out.println("调用logout");
            //  subject.logout();
         System.out.println("是否认证:"+subject.isAuthenticated());
        } catch (UnknownAccountException e) {
              System.out.println("账户异常:"+e.getMessage());
        }catch (IncorrectCredentialsException e)
        {
            System.out.println("密码异常:"+e.getMessage());
        }catch (AuthenticationException e){
    
              System.out.println(e.getMessage());
        }
    
        PrincipalCollection principals = subject.getPrincipals();
    
          System.out.println("验证成功的用户名:"+principals+"   验证成功的realm:"+principals.getRealmNames());
    }
    
    

    user.properties

    user.admin=111
    user.tom=666
    
    

    shiro.ini

    #配置数据源
    
    dataSource=com.alibaba.druid.pool.DruidDataSource
    dataSource.driverClassName=com.mysql.jdbc.Driver
    dataSource.url=jdbc:mysql://localhost:3306/shiro?useUnicde=false&characterEncoding=utf-8
    dataSource.username=root
    dataSource.password=123456
    
    # 使用JdbcRealm
    
    jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
    #注入数据源
    jdbcRealm.dataSource=$dataSource
    #重写认证sql语句
    jdbcRealm.authenticationQuery=select password from t_user where login_name=?
    
    # 使用自定义Reaml
    
    propertiesRealm= shiro02.realm.PropertiesRealm
    propertiesRealm.path=classpath:shiro02/user.properties
    
    #认证器
    authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
    
    # 认证策略
    
     #   第一种: 最少有一个Realm验证成功即可,返回所有Realm身份验证成功的验证消息
    authenticationStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy
    
     #   第二种: 最少有一个Realm验证成功即可,返回第一个Realm身份验证成功的消息。
    authenticationStrategy=org.apache.shiro.authc.pam.FirstSuccessfulStrategy
    
     #   第三种: 必须所有Realm认证成功。
    authenticationStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
     authenticator.authenticationStrategy=$authenticationStrategy
    
    #将认证器添加到securityManager
    securityManager.authenticator=$authenticator
    
    
    
    
    securityManager.realms=$jdbcRealm,$propertiesRealm
    
    

    sql 语句

    drop database if exists shiro;
    
    create database shiro  charset utf8 ;
    
    use shiro;
    
    create table t_user
    (
    id int primary key auto_increment,
    login_name varchar(200) not null  unique,
    password varchar(200)
    )engine=Innodb charset utf8;
    
    insert  into t_user(login_name,password)values('admin','111');
    insert into t_user(login_name,password)values('tom','222');
    

    密码加密

    编码/解码

    两种方式 base64和十六进制

    • base64
    public void test01(){
    
    
    
        //编码
        String str="hello shrio";
        String encodeToString = Base64.encodeToString(str.getBytes());
          System.out.println(encodeToString);
    
        //解码
    
        String decodeToString = Base64.decodeToString(encodeToString);
          System.out.println(decodeToString);
    
    }
    
    
    • 十六进制
    @Test
       public void test2()
       {
           String str2="hello Hex";
    
           String encodingToString= org.apache.shiro.codec.Hex.encodeToString(str2.getBytes());
             System.out.println(encodingToString);
    
           String decodeToString=new String(Hex.decode(encodingToString));
             System.out.println(decodeToString);
    
       }
    
    

    散列加密

    • md5
    String str="hello md5";
    
    //普通MD5 安全一般
      String str1=new Md5Hash(str).toString();
      System.out.println(str1);
    
    //带盐值加密 安全中等
    
    String salt="saltHello"; 
    
    String str2=new Md5Hash(str,salt).toBase64();
      System.out.println(str2);
    
    //盐值散列次数 非常安全
    
    String str3=new Md5Hash(str,salt,3).toBase64();
      System.out.println(str3);
    

    SHA 加密

    //三种方式
    String username="toms";
    String password="123";
    String s1=new Sha1Hash(password,username,3).toHex();
    String s2=new Sha256Hash(password,username,3).toHex();
    String s3=new Sha512Hash(password,username,3).toHex();
    
    System.out.println(s1);
    System.out.println(s2);
    System.out.println(s3);
    
    
    

    shiro 加密工具类

    SimpleHash

    String password="zhangsan123";
    String salt="salt";
    
    String md5str1 = new SimpleHash("md5",password,salt).toBase64();
    String md5str2 = new SimpleHash("md5",password,salt,5).toBase64();//散列次数
    
    String sha1str = new SimpleHash("sha1",password,salt).toBase64();
    String sha2str = new SimpleHash("sha1",password,salt,5).toBase64();//散列次数
    
    String sha256str = new SimpleHash("sha-256",password,salt).toBase64();
    String sha256str2 = new SimpleHash("sha-256",password,salt,5).toBase64();//散列次数
    
    System.out.println(md5str1);
    System.out.println(md5str2);
    System.out.println(sha1str);
    System.out.println(sha2str);
    System.out.println(sha256str);
    System.out.println(sha256str2);
    

    PasswordService

    它用于对明密码进行加密,以及判断密码是否匹配。 PasswordService是个接口它实现了DefaultPasswordService。

    • 默认
      DefaultPasswordService默认使用的加密SHA-256和散列次数500000次,如果不想使用它可以重写PasswordService接口,实现自定义。
    public static final String DEFAULT_HASH_ALGORITHM = "SHA-256";
    public static final int DEFAULT_HASH_ITERATIONS = 500000; //500,000
    
    String password="pwd123";
    
    PasswordService passwordService=new DefaultPasswordService();
    String encryptPassword = passwordService.encryptPassword(password);
      System.out.println(encryptPassword);
    
    • 自定义:
      PasswordSerivceImpl
    public class PasswordSerivceImpl  implements PasswordService{
    
        private String algorithmName;//算法名称
    
        private String salt;//盐值
    
        private int hashInterations;//散列次数
    
        /*
        * 用于对文明密码进行加密
        * */
        @Override
        public String encryptPassword(Object plaintextPassword) throws IllegalArgumentException {
    
           return new SimpleHash(algorithmName,plaintextPassword,salt,hashInterations).toBase64();
        }
    
        /*
        * 用于密码进行匹配
        * */
        @Override
        public boolean passwordsMatch(Object submittedPlaintext, String encrypted) {
    
            String encryPassword=encryptPassword(submittedPlaintext);
            return  encryPassword.equals(encryPassword);
    
        }
    
        public void setAlgorithmName(String algorithmName) {
            this.algorithmName = algorithmName;
        }
    
        public void setSalt(String salt) {
            this.salt = salt;
        }
    
        public void setHashInterations(int hashInterations) {
            this.hashInterations = hashInterations;
        }
    }
    
    
    

    test

    String password="pwd123";
    String salt="salt";
    
    PasswordSerivceImpl passwordService=new PasswordSerivceImpl();
    passwordService.setAlgorithmName("sha1");
    passwordService.setHashInterations(4);
    passwordService.setSalt(salt);
    String encryptPassword = passwordService.encryptPassword(password); //加密
    System.out.println(encryptPassword);
    
    boolean passwordsMatch = passwordService.passwordsMatch(password, encryptPassword);//判断是否匹配
      System.out.println(passwordsMatch);
    
    

    CredentialsMatcher

    CredentialsMatcher实现类

    SimpleCredentialsMatcher

    默认的密码匹配器,直接判断密码是否相同。

    HashedCredentialsMatcher

    散列密码匹配器。这个类可以对密码加密做比较,但是如果用盐值加密的数据,数据库中如果没有password_salt列的话又无法直接比较。如果数据库中没有password_salt列 ,又想使用盐值则需要重写JdbcRealm

    • 不带盐值,普通的加密,如md5
      可以查看 CredentialsMatcher 实现类
    protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?";
    

    shiro.ini

    #配置数据源
    dataSource=com.alibaba.druid.pool.DruidDataSource
    dataSource.driverClassName=com.mysql.jdbc.Driver
    dataSource.url=jdbc:mysql://localhost:3306/shiro?useUnicde=false&characterEncoding=utf-8
    dataSource.username=root
    dataSource.password=123456
    # 使用JdbcRealm
    
    jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
    jdbcRealm.dataSource=$dataSource
    jdbcRealm.authenticationQuery=select password from t_user where login_name=?
    #配置密码匹配器 如果不配置默认调用的是SimpleCredentialsMatcher,它只是对两个密码不错任何操作直接判断。
    credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
    credentialsMatcher.hashAlgorithmName=md5 //只采用md5加密
    
    #将密码匹配器注入到JdbcRealm中
    jdbcRealm.credentialsMatcher=$credentialsMatcher
    securityManager.realms=$jdbcRealm
    

    main

    
    public static void main(String[] args) {
    
     Subject subject= ShiroUtils.getSubject("classpath:shiro04/shiro.ini");
    
        UsernamePasswordToken token=new UsernamePasswordToken("tom","123");
    
        try {
    
            subject.login(token);
    
         System.out.println("是否认证:"+subject.isAuthenticated());
    
    
        } catch(UnknownAccountException e){
            System.out.println("未知的账户!e:"+e.getMessage());
        } catch (IncorrectCredentialsException e){
            System.out.println("错误的密码!e:"+e.getMessage());
        } catch (AuthenticationException e) {
            System.out.println("认证异常!e:"+e.getMessage());
        }
    
    
    }
    
    • 带盐值
      main
    
    public static void main(String[] args) {
    
     Subject subject= ShiroUtils.getSubject("classpath:shiro04/shiro.ini");
    
        UsernamePasswordToken token=new UsernamePasswordToken("tom","123");
    
    
    
        try {
    
            subject.login(token);
    
         System.out.println("是否认证:"+subject.isAuthenticated());
    
    
        } catch(UnknownAccountException e){
            System.out.println("未知的账户!e:"+e.getMessage());
        } catch (IncorrectCredentialsException e){
            System.out.println("错误的密码!e:"+e.getMessage());
        } catch (AuthenticationException e) {
            System.out.println("认证异常!e:"+e.getMessage());
        }
    
    
    }
    
    

    JdbcsaltRealm

    public class JdbcsaltRealm extends JdbcRealm {
    
        public JdbcsaltRealm()
        {
            setSaltStyle(SaltStyle.COLUMN);
        }
    }
    
    

    shiro.ini

    #配置数据源
    
    dataSource=com.alibaba.druid.pool.DruidDataSource
    dataSource.driverClassName=com.mysql.jdbc.Driver
    dataSource.url=jdbc:mysql://localhost:3306/shiro?useUnicde=false&characterEncoding=utf-8
    dataSource.username=root
    dataSource.password=123456
    
    # 使用自定义的JdbcsaltRealm
    
    jdbcRealm=shiro04.JdbcsaltRealm
    jdbcRealm.dataSource=$dataSource
    # 重写带salt语句 以login_name当盐值
    jdbcRealm.authenticationQuery=select password,login_name from t_user where login_name=?
    
    
    #配置密码匹配器
    credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
    credentialsMatcher.hashAlgorithmName=md5
    credentialsMatcher.hashIterations=3
    #将密码匹配器注入到JdbcRealm中
    jdbcRealm.credentialsMatcher=$credentialsMatcher
    
    securityManager.realms=$jdbcRealm
    
    
    
  • 相关阅读:
    自学it18大数据笔记-第三阶段Scala-day03——会持续更新……
    自学it18大数据笔记-第三阶段Scala-day01+~day02——会持续更新……
    自学it18掌大数据笔记-第三阶段Scala-day00-day01——会持续更新……
    自学it18大数据笔记-第三阶段Storm-day5——会持续更新……
    自学it18大数据笔记-第三阶段Storm-day4——会持续更新……
    自学it18大数据笔记-第三阶段Storm-day2-day3——会持续更新……
    自学it18大数据笔记-第三阶段Storm-day1——会持续更新……
    自学it18大数据笔记-第二阶段Sqoop-day1——会持续更新……
    自学it18大数据笔记-第二阶段Pig-day1——会持续更新……
    自学it18大数据笔记-第二阶段Kafka-day2——会持续更新……
  • 原文地址:https://www.cnblogs.com/lilihai/p/10144065.html
Copyright © 2011-2022 走看看