如果要看多Realm进行授权:

请参看   https://blog.csdn.net/u013294097/article/details/90066869

假设现在有这样一种需求:存在两张表user和admin,分别记录普通用户和管理员的信息。并且现在要实现普通用户和管理员的分开登录,即需要两个Realm——UserRealm和AdminRealm,分别处理普通用户和管理员的验证功能。 
  但是正常情况下,当定义了两个Realm,无论是普通用户登录,还是管理员登录,都会由这两个Realm共同处理。这是因为,当配置了多个Realm时,我们通常使用的认证器是shiro自带的org.apache.shiro.authc.pam.ModularRealmAuthenticator,其中决定使用的Realm的是doAuthenticate()方法,源代码如下:

protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {assertRealmsConfigured();Collection<Realm> realms = getRealms();if (realms.size() == 1) {return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);} else {return doMultiRealmAuthentication(realms, authenticationToken);}}

这段代码的意思是:当只有一个Realm时,就使用这个Realm,当配置了多个Realm时,会使用所有配置的Realm。 
  现在,为了实现需求,我会创建一个org.apache.shiro.authc.pam.ModularRealmAuthenticator的子类,并重写doAuthenticate()方法,让特定的Realm完成特定的功能。如何区分呢?我会同时创建一个org.apache.shiro.authc.UsernamePasswordToken的子类,在其中添加一个字段loginType,用来标识登录的类型,即是普通用户登录,还是管理员登录。具体步骤如下:

1:创建枚举类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();}
}

2.新建org.apache.shiro.authc.UsernamePasswordToken的子类CustomizedToken:

import org.apache.shiro.authc.UsernamePasswordToken;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;}
}

3.新建org.apache.shiro.authc.pam.ModularRealmAuthenticator的子类CustomizedModularRealmAuthenticator:

import java.util.ArrayList;
import java.util.Collection;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.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 AuthenticationInfo doAuthenticate(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)return doSingleRealmAuthentication(typeRealms.iterator().next(), customizedToken);elsereturn doMultiRealmAuthentication(typeRealms, customizedToken);}}

4.创建分别处理普通用户登录和管理员登录的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;import com.ang.elearning.po.User;
import com.ang.elearning.service.IUserService;public class UserRealm extends AuthorizingRealm {@ResourceIUserService 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;}}AdminRealm: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;import com.ang.elearning.po.Admin;
import com.ang.elearning.service.IAdminService;public class AdminRealm extends AuthorizingRealm {@Resourceprivate 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;}}

5.在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.CustomizedModularRealmAuthenticator"><!-- 配置认证策略,只要有一个Realm认证成功即可,并且返回所有认证成功信息 --><property name="authenticationStrategy"><bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean></property></bean><!-- 配置Realm --><bean id="userRealm" class="com.ang.elearning.shiro.UserRealm"><!-- 配置密码匹配器 --><property name="credentialsMatcher"><bean class="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"><bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><!-- 加密算法为MD5 --><property name="hashAlgorithmName" value="MD5"></property><!-- 加密次数 --><property name="hashIterations" value="1024"></property></bean></property></bean>

6.配置控制器:

UserController:@Controller
@RequestMapping("/user")
public class UserController {private static final String USER_LOGIN_TYPE = LoginType.USER.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";}
}AdminController:@Controller
@RequestMapping("/admin")
public class AdminController {private static final String ADMIN_LOGIN_TYPE = LoginType.ADMIN.toString();@RequestMapping(value="/login",method=RequestMethod.POST)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";}
}

7.测试页面:login.jsp

