基本概念
-
身份验证
即在应用中谁能证明他就是他本人。一般提供如他们的身份ID 一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明。
在 shiro 中,用户需要提供principals(身份)和credentials(证明)给shiro,从而应用能验证用户身份。
-
principals(身份)
身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。 一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。
-
credentials(证明)
证明/凭证,即只有主体知道的安全值,如密码/数字证书等。 最常见的principals和credentials组合就是用户名/密码了。
认证流程
1、调用Subject.login(token)
进行登录,其会自动委托给Security Manager,调用之前必须通过SecurityUtils.setSecurityManager()
设置。
2、Security Manager负责真正的身份验证逻辑,它会委托给Authenticator进行身份验证。
3、Authenticator才是真正的身份验证者,Shiro API中核心的身份认证入口点,此处可以自定义自己的实现。
4、Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证。
5、Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份验证失败。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。
入门程序实现认证
1、创建项目,创建普通的Maven工程。
2、在pom.xml中导入依赖
<!-- shiro核心包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.6</version>
</dependency>
3、log4j.properties日志配置文件
log4j.rootLogger=debug, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
4、在src/java/resources下新建shiro.ini文件
# 配置用户名和密码
[users]
zhangsan=123456
lisi=123456
5、编写代码实现认证
package com.coydone.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
public class AuthUserTeat {
public static void main(String[] args) {
//1、接收用户名和密码
String username = "zhangsan";
String password = "123456";
//2、把用户名和密码封装
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
//3、创建安全管理器的工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//4、从Factory中得到安全管理器
SecurityManager securityManager = factory.getInstance();
//5、把securityManager和Subject绑定到当前线程
SecurityUtils.setSecurityManager(securityManager);
//6、从SecurityUtils中得到subject
Subject subject = SecurityUtils.getSubject();
//7、去认证
try {
subject.login(token);
System.out.println("认证通过");
} catch (AuthenticationException e) {
System.out.println("用户名或密码不正确");
}
/*
catch (IncorrectCredentialsException e) {
System.out.println("密码不正确");
} catch (UnknownAccountException e) {
System.out.println("用户名不存在");
}
*/
//8、查看认证状态
System.out.println("认证状态:"+subject.isAuthenticated());
//9、退出
subject.logout();
System.out.println("认证状态:"+subject.isAuthenticated());
}
}
自定义Realm完成认证
Shiro默认使用自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义realm。
最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权,通常自定义的realm继承AuthorizingRealm。
1、自定义UserRealm
package com.coydone.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;
public class UserRealm extends AuthorizingRealm {
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//1、得到身份
String username = token.getPrincipal().toString();
//得到凭证
//String password = token.getCredentials().toString();
//在shiro里面是先根据用户名把用户对象查询出来,再来做密码匹配
//2,根据用户名到数据库中取出用户信息 如果查询不到 返回null 可以使用service来查
String password = "123456";//假如从数据库中获取密码为1111
//3,返回认证信息
/**
* 参数1:可以传到任意对象,如果登录成功,会调用doGetAuthorizationInfo去授权
* 参数2:从数据库里面查询出来的密码
* 参数3:当前类名
*/
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, this.getName());
return simpleAuthenticationInfo;
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
2、配置shiro.ini文件
# 作全局配置
[main]
# 创建UserRealm的对象
userRealm=com.coydone.realm.UserRealm
# 创建默认的安全管理器
securityManager=org.apache.shiro.mgt.DefaultSecurityManager
# 把userRealm给安全管理器
securityManager.realms=$userRealm
3、测试(测试代码同上)
public class AuthUserTeat {}