Shiro学习_02(认证)
Shiro身份验证
- 认证: 判断一个用户是否为合法用户的处理过程。即提供用户名和密码,检验是否与数据库存储的用户名密码一致。
Shrio中认证的管家对象
- Subject:主体
访问系统的用户
- Principal:身份信息
身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。
一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号
- Credential:凭证信息
证明 / 凭证,即只有主体知道的安全值,如密码 / 数字证书等。
认证流程
使用加密认证(MD5+Salt+Hash)
MD5加密
package com.shiro.util;
import org.apache.shiro.crypto.hash.Md5Hash;
import java.util.UUID;
public class TestShiroMD5 {
public static void main(String[] args) {
// 可以使用uuid作为盐值
String uuid = UUID.randomUUID().toString().replace("-", "");
System.out.println("UUID: "+uuid);
// 使用md5 + salt + hash散列(参数代表要散列多少次,一般是 1024或2048)
Md5Hash md5Hash2 = new Md5Hash("123456", uuid, 1024);
System.out.println(md5Hash2.toHex());
}
}
- 输出
UUID: 3e451cd1bce14b5e86588a13559c83d6
094aa06418bda3cbb3cb61c875e6c5a9
自定义加密的Realm
package com.shiro.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
/**
* 使用自定义realm 加入md5 + salt +hash
*/
public class CustomerMd5Realm extends AuthorizingRealm {
/**
* 授权
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
/**
* 认证
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取token中的用户名和密码
String principal = (String) token.getPrincipal();
String credentials = new String((char[]) token.getCredentials());
// 模拟数据库查询到的信息
String username = "shiro";
// 密码使用MD5生成加密后的密码”123456“
String password = "094aa06418bda3cbb3cb61c875e6c5a9";
// 使用uuid生成的值作为盐值
String salt = "3e451cd1bce14b5e86588a13559c83d6";
// 根据用户名查询数据库
if (username.equals(principal)) {
/**
* 依次传入:账号信息、加密后的密码、密码加密的盐值、当前realm对象的name
*/
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal
, password
, ByteSource.Util.bytes(salt)
, this.getName());
return simpleAuthenticationInfo;
}
return null;
}
}
使用加密Realm认证
package com.shiro.test;
import com.shiro.realm.CustomerMd5Realm;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
@Slf4j
public class TestCustomerMd5RealmAuthenicator {
public static void main(String[] args) {
// 1.创建安全管理员
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
// 2.注入realm
CustomerMd5Realm realm = new CustomerMd5Realm();
// 3.设置realm使用hash凭证匹配器
HashedCredentialsMatcher credentialsMathcher = new HashedCredentialsMatcher();
// 设置使用的算法
credentialsMathcher.setHashAlgorithmName("md5");
// 设置散列次数
credentialsMathcher.setHashIterations(1024);
realm.setCredentialsMatcher(credentialsMathcher);
defaultSecurityManager.setRealm(realm);
// 4.将安全管理器注入安全工具
SecurityUtils.setSecurityManager(defaultSecurityManager);
// 5.通过安全工具类获取subject
Subject subject = SecurityUtils.getSubject();
// 6.认证
UsernamePasswordToken token = new UsernamePasswordToken("shiro", "123456");
try {
subject.login(token);
log.info("登录成功");
} catch (UnknownAccountException e) {
e.printStackTrace();
log.error("用户名错误");
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
log.error("密码错误");
}
}
}
未加密
自定义Realm
package com.shiro.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* 自定义Realm
*/
public class CustomerRealm extends AuthorizingRealm {
/**
* 授权
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
/**
* 认证
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 从token中获取用户名
String principal = (String) token.getPrincipal(); //得到用户名
String credentials = new String((char[])token.getCredentials()); //得到密码
System.out.println(principal);
System.out.println(credentials);
// 在实际开发中,用户身份信息是从数据库中查询的
// 假设从数据库中获取了用户名和密码
String username = "shiro";
String password = "123456";
if (username.equals(principal)) {
/**
* principal: 数据库的用户名
* password: 数据库的密码
* this.getName(): 提供当前realm的名字
*/
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal
, password
, this.getName());
return simpleAuthenticationInfo;
}
return null;
}
}
使用未加密Realm认证
package com.shiro.test;
import com.shiro.realm.CustomerRealm;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
/**
* 测试自定义的Realm
*/
@Slf4j
public class TestAuthenticatorCusttomerRealm {
public static void main(String[] args) {
// 1.创建安全管理对象securityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
// 2.给安全管理器设置realm(设置为自定义realm获取认证数据)
defaultSecurityManager.setRealm(new CustomerRealm());
// 3.给安装工具类中设置默认安全管理器
SecurityUtils.setSecurityManager(defaultSecurityManager);
// 4.获取主体对象subject
Subject subject = SecurityUtils.getSubject();
// 5.创建token令牌
UsernamePasswordToken token = new UsernamePasswordToken("shiro", "123456");
try {
// 用户登录
subject.login(token);
log.info("登陆成功");
} catch (UnknownAccountException e) {
e.printStackTrace();
log.error("用户名或密码错误");
}
}
}