shiro实现不同身份使用不同Realm进行验证
- 格式:doc
- 大小:49.00 KB
- 文档页数:18
withidentity方法“withIdentity方法”,以中括号内的内容为主题,写一篇1500-2000字文章,一步一步回答引言:在软件开发中,身份验证是非常重要的一个方面。
当用户需要访问系统的特定资源时,系统需要验证其身份,以确保只有授权用户才能进行访问。
withIdentity方法是一种用于创建和管理用户身份的功能,它为开发人员提供了一种简单而强大的方法来进行身份验证。
第一部分:什么是withIdentity方法withIdentity方法是一种用于创建用户身份的方法。
它是Apache Shiro 身份验证和授权框架中的一部分,用于创建一个表示用户身份的SimplePrincipalCollection对象。
这个方法接受一个参数,该参数可以是用户名、用户ID或其他标识用户身份的值。
第二部分:withIdentity方法的使用步骤使用withIdentity方法可以分为以下几个步骤:1. 引入Apache Shiro库:首先,需要引入Apache Shiro库到项目中。
可以通过在项目的依赖管理文件(如pom.xml)中添加Apache Shiro的依赖项来实现。
2. 创建Subject对象:在进行用户身份验证之前,需要创建Subject对象。
Subject对象代表了当前的用户。
3. 创建和配置Realm对象:Realm是Shiro中的一个关键组件,它负责进行身份验证和授权。
创建Realm对象并进行相应的配置,以实现和用户身份相关的操作。
4. 实例化SimplePrincipalCollection对象:使用withIdentity方法之前,需要实例化一个SimplePrincipalCollection对象。
SimplePrincipalCollection是Shiro中表示用户身份的类,通过将代表用户身份的值传递给构造函数来创建对象。
5. 调用withIdentity方法:调用withIdentity方法,将用户身份值作为参数传递给方法。
Springboot+Shiro记录⽤户登录信息并获取当前登录⽤户信息的实现代码由于最近做项⽬需要,在⽤户登陆后有⼀个功能是需要⽤户的信息,进⾏写⼊数据库的操作。
但是⽬前还⽤不到Shiro的⾼级权限,只为了简单获取⽤户信息,⾃⼰整合了⼀个只记录⽤户,获取⽤户信息的功能。
导⼊Shiro依赖<!-- Shiro --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.4.0</version></dependency>User类这个类只需要⾃⼰定义⼀个username(可以其他的phone、email都⾏)和password(密码)就可以,其他的可以⾃⼰扩充。
UserRealm(核⼼)这个类的功能:1、⽤户的授权操作,但是这⾥先不授予权限(后续可以在这⾥补充)2、⽤户认证,这⾥有三种认证结果。
①⽤户登录成功②抛出UnknownAccountException异常,表⽰获取的user是null 。
③抛出IncorrectCredentialsException异常,表⽰这个user的密码错误。
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 ernamePasswordToken;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;/*** ⾃定义Realm*/public class UserRealm extends AuthorizingRealm {@Autowired(required = false)private UserService userService;private final Logger logger = LoggerFactory.getLogger(UserRealm.class);/*** 执⾏授权逻辑** @param arg0* @return*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {System.out.println("执⾏授权逻辑");//给资源进⾏授权SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//不授权先不写return info;}/*** 执⾏认证逻辑** @param arg0* @return* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {System.out.println("执⾏认证逻辑"); // 编写shiro判断逻辑,判断⽤户名和密码UsernamePasswordToken token = (UsernamePasswordToken) arg0; // 判断⽤户名User user = userService.findUserByPhone(token.getUsername());if (user == null) { // 该⽤户不存在return null; // shiro底层会抛出UnKnowAccountException}return new SimpleAuthenticationInfo(user, user.getPassword(), ""); // 判断密码}}ShiroConfig类(核⼼)代码基本不需要修改,根据个⼈不同的情况,需要修改的地⽅是第⼀个⽅法。
shiro验证权限的流程以shiro验证权限的流程为标题,下面将详细介绍shiro验证权限的流程。
一、什么是shiro验证权限shiro是一个强大且易于使用的Java安全框架,用于身份验证、授权和加密。
它提供了一个可插拔的架构,使开发者可以轻松地集成shiro到他们的应用程序中,并通过简单的配置来实现身份验证和授权功能。
1. 配置shiro安全管理器:首先,我们需要配置一个shiro安全管理器。
安全管理器是shiro的核心组件,负责协调整个身份验证和授权过程。
我们可以通过编写一个shiro配置文件来配置安全管理器,指定所需的身份验证和授权策略。
2. 编写自定义realm:realm是shiro与应用程序进行交互的接口,负责从应用程序中获取用户的身份信息和权限信息。
我们需要编写一个自定义的realm,实现shiro的Realm接口,并重写其中的方法,以便从数据库或其他存储中获取用户的身份和权限信息。
3. 进行身份验证:一旦配置好安全管理器和自定义realm,我们就可以使用shiro进行身份验证了。
首先,用户提交用户名和密码进行登录,shiro会调用自定义realm中的方法,根据用户名从数据库中获取用户的密码,并与用户输入的密码进行比较。
如果密码匹配成功,说明用户身份验证通过;否则,验证失败。
4. 进行授权验证:身份验证通过后,shiro会根据配置的授权策略,判断用户是否具有访问某个资源的权限。
shiro提供了多种授权策略,如基于角色的授权、基于权限的授权等。
我们可以通过在自定义realm中返回用户的角色和权限信息来进行授权验证。
5. 实现权限控制:一旦用户被授权访问某个资源,我们还可以在代码中进行权限控制,以确保用户只能访问他们被授权的资源。
shiro 提供了一些注解和标签,如@RequiresRoles、@RequiresPermissions等,可以方便地在代码中进行权限控制。
6. 处理无权限访问:如果用户没有被授权访问某个资源,我们可以通过配置shiro的未授权页面,将用户重定向到一个友好的页面,或返回相应的错误信息。
shiro认证流程Shiro是一个Java安全框架,用于管理用户认证和授权。
Shiro框架提供了强大的认证和授权功能,可以轻松地集成到Java应用程序中。
下面将介绍Shiro认证的基本流程,包括主体查询、凭证匹配、身份认证、认证结果处理等。
1. 主体查询:认证流程的第一步是查询主体的信息。
主体可以是用户、设备或其他可以进行身份认证的实体。
在Shiro框架中,主体由一个唯一标识符表示,通常是用户名或用户ID。
2. 凭证匹配:一旦确定了要认证的主体,就需要验证其相关的凭证。
凭证可以是密码、指纹、证书等。
在认证之前,Shiro通常将凭证存储在一个Realm中,以便在需要时进行匹配。
Realm是Shiro认证的关键组件,它负责查询用户信息、获取用户凭证等操作。
3. 身份认证:凭证匹配成功后,Shiro会对主体进行身份认证。
身份认证是确认主体的身份是否合法的过程。
在这个步骤中,Shiro通过验证主体的凭证来确保主体的身份与凭证的匹配。
4. 认证结果处理:一旦身份认证成功,Shiro可以选择将认证结果存储在会话管理器中,以便随后的请求可以继续访问已通过身份认证的资源。
此外,还可以通过回调方法、事件监听器等方式处理认证结果。
整个Shiro认证流程可以通过以下步骤来总结:1.查询主体信息2.凭证匹配3.身份认证4.认证结果处理除了上述基本认证流程外,Shiro还提供了许多扩展功能,以满足不同应用场景的需求。
例如,可以通过配置文件进行认证配置,允许多种认证方式,支持单点登录等。
Shiro还提供了可插拔的认证策略,可以根据具体的应用需求进行配置。
例如,可以通过配置决定是将认证结果存储在缓存中还是持久化到数据库中。
总结起来,Shiro认证流程是一个灵活且可扩展的流程。
通过了解Shiro的认证流程,开发人员可以更好地了解Shiro框架的工作原理,并根据具体需求进行配置和定制。
shiro是啥Shiro的核心组件介绍Shiro是一个强大且易用的Java安全框架,它提供了身份验证、授权、加密和会话管理等关键安全功能。
下面对Shiro的核心组件进行详细介绍:1. Subject:Subject是Shiro的核心概念,表示当前正在执行操作的用户。
Subject是一个抽象概念,可以是一个人、一个服务或者一个设备。
Subject可以执行身份验证、授权和会话等操作。
2. SecurityManager:SecurityManager是Shiro的核心组件,负责所有的安全操作。
它是Subject执行操作的入口点,并且管理所有的安全操作。
SecurityManager可以将身份验证、授权和会话管理等功能委托给相应的组件实现。
3. Authenticator:Authenticator负责验证Subject的身份信息。
Shiro支持多种身份验证方式,包括用户名/密码验证、证书验证和第三方认证等。
Authenticator使用配置好的Realm(下面会介绍)获取Subject的身份信息进行验证。
4. Authorizer:Authorizer负责授权操作。
在身份验证成功之后,Authorizer通过用户的角色和权限信息确定用户是否有权限执行特定的操作。
Authorizer使用配置好的Realm获取用户的角色和权限信息。
5. Realm:Realm是Shiro与应用程序进行交互的桥梁,负责获取应用程序保存的用户、角色和权限信息。
Shiro支持多种Realm实现,包括数据库、LDAP、Active Directory等。
开发者可以根据自己的需求选择不同的Realm实现。
6. SessionManager:SessionManager负责管理用户的会话信息。
Shiro可以将用户的会话信息存储在多种存储介质上,如内存、数据库或者缓存中。
SessionManager提供了会话的创建、销毁和管理等功能。
shiro simpleauthenticationinfo() 构造方法讲解**一、背景介绍**Shiro是一个广泛使用的Java安全框架,它提供了身份认证、授权、会话管理和加密等功能。
在Shiro中,AuthenticationInfo类是用于存储和操作身份验证信息的核心类。
其中,simpleAuthenticationInfo()方法则是用于创建一个新的AuthenticationInfo对象,用于存储用户的身份验证信息。
**二、构造方法详解**simpleAuthenticationInfo()方法接受一个用户名和一个Realm 对象作为参数。
这个方法会根据提供的用户名和Realm对象创建一个新的AuthenticationInfo对象。
这个对象包含了用户名、密码以及其他身份验证信息。
这个方法的构造过程大致分为三个步骤:1. 创建一个新的AuthenticationInfo对象,并设置其属性。
这些属性包括用户名、密码、Realm对象等。
2. 根据Realm对象中的配置,对用户名和密码进行验证。
如果验证通过,则将用户名和Realm对象存储在AuthenticationInfo对象中。
3. 如果验证失败,则会抛出一个异常。
值得注意的是,simpleAuthenticationInfo()方法返回的是一个ReadOnlyAuthenticationInfo对象,这是因为Shiro的安全机制要求身份验证信息只能读取,不能修改。
**三、使用示例**下面是一个简单的使用示例:```java// 创建一个Realm对象,用于存储用户的信息和配置MyRealm realm = new MyRealm();// 创建一个用户名(例如"john")String username = "john";// 使用simpleAuthenticationInfo()方法创建一个新的AuthenticationInfo对象ReadOnlyAuthenticationInfo info = SimpleAuthenticationInfo.createReadOnly(username, "password", realm);```在这个示例中,我们创建了一个名为"john"的用户,并使用simpleAuthenticationInfo()方法创建了一个新的AuthenticationInfo对象,该对象包含了用户名"john"和密码"password"。
shiro 原理Shiro是一个强大的Java安全框架,它提供了身份验证、授权、密码学和会话管理等功能。
Shiro的核心原理是将安全性集成到应用程序中,以保护应用程序免受未经授权的访问和攻击。
一、Shiro架构Shiro采用了模块化的架构,包括Subject、SecurityManager和Realm三个核心组件。
1. SubjectSubject是Shiro中的核心对象,它代表当前用户。
Subject可以是一个人、一个程序或者其他实体。
Subject可以执行身份验证和授权操作,并且可以与应用程序交互。
2. SecurityManagerSecurityManager是Shiro的核心组件之一,它负责处理所有与安全相关的操作。
SecurityManager维护了一个或多个Realm,并通过这些Realm来执行身份验证和授权操作。
3. RealmRealm是Shiro中的数据源,它负责从数据库或其他数据源中获取用户信息并进行身份验证和授权操作。
每个Realm都有自己的一组规则来确定如何处理用户信息。
二、Shiro认证流程1. 用户登录当用户输入用户名和密码时,Subject会将这些凭据传递给SecurityManager进行身份验证。
SecurityManager会使用其中一个或多个Realm来验证凭据。
2. Realm身份验证每个Realm都有自己的一组规则来确定如何处理用户信息。
在进行身份验证时,Realm会从数据库或其他数据源中获取用户信息,并将其与传递的凭据进行比较。
如果凭据匹配,则身份验证成功,否则失败。
3. 认证结果返回当身份验证完成后,SecurityManager将认证结果返回给Subject。
如果认证成功,则Subject可以继续执行操作,否则需要重新输入凭据。
三、Shiro授权流程1. 用户访问资源当用户尝试访问应用程序中的资源时,Subject会将请求传递给SecurityManager进行授权操作。
shiro的使用的步骤Shiro是一个开源的Java安全框架,用于简化应用程序的身份验证、授权、加密等安全操作。
它提供了一套易于使用的API和一系列可配置的组件,以帮助开发者快速实现安全功能。
下面是使用Shiro的一般步骤:1. 引入Shiro依赖:首先,我们需要在项目中引入Shiro的依赖库。
可以通过Maven或手动下载并添加到项目中。
例如,在Maven 项目中,可以在POM文件中添加以下依赖:xml<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.8.0</version></dependency>2. 配置Shiro:在使用Shiro之前,我们需要配置Shiro的环境。
这包括配置安全策略、数据源、缓存等。
Shiro的配置可以通过properties文件、XML文件或编程方式进行。
- 配置文件方式:创建一个shiro.ini或shiro.xml文件,并配置相应的组件。
例如,定义一个基于用户名/密码的身份验证器:[main]myRealm = com.example.MyRealmsecurityManager.realms = myRealm[users]username=password- 编程方式:可以通过编写Java代码来配置Shiro的组件。
例如,以编程方式配置安全管理器:javaDefaultSecurityManager securityManager = new DefaultSecurityManager();securityManager.setRealm(new MyRealm());SecurityUtils.setSecurityManager(securityManager);3. 创建Realm:Realm是Shiro与应用程序数据交互的桥梁,用于身份验证、授权等操作。
shiro dogetauthenticationinfo重复调用-回复「shiro dogetauthenticationinfo重复调用」,这是一个关于Shiro框架中一个常见问题的主题,我们将一步一步地回答这个问题,帮助读者理解这个问题的原因及解决方案。
Shiro是一个强大而灵活的Java安全框架,用于身份验证、授权和会话管理。
在使用Shiro进行身份验证时,我们通常会遇到一些常见问题。
其中之一就是Shiro的doGetAuthenticationInfo方法重复调用的问题。
doGetAuthenticationInfo方法是Shiro中负责身份验证的方法,它用于验证用户的身份信息,并返回一个AuthenticationInfo对象。
在某些情况下,我们可能会发现doGetAuthenticationInfo方法被重复调用。
这会导致一些问题,例如产生不必要的数据库查询、性能下降等。
那么,为什么会发生doGetAuthenticationInfo方法重复调用的情况呢?下面是一些可能的原因:1. Shiro的配置错误:可能是因为我们在Shiro的配置中配置了多个Realm,而每个Realm都会调用doGetAuthenticationInfo方法。
这可能导致doGetAuthenticationInfo方法被多次调用。
2. 会话管理器的配置错误:在一些情况下,我们可能会错误地配置了Shiro的会话管理器。
会话管理器的配置错误可能导致会话无法正确地关闭或销毁,从而导致doGetAuthenticationInfo方法被重复调用。
3. 缓存的配置问题:Shiro提供了缓存的功能,用于提高性能。
然而,如果我们在缓存的配置中出现问题,可能会导致doGetAuthenticationInfo方法被重复调用。
了解了可能的原因后,下面是解决该问题的一些步骤:步骤1:检查Shiro的配置文件首先,我们应该检查Shiro的配置文件,确保配置中只使用一个Realm。
shiroconfig实例ShiroConfig是一个用来配置Apache Shiro安全框架的类。
在Java应用程序中,ShiroConfig类通常用来配置安全策略,定义用户认证和授权规则,以及配置与安全相关的其他设置。
下面我将从多个角度来介绍ShiroConfig的一些常见实例用法。
1. 用户认证和授权规则配置,在ShiroConfig中,你可以配置用户的认证方式,例如基于数据库的认证、LDAP认证或者其他自定义的认证方式。
同时,你也可以配置用户的授权规则,定义哪些用户有权访问哪些资源。
例如,你可以配置某个用户需要具备哪些角色或权限才能访问某个页面或执行某个操作。
2. 安全过滤器链配置,ShiroConfig可以用来配置安全过滤器链,定义哪些URL需要经过哪些安全过滤器的处理。
你可以根据具体的需求,配置不同的安全过滤器来实现对不同URL的访问控制,例如对某些URL进行身份认证、权限检查或者其他安全控制。
3. Realm配置,在ShiroConfig中,你可以配置Realm,用于验证用户的身份和获取用户的授权信息。
通过配置Realm,你可以将Shiro集成到现有的用户存储系统中,例如数据库、LDAP或者自定义的用户存储系统。
4. Session管理配置,ShiroConfig也可以用来配置会话管理,包括会话超时时间、会话存储方式、会话验证方式等。
你可以根据具体的需求,配置不同的会话管理策略来实现对用户会话的管理和控制。
5. RememberMe功能配置,ShiroConfig还可以配置RememberMe功能,用于实现用户的持久登录功能。
你可以配置RememberMe的加密方式、cookie名称、有效时间等参数,来实现对用户持久登录的支持。
综上所述,ShiroConfig在Apache Shiro安全框架中起着至关重要的作用,通过合理的配置,可以实现对用户认证、授权、安全过滤器链、Realm、会话管理和RememberMe功能等方面的灵活控制。
shiro实现不同身份使用不同Realm进行验证假设现在有这样一种需求:存在两张表user和admin,分别记录普通用户和管理员的信息。
并且现在要实现普通用户和管理员的分开登录,即需要两个Realm——UserRealm 和AdminRealm,分别处理普通用户和管理员的验证功能。
但是正常情况下,当定义了两个Realm,无论是普通用户登录,还是管理员登录,都会由这两个Realm共同处理。
这是因为,当配置了多个Realm时,我们通常使用的认证器是shiro自带的org.apache.shiro.authc.pam.ModularRealmAuthenticator,其中决定使用的Realm的是doAuthenticate()方法,源代码如下:protected AuthenticationInfodoAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {assertRealmsConfigured();Collection<Realm> realms = getRealms();if (realms.size() == 1) {returndoSingleRealmAuthentication(realms.iterator().next(), authenticationToken);} else {return doMultiRealmAuthentication(realms, authenticationToken);}}123456789这段代码的意思是:当只有一个Realm 时,就使用这个Realm,当配置了多个Realm时,会使用所有配置的Realm。
现在,为了实现需求,我会创建一个org.apache.shiro.authc.pam.ModularRealmAuthenticator的子类,并重写doAuthenticate()方法,让特定的Realm完成特定的功能。
如何区分呢?我会同时创建一个ernamePasswordToken的子类,在其中添加一个字段loginType,用来标识登录的类型,即是普通用户登录,还是管理员登录。
具体步骤如下:第一步:创建枚举类LoginType用以记录登录的类型://登录类型//普通用户登录,管理员登录public enum LoginType {USER("User"), ADMIN("Admin"); private String type; private LoginType(String type) {this.type = type;} @Overridepublic String toString() {return this.type.toString();}}12345678910111213141516第二步:新建ernamePasswordToken的子类CustomizedToken:importernamePasswordToken;public class CustomizedToken extends UsernamePasswordToken { //登录类型,判断是普通用户登录,教师登录还是管理员登录private String loginType; public CustomizedToken(final String username, final String password,String loginType) {super(username,password);this.loginType = loginType;} public String getLoginType() {return loginType;} public void setLoginType(String loginType) {this.loginType = loginType;}}1234567891011121314151617181920第三步:新建org.apache.shiro.authc.pam.ModularRealmAuthenticator的子类CustomizedModularRealmAuthenticator:importjava.util.ArrayList;import java.util.Collection;importorg.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;importorg.apache.shiro.authc.pam.ModularRealmAuthenticator; import org.apache.shiro.realm.Realm;/*** @author Alan_Xiang* 自定义Authenticator* 注意,当需要分别定义处理普通用户和管理员验证的Realm时,对应Realm的全类名应该包含字符串“User”,或者“Admin”。
* 并且,他们不能相互包含,例如,处理普通用户验证的Realm的全类名中不应该包含字符串"Admin"。
*/public class CustomizedModularRealmAuthenticator extends ModularRealmAuthenticator { @Overrideprotected AuthenticationInfodoAuthenticate(AuthenticationToken authenticationToken)throws AuthenticationException {// 判断getRealms()是否返回为空assertRealmsConfigured();// 强制转换回自定义的CustomizedTokenCustomizedToken customizedToken = (CustomizedToken) authenticationToken;// 登录类型String loginType = customizedToken.getLoginType();// 所有RealmCollection<Realm> realms = getRealms();// 登录类型对应的所有RealmCollection<Realm> typeRealms = new ArrayList<>();for (Realm realm : realms) {if (realm.getName().contains(loginType))typeRealms.add(realm);} // 判断是单Realm还是多Realmif (typeRealms.size() == 1)returndoSingleRealmAuthentication(typeRealms.iterator().next(), customizedToken);elsereturn doMultiRealmAuthentication(typeRealms, customizedToken);}}1234567891011121314151617181920212223242526272 8293031323334353637383940414243第四步:创建分别处理普通用户登录和管理员登录的Realm:UserRealm:import javax.annotation.Resource;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.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.util.ByteSource;importer;import com.ang.elearning.service.IUserService;public class UserRealm extends AuthorizingRealm { @Resource IUserService userService; @Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null;} @Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {User user = null;// 1. 把AuthenticationToken转换为CustomizedTokenCustomizedToken customizedToken = (CustomizedToken) token;// 2. 从CustomizedToken中获取emailString email = customizedToken.getUsername();// 3. 若用户不存在,抛出UnknownAccountException异常user = userService.getUserByEmail(email);if (user == null)throw new UnknownAccountException("用户不存在!");// 4.// 根据用户的情况,来构建AuthenticationInfo对象并返回,通常使用的实现类为SimpleAuthenticationInfo // 以下信息从数据库中获取// (1)principal:认证的实体信息,可以是email,也可以是数据表对应的用户的实体类对象Object principal = email;// (2)credentials:密码Object credentials = user.getPassword();// (3)realmName:当前realm对象的name,调用父类的getName()方法即可String realmName = getName();// (4)盐值:取用户信息中唯一的字段来生成盐值,避免由于两个用户原始密码相同,加密后的密码也相同ByteSource credentialsSalt =ByteSource.Util.bytes(email);SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt,realmName);return info;}}1234567891011121314151617181920212223242526272 829303132333435363738394041424344454647484950515253 5455AdminRealm:importjavax.annotation.Resource;importorg.apache.shiro.authc.AuthenticationException;importorg.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.util.ByteSource;importcom.ang.elearning.po.Admin;import com.ang.elearning.service.IAdminService;public class AdminRealm extends AuthorizingRealm { @Resource private IAdminService adminService; @Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // TODO Auto-generated method stubreturn null;} @Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {Admin admin = null;// 1. 把AuthenticationToken转换为CustomizedTokenCustomizedToken customizedToken = (CustomizedToken) token;// 2. 从CustomizedToken中获取usernameString username = customizedToken.getUsername();// 3. 若用户不存在,抛出UnknownAccountException异常admin =adminService.getAdminByUsername(username);if (admin == null)throw new UnknownAccountException("用户不存在!");// 4.// 根据用户的情况,来构建AuthenticationInfo对象并返回,通常使用的实现类为SimpleAuthenticationInfo // 以下信息从数据库中获取// (1)principal:认证的实体信息,可以是username,也可以是数据表对应的用户的实体类对象Object principal = username;// (2)credentials:密码Object credentials = admin.getPassword();// (3)realmName:当前realm对象的name,调用父类的getName()方法即可String realmName = getName();// (4)盐值:取用户信息中唯一的字段来生成盐值,避免由于两个用户原始密码相同,加密后的密码也相同ByteSource credentialsSalt =ByteSource.Util.bytes(username);SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt,realmName);return info;}}1234567891011121314151617181920212223242526272 829303132333435363738394041424344454647484950515253 545556第五步:在spring配置文件中指定使用自定义的认证器:(其他配置略) <!-- 配置SecurityManager--><bean id="securityManager"class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" ><property name="cacheManager"ref="cacheManager" /><property name="authenticator"ref="authenticator"></property><!-- 可以配置多个Realm,其实会把realms属性赋值给ModularRealmAuthenticator的realms属性--><property name="realms"><list><ref bean="userRealm" /><ref bean="adminRealm"/></list></property></bean><!-- 配置使用自定义认证器,可以实现多Realm认证,并且可以指定特定Realm处理特定类型的验证--><bean id="authenticator"class="com.ang.elearning.shiro.CustomizedModularRealmAuth enticator"><!-- 配置认证策略,只要有一个Realm认证成功即可,并且返回所有认证成功信息--><property name="authenticationStrategy"><beanclass="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrate gy"></bean></property></bean> <!-- 配置Realm --><bean id="userRealm"class="erRealm"><!-- 配置密码匹配器--><property name="credentialsMatcher"><beanclass="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><!-- 加密算法为MD5 --><property name="hashAlgorithmName" value="MD5"></property><!-- 加密次数--><property name="hashIterations" value="1024"></property></bean></property></bean> <bean id="adminRealm"class="com.ang.elearning.shiro.AdminRealm"><!-- 配置密码匹配器--><property name="credentialsMatcher"><beanclass="org.apache.shiro.authc.credential.HashedCredentialsMat cher"><!-- 加密算法为MD5 --><property name="hashAlgorithmName" value="MD5"></property><!-- 加密次数--><property name="hashIterations" value="1024"></property></bean></property></bean>1234567891011121314151617181920212223242 52627282930313233343536373839404142434445第六步:配置控制器:UserController:@Controller @RequestMapping("/user")public class UserController { private static final String USER_LOGIN_TYPE = ER.toString();@Resourceprivate IUserService userService;@RequestMapping(value = "login", method = RequestMethod.POST)public String login(@RequestParam("email") String email, @RequestParam("password") String password) {Subject currentUser = SecurityUtils.getSubject();if (!currentUser.isAuthenticated()) {CustomizedToken customizedToken = new CustomizedToken(email, password, USER_LOGIN_TYPE);customizedToken.setRememberMe(false);try {currentUser.login(customizedToken);return "user/index";} catch (IncorrectCredentialsException ice) {System.out.println("邮箱/密码不匹配!");} catch (LockedAccountException lae) {System.out.println("账户已被冻结!");} catch (AuthenticationException ae) {System.out.println(ae.getMessage());}}return "redirect:/login.jsp";}}1234567891011121314151617181920212223242526272829 AdminController:@Controller@RequestMapping("/admin")public class AdminController { private static final String ADMIN_LOGIN_TYPE = LoginType.ADMIN.toString();@RequestMapping(value="/login",method=RequestMethod.PO ST)public String login(@RequestParam("username") String username,@RequestParam("password") String password){ Subject currentUser = SecurityUtils.getSubject();if(!currentUser.isAuthenticated()){CustomizedToken customizedToken = new CustomizedToken(username, password,ADMIN_LOGIN_TYPE);customizedToken.setRememberMe(false);try {currentUser.login(customizedToken);return "admin/index";} catch (IncorrectCredentialsException ice) {System.out.println("用户名/密码不匹配!");} catch (LockedAccountException lae) {System.out.println("账户已被冻结!");} catch (AuthenticationException ae) {System.out.println(ae.getMessage());}}return "redirect:/login.jsp";}}123456789101112131415161718192021222324252627测试页面:login.jsp<body><formaction="${pageContext.request.contextPath }/user/login"method="POST">邮箱:<input type="text" name="email"><br><br>密码:<input type="password"name="password"><br><br><input type="submit" value="用户登录"></form><br><br><formaction="${pageContext.request.contextPath }/admin/login"method="POST">用户名:<input type="text" name="username"><br><br>密码:<input type="password"name="password"><br><br><input type="submit" value="管理员登录"></form></body>1234567891011121314151617181920这就实现了UserRealm用以处理普通用户的登录验证,AdminRealm用以处理管理员的登录验证。