之前写的博客里都是使用.ini文件来获取信息的,包括用户信息,角色信息,权限信息等。进入系统时,都是从.ini文件这读取进入的。实际中除非这个系统特别特别简单,否则一般都不是这样干的,这些信息都是需要在数据库中进行维护的,所以就需要用到自定义realm了。
1. 数据库建表
首先在数据库中新建三个表:t_user,t_role和t_permission,分别存储用户信息,角色信息和权限信息,建表语句如下:
CREATE TABLE `t_role` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `rolename` varchar(20) DEFAULT NULL COMMENT '角色名称', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户主键', `username` varchar(20) NOT NULL COMMENT '用户名', `password` varchar(20) NOT NULL COMMENT '密码', `role_id` int(11) DEFAULT NULL COMMENT '外键关联role表', PRIMARY KEY (`id`), KEY `role_id` (`role_id`), CONSTRAINT `t_user_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 CREATE TABLE `t_permission` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `permissionname` varchar(50) NOT NULL COMMENT '权限名', `role_id` int(11) DEFAULT NULL COMMENT '外键关联role', PRIMARY KEY (`id`), KEY `role_id` (`role_id`), CONSTRAINT `t_permission_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
每个表中我添加了一些测试数据,如下:
2. 自定义realm
自定义realm中需要操作数据库,所有首先得先写一个dao,使用的是原始的jdbc,主要是下面的自定义realm。
public class UserDao { //根据用户名查找用户 public User getByUsername(Connection conn, String username) throws Exception { User resultUser = null; String sql = "select * from t_user where username=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, username); ResultSet rs = ps.executeQuery(); if(rs.next()) { resultUser = new User(); resultUser.setId(rs.getInt("id")); resultUser.setUsername(rs.getString("username")); resultUser.setPassword(rs.getString("password")); } return resultUser; } //根据用户名查找改用户所拥有的角色 public Set<String> getRoles(Connection conn, String username) throws Exception { Set<String> roles = new HashSet<String>(); String sql = "select * from t_user u, t_role r where u.role_id=r.id and u.username=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, username); ResultSet rs = ps.executeQuery(); while(rs.next()) { roles.add(rs.getString("rolename")); } return roles; } //根据用户名查找该用户角色所拥有的权限 public Set<String> getPerms(Connection conn, String username) throws Exception { Set<String> perms = new HashSet<String>(); String sql = "select * from t_user u, t_role r, t_permission p where u.role_id=r.id and p.role_id=r.id and u.username=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, username); ResultSet rs = ps.executeQuery(); while(rs.next()) { perms.add(rs.getString("permissionname")); } return perms; } }
有了dao了,接下来就可以写自定义的realm了,自定义realm需要继承AuthorizingRealm类,因为该类封装了很多方法,它也是一步步继承自Realm类的,继承了AuthorizingRealm类后,需要重写两个方法:
doGetAuthenticationInfo()方法:用来验证当前登录的用户,获取认证信息
doGetAuthorizationInfo()方法:用来为当前登陆成功的用户授予权限和角色(已经登陆成功了)
下面来看一下具体的实现:
public class MyRealm extends AuthorizingRealm { private UserDao userDao = new UserDao(); // 为当前登陆成功的用户授予权限和角色,已经登陆成功了 @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); //获取用户名 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); Connection conn = null; try { conn = DbUtil.getConnection(); authorizationInfo.setRoles(userDao.getRoles(conn, username)); //设置角色 authorizationInfo.setStringPermissions(userDao.getPerms(conn, username)); //设置权限 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { DbUtil.closeConnection(conn); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } return authorizationInfo; } // 验证当前登录的用户,获取认证信息 @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); // 获取用户名 Connection conn = null; try { conn = DbUtil.getConnection(); User user = userDao.getByUsername(conn, username); // 仅仅是根据用户名查出的用户信息,不涉及到密码 if (user != null) { AuthenticationInfo authcInfo = new SimpleAuthenticationInfo( user.getUsername(), user.getPassword(), "myrealm"); return authcInfo; } else { return null; } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { DbUtil.closeConnection(conn); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } return null; } }
从上面两个方法中可以看出:验证身份的时候是根据用户输入的用户名先从数据库中查出该用户名对应的用户,这时候并没有涉及到密码,也就是说到这一步的时候,即使用户输入的密码不对,也是可以查出来该用户的,然后将该用户的正确信息封装到authcInfo 中返回给Shiro,接下来就是Shiro的事了,它会根据这里面的真实信息与用户前台输入的用户名和密码进行校验, 这个时候也要校验密码了,如果校验通过就让用户登录,否则跳转到指定页面。同理,权限验证的时候也是先根据用户名获取与该用户名有关的角色和权限,然后封装到authorizationInfo中返回给Shiro。
3. 修改ini文件
在该配置文件中,[users]和[roles]的信息就可以删掉了,因为这些信息都是从数据库中维护的,另外还要在文件中指定我们自定义的realm的完全限定名,并且指定securityManager的realm使用我们自定义的realm,如下:
[main] authc.loginUrl=/login roles.unauthorizedUrl=/unauthorized.jsp perms.unauthorizedUrl=/unauthorized.jsp #定义自己的realm myRealm=demo.shiro.realm.MyRealm securityManager.realms=$myRealm #定义请求的地址需要做什么验证 [urls] /login=anon /admin=authc /student=roles[teacher] /teacher=perms["user:create"]
这样我们自定义的realm就搞定了,根据配置文件,当我们请求…/admin的时候会进行身份认证,所以会进入LoginServlet中,当调用currentUser.login(token);
的时候,就会进入我们自定义的realm中的doGetAuthenticationInfo方法进行身份初始化,然后交给Shiro去验证。当我们请求…./student的时候,也会先进行身份验证,就是上面的过程,然后验证通过,当我们再次请求…/student的时候,就会进入我们自定义的realm中的doGetAuthorizationInfo方法进行权限的初始化,然后交给Shiro去验证。
相关推荐
shiro自定义realm案例,参考文档:http://blog.csdn.net/qq_19558705/article/details/50775509
其中QueryDatabaseAuthenticationHandler这个类是自定义构建的,在cas/WEB-INF/lib/cas-jdbc-1.0.0.jar里面,有兴趣的同学可以发编译看下,关于几个属性的说明 1. dataSource: 数据源,配置MySQL的连接信息 2. ...
这个程序是eclipse编写的,学习shiro框架,入门的,用于测试自定义的Realm的小例子,仅仅用于学习,不得用于商业用途
shiro权限框架自定义Realm示例
这里是shiro在web应用中自定义Realm的代码,以便做一个参考
今天小编就为大家分享一篇关于Spring配置shiro时自定义Realm中属性无法使用注解注入的解决办法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
shiro使用自定义realm,利用mybatis做查询,实现身份认证和授权
从实例入手学习Shiro自定义Realm实现查询数据进行验证示例代码.zip
自定义realm Shiro加密 Shiro散列配置 HashedCredentialsMatcher //加密 HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); matcher.setHashAlgorithmName("md5");//设置加密算法 matcher....
shiro授权,自定义realm,shiro与项目整合,shiro缓存,验证码,记住我
shiro标签,第六讲 自定义Realm(加入整合spring和MyBatis), 第七讲 加密(加密算法、加密过程、加密实现代码),第八讲 记住我,第九讲 缓存管理(代码实现),第十讲 会话管理(session的监听和检测、环境配置)...
shiro demo 源码里面2中realm 一种是jdbcRealm 一种是自定义realm 有sql脚本。请看db文件夹下的readme.txt 有关这个项目的详细介绍,使用了简单的标签库权限控制当做例子
ssm整合shiro通过自定义Realm实现认证登录、权限处理、自定义role拦截、MD5加密
-- 項目自定义的Realm --> <bean id="myShiroRealm" class="com.z.shiro.realm.ShiroRealm"> <property name="cacheManager" ref="cacheManager" /> </bean> <!-- Shiro Filter --> <bean id="...
本系统演示: ssm 整合shiro 自定义shiro Realm 登录 授权拦截器 log4j 控制台打印sql
05.自定义realm登录登出.avi 06.加密realm登录登出.avi 07.RBAC权限模型理解.avi 08.ini方式检查用户拥有角色.avi 09.ini方式检查用户拥有权限.avi 10.自定义realm检查用户拥有权限.avi 11.shiro授权流程分析.avi 12...
Apache Shiro 是目前使用率较高的一个 Java 安全框架。本视频基于 Shiro 的新版本 1.3.2 录制。内容涵盖 Shiro 认证、加密、授权、安全标签、安全...5.自定义 Realm 第五章 加密 1.shiro 加密解密 2.shiro 加密应用
自定义realm(数据源,从数据库获得真实用户信息(密码权限),并封装成AuthenticationInfo认证信息 和 AuthorizationInfo授 权信息 自定义拦截器(也用Bean 配置是为了可以在拦截器里可以用@Autowird 获得...
学习如何自定义 Realm 来实现不同的身份认证方式。 授权: 理解授权的概念和权限管理。 学习如何定义权限字符串和角色。 了解如何通过 Shiro 进行权限检查和访问控制。 会话管理: 理解会话管理的目的和流程。 ...
│ 30-使用自定义realm-1.mp4 │ 31-详细的测试-关于密码认证-1.mp4 │ 32-认证流程-1.mp4 │ 33-测试加密算法-1.mp4 │ 34-密码加密自定义realm验证-1.mp4 │ 35-权限管理入门-1.mp4 │ 36-角色的判断-1.mp4 │ 37-...