<body><form action="${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><form action="${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>

这就实现了UserRealm用以处理普通用户的登录验证,AdminRealm用以处理管理员的登录验证。 
  如果还需要添加其他类型,例如,需要添加一个教师登录模块,只需要再新建一个TeacherRealm,并且在枚举类loginType中添加教师的信息,再完成其他类似的配置即可。

Shiro的多Realm验证的实现--shiro实现不同身份使用不同Realm进行验证相关推荐

  1. shiro多realm验证之——shiro实现不同身份使用不同Realm进行验证(转)

    转自: http://blog.csdn.net/xiangwanpeng/article/details/54802509 (使用特定的realm实现特定的验证) 假设现在有这样一种需求:存在两张表 ...

  2. shiro学习一 (开涛的跟我学系列 ) 身份验证

    原文来自于http://jinnianshilongnian.iteye.com/blog/2018398 1.简介 Apache Shiro是Java的一个安全框架.可以帮助我们完成:认证.授权.加 ...

  3. shiro学习总结(一)----初识shiro

    本系列内容大多总结自官网和张开涛的<跟我学Shiro> 一.shiro简介 1.1.shiro有什么用? shiro是一个功能强大使用简单的java安全框架,主要提供了五大功能: 1.认证 ...

  4. Shiro学习总结(1)——Apache Shiro简介

    1.1  简介 Apache Shiro是Java的一个安全框架.目前,使用Apache Shiro的人越来越多,因为它相当简单,对比springSecurity,可能没有Spring Securit ...

  5. Shiro学习总结(3)——Apache Shiro身份认证

    身份验证,即在应用中谁能证明他就是他本人.一般提供如他们的身份ID一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明. 在shiro中,用户需要提供principals (身份)和cre ...

  6. shiro登陆成功后被拦截_Springboot+Shiro+redis整合

    1.Shiro是Apache下的一个开源项目,我们称之为Apache Shiro.它是一个很易用与Java项目的的安全框架,提供了认证.授权.加密.会话管理,与spring Security 一样都是 ...

  7. R语言构建xgboost文本分类模型(bag of words):xgb.cv函数交叉验证确定xgboost模型的最优子树个数、交叉验证获取最优子树之后构建最优xgboost模型并评估模型文本分类效能

    R语言构建xgboost文本分类模型(bag of words):xgb.cv函数交叉验证确定xgboost模型的最优子树个数.交叉验证获取最优子树之后构建最优xgboost模型并评估模型文本分类效能 ...

  8. R语言构建xgboost模型:xgb.cv函数交叉验证确定模型的最优子树个数(可视化交叉验证对数损失函数与xgboost模型子树个数的关系)、交叉验证获取最优子树之后构建最优xgboost模型

    R语言构建xgboost模型:xgb.cv函数交叉验证确定模型的最优子树个数(可视化交叉验证对数损失函数与xgboost模型子树个数的关系).交叉验证获取最优子树之后构建最优xgboost模型 目录

  9. 交叉验证(cross validation)是什么?K折交叉验证(k-fold crossValidation)是什么?

    交叉验证(cross validation)是什么?K折交叉验证(k-fold crossValidation)是什么? 交叉验证(cross validation)是什么?  交叉验证是一种模型的验 ...

最新文章

  1. 解剖JavaScript中的null和undefined
  2. R语言如何将字符串转变为命令执行
  3. mantelhean.test r语言_R语言基础-检验与分析函数
  4. 分享Kali Linux 2016.2第42周镜像文件
  5. 寻找数组中只出现一次的数
  6. 继英伟达最小边缘超算,英特尔再推10倍VPU,终端AI芯片竞争加剧
  7. 高精度除以低精度板子
  8. python 什么是上下文管理器(ContextManager)?
  9. 启明云端分享 | Sigmastar SSD201\SSD202D核心板在智能料理机方案的应用(4.3寸彩屏应用)
  10. java 输出全年日期_Java 输出某一年所有的日期
  11. 海信电视root工具_中国企业的远见:用一项自主技术,打败日韩电视,成为行业引领者...
  12. php中怎么函数加字符串,如何使用PHP中的字符串函数
  13. using和名空间namespace
  14. js 自定义getClass函数实现获取dom的class 兼容火狐ie
  15. 苹果背后的拼多多双11“农产品狂想曲”
  16. linux 查看链接文件,Linux下的链接文件详解
  17. html中图片左右切换,超简单的图片左右切换滑动
  18. Kafka producer的事务和幂等性
  19. Navicat Premium 15的使用
  20. Vue 开发的组件库

热门文章

  1. Oracle数据库链路
  2. 字节跳动九周年张一鸣演讲:反对all-in、抽象概念和方法论
  3. App后台开发运维和架构实践学习总结(8)——后台产品设计的4个原则
  4. Beetl学习总结(3)——高级功能
  5. Java基础学习总结(44)——10个Java 8 Lambda表达式经典示例
  6. 组装r730服务器,戴尔poweredge r730服务器配置及系统安装详解教程
  7. mysql 删除版本信息_mysql5.5版本删除大表
  8. 解决设备行业尾款回收问题-深思精锐5时钟锁
  9. Hbase新API以及Hbase增删改差
  10. 云效支持自定义构建镜像 征集10家企业免费使用