一 认证
1.1 认证
身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。
1.2 认证角色中的对象
-
Subject:主体
访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体;
-
Principal:身份信息
是主体(subject)进行身份认证的标识,标识必须具有唯一性
,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)。
-
credential:凭证信息
是只有主体自己知道的安全信息,如密码、证书等
1.3 认证流程
二 简单认证流程
2.1 pom文件
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.5.3</version>
</dependency>
2.2 shiro信息配置文件
创建shiro.ini配置文件,放到resource文件目录下,写入的内容,如下:
2.3 验证代码
public class TestAuthenticator {
public static void main(String[] args) {
//创建securityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(new IniRealm("classpath:shiro.ini"));
//将安装工具类中设置默认安全管理器
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取主体对象
Subject subject = SecurityUtils.getSubject();
//创建token令牌
UsernamePasswordToken token = new UsernamePasswordToken("xiaochen1", "123");
try {
subject.login(token);//用户登录
System.out.println("登录成功~~");
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("用户名错误!!");
}catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("密码错误!!!");
}
}
}
执行结果:
将用户配置文件中正确的用户:
public class TestAuthenticator {
public static void main(String[] args) {
//创建securityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(new IniRealm("classpath:shiro.ini"));
//将安装工具类中设置默认安全管理器
SecurityUtils.setSecurityManager(defaultSecurityManager);
//获取主体对象
Subject subject = SecurityUtils.getSubject();
//创建token令牌
UsernamePasswordToken token = new UsernamePasswordToken("lisi", "123");
try {
subject.login(token);//用户登录
System.out.println("登录成功~~");
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("用户名错误!!");
}catch (IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("密码错误!!!");
}
}
}
执行结果:
2.4 源码的流程
认证:
1.最终执行用户名比较 SimpleAccountRealm
doGetAuthenticationInfo 在这个方法中完成用户名的校验
2.最终密码校验是在AuthenticationRealm中
assertCredentialsMatch
总结:AuthenticatingRealm 认证的realm DoGetAuthenticationInfo方法
AuthorizatingRealm 授权realm DoGetAuthorizationInfo方法
三 Ream
3.1 reaml的作用
上边的程序使用的是Shiro自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm。
shiro提供的realm如下图所示:
2.认证源码使用的SimpleAccountRealm
SimpleAccountRealm的部分源码中有两个方法一个是 认证 一个是 授权
, (AuthenticatingReaml有DoGetAuthenticationInfo()方法,AuthorizatingRealm有DoGetAuthorizationInfo()方法,AuthorizatingRealm继承AuthenticatingReaml,则同时具有了DoGetAuthenticationInfo()和DoGetAuthorizationInfo()两个方法,而SimpleAccountRealm继承AuthorizatingRealm,则SimpleAccountRealm同样具有DoGetAuthenticationInfo()和DoGetAuthorizationInfo()两个方法的功能)
3.2 自定义realm
1.调用类:
package com.shiro.ljf.demo.test;
import com.shiro.ljf.demo.sptshirodemo.shiro.CustomerDefineRealm;
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.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
/**
* 使用自定义realm
*/
public class TestCustomerRealmAuthenticator {
public static void main(String[] args) {
//创建securityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//设置自定义realm
defaultSecurityManager.setRealm(new CustomerDefineRealm());
//将安全工具类设置安全工具类
SecurityUtils.setSecurityManager(defaultSecurityManager);
//通过安全工具类获取subject
Subject subject = SecurityUtils.getSubject();
//创建token
UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123");
try {
subject.login(token);
System.out.println(subject.isAuthenticated());
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("用户名错误");
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
System.out.println("密码错误");
}
//认证用户进行授权
if(subject.isAuthenticated()){
//1.基于角色权限控制
System.out.println(subject.hasRole("admin"));
}
}
}
2.自定义CustomerDefineRealm
package com.shiro.ljf.demo.sptshirodemo.shiro;
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;
/**
* @ClassName: CustomerDefineRealm
* @Description: TODO 自定义realm实现 将认证|授权数据的来源转为数据库的实现
* @Author: liujianfu
* @Date: 2021/05/29 19:23:30
* @Version: V1.0
**/
public class CustomerDefineRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("==================");
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//在token中获取用户名
String principal = (String) token.getPrincipal();
System.out.println(principal);
//根据身份信息使用jdbc mybatis查询相关数据库
if("lisi".equals(principal)){
//参数1:返回数据库中正确的用户名 //参数2:返回数据库中正确密码 //参数3:提供当前realm的名字 this.getName();
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal,"123",this.getName());
return simpleAuthenticationInfo;
}
return null;
}
}
3.调试
4. 改为正确的用户名
验证通过后,调用
System.out.println(" hou:"+subject.isAuthenticated()); 则会返回true。