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


posted @ 2018-12-19 16:24  小朋友写代码  阅读(182)  评论(0编辑  收藏  举报