第七章:自定义Realm,从数据库中获取数据进行认证【重点】
工程结构

一、建立数据库,数据库名shiro
用户表users、角色表roles、权限表permissions
一个用户有多个角色,一个角色有多种权限
CREATE TABLE `users` ( `id` int(11) NOT NULL, `userName` varchar(20) DEFAULT NULL, `password` varchar(20) DEFAULT NULL, `roleId` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `FK_ID_ROLES_USERS` (`roleId`), CONSTRAINT `FK_ID_ROLES_USERS` FOREIGN KEY (`roleId`) REFERENCES `roles` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `roles` ( `id` int(11) NOT NULL, `roleName` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `permissions` ( `id` int(11) NOT NULL, `permissionName` varchar(50) DEFAULT NULL, `roleId` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `FK_ID_ROLES_PERMISSIONS` (`roleId`), CONSTRAINT `FK_ID_ROLES_PERMISSIONS` FOREIGN KEY (`roleId`) REFERENCES `roles` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
插入测试数据:



二、在pom.xml中添加mysql数据库驱动包
<!-- mysql数据库驱动包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency>
三、添加IO包
<!-- IO包 --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency>
四、在src/main/resources下创建db.properties
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/shiro?useUnicod=true&characterEncoding=utf-8 userName=root password=123456
五、创建包com.java1234.common,包下创建连接数据库的工具类DBHelper.java
package com.java1234.common;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
/**
* 连接数据库
*/
public class DBHelper {
// 驱动参数
private static Connection conn = null;
private static PreparedStatement ps = null;
// 连接
public static Connection getConnection(String driverClassName,
String url, String userName, String password) throws Exception {
try {
Class.forName(driverClassName);
conn = DriverManager.getConnection(url, userName, password);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
public static PreparedStatement getPreparedStatement(Connection conn, String sql) throws Exception {
try {
ps = conn.prepareStatement(sql);
} catch (Exception e) {
e.printStackTrace();
}
return ps;
}
// 释放资源
public static void closePreparedStatement(PreparedStatement ps) throws Exception {
try {
if (ps != null) {
ps.close();
ps = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void closeConnection(Connection conn) throws Exception {
try {
if (conn != null) {
conn.close();
conn = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void closeResultSet(ResultSet rs) throws Exception {
try {
if (rs != null) {
rs.close();
rs = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getValueByKey(String filename, String key) {
Properties ps = new Properties();
InputStream is = null;
try {
is = new BufferedInputStream(new FileInputStream(filename));
ps.load(is);
String value = ps.getProperty(key);
return value;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (is != null) {
try {
is.close();
is = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
六、创建测试类,测试数据库是否连接成功
package com.java1234.test;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
import com.java1234.common.DBHelper;
public class DbTest {
public static void main(String[] args) {
String filename = "src\\main\\resources\\db.properties";
String driverClassName = getValueByKey(filename, "driverClassName");
String url = getValueByKey(filename, "url");
String userName = getValueByKey(filename, "userName");
String password = getValueByKey(filename, "password");
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBHelper.getConnection(driverClassName, url, userName, password);
String sql = "SELECT * FROM users";
ps = DBHelper.getPreparedStatement(conn, sql);
rs = ps.executeQuery();
while (rs.next()) {
Integer db_id = rs.getInt(1);
String db_userName = rs.getString(2);
String db_password = rs.getString(3);
System.out.println(db_id + " | " + db_userName + " | " + db_password);
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
DBHelper.closeResultSet(rs);
DBHelper.closePreparedStatement(ps);
DBHelper.closeConnection(conn);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static String getValueByKey(String filename, String key) {
Properties ps = new Properties();
InputStream is = null;
try {
is = new BufferedInputStream(new FileInputStream(filename));
ps.load(is);
String value = ps.getProperty(key);
return value;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (is != null) {
try {
is.close();
is = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
结果: 数据库连接成功!
1 | java1234 | 123456
2 | jack | 123
3 | marry | 234
4 | json | 345
-------------------------------------
七、创建POJO类和DAO类
Users.java
private Integer id; private String userName; private String password; private Roles role;
Roles.java
private Integer id; private String roleName;
Permissions.java
private Integer id; private String permissionName; private Roles role;
UserDao.java
package com.java1234.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashSet;
import java.util.Set;
import com.java1234.common.DBHelper;
import com.java1234.entities.Users;
public class UserDao {
// 数据库参数
private static Connection conn = null;
private static PreparedStatement ps = null;
private static ResultSet rs = null;
// 连接参数
private static String filename = null;
private static String jdbc_driverClassName = null;
private static String jdbc_url = null;
private static String jdbc_userName = null;
private static String jdbc_password = null;
static {
// filename = "src\\main\\resources\\db.properties";
filename = "G:\\Test2\\ShiroWeb\\src\\main\\resources\\db.properties";
jdbc_driverClassName = DBHelper.getValueByKey(filename, "driverClassName");
jdbc_url = DBHelper.getValueByKey(filename, "url");
jdbc_userName = DBHelper.getValueByKey(filename, "userName");
jdbc_password = DBHelper.getValueByKey(filename, "password");
try {
conn = DBHelper.getConnection(jdbc_driverClassName, jdbc_url, jdbc_userName, jdbc_password);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据用户名获取用户信息
* @param userName 用户输入的用户名
* @return
* @throws Exception
*/
public Users getByUserName(String userName) throws Exception {
Users user = null;
String sql = "SELECT * FROM users WHERE userName = ? LIMIT 1";
try {
ps = DBHelper.getPreparedStatement(conn, sql);
ps.setString(1, userName);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
user = new Users();
user.setId(rs.getInt(1));
user.setUserName(rs.getString(2));
user.setPassword(rs.getString(3));
}
} catch (Exception e) {
e.printStackTrace();
}
return user;
}
/**
* 根据用户名获取用户的角色
* @param userName
* @return 角色列表
* @throws Exception
*/
public Set<String> getRoles(String userName) throws Exception {
Set<String> roles = new HashSet<String>();
String sql = "SELECT r.roleName FROM users u LEFT JOIN roles r ON u.roleId = r.id WHERE u.userName = ?";
try {
ps = DBHelper.getPreparedStatement(conn, sql);
ps.setString(1, userName);
rs = ps.executeQuery();
while (rs.next()) {
roles.add(rs.getString("roleName"));
}
} catch (Exception e) {
e.printStackTrace();
}
return roles;
}
public Set<String> getPermissions(String userName) throws Exception {
Set<String> permissions = new HashSet<String>();
String sql = "SELECT p.permissionName FROM users u LEFT "
+ "JOIN roles r ON u.roleId = r.id LEFT "
+ "JOIN permissions p ON r.id = p.roleId WHERE u.userName = ?";
try {
ps = DBHelper.getPreparedStatement(conn, sql);
ps.setString(1, userName);
rs = ps.executeQuery();
while (rs.next()) {
permissions.add(rs.getString("permissionName"));
}
} catch (Exception e) {
e.printStackTrace();
}
return permissions;
}
}
八、创建自定义Realm
创建com.java1234.realm.MyRealm.java
package com.java1234.realm;
import java.util.Iterator;
import java.util.Set;
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.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import com.java1234.dao.UserDao;
import com.java1234.entities.Users;
public class MyRealm extends AuthorizingRealm {
private UserDao userDao = new UserDao();
/**
* 验证当前登录的用户
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
String userName = (String) token.getPrincipal();
try {
Users user = userDao.getByUserName(userName); // 根据用户名获取用户
if (user != null) {
AuthenticationInfo info = new SimpleAuthenticationInfo(
user.getUserName(), user.getPassword(), "XXX");
return info;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 为当前用户授予角色和权限, 在用户成功登录后才会执行这个方法
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
/**
* 获取用户名,这里的用户名是数据库中的用户名,即从上面的方法doGetAuthenticationInfo()
* 中获取的user中的user.getUserName()中获取到的合法的用户名, 通过这个用户名可以获取到用户拥有的角色和权限
*/
String userName = (String) principals.getPrimaryPrincipal();
// 绑定用户所拥有的角色和权限
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
try {
// 根据用户名获取用户角色,并将其绑定到info中
Set<String> roles = userDao.getRoles(userName);
Iterator<String> iterator = roles.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
info.setRoles(roles);
// 根据用户名获取用户权限,并剑气绑定到info中
Set<String> permissions = userDao.getPermissions(userName);
Iterator<String> iterator2 = permissions.iterator();
while (iterator2.hasNext()) {
System.out.println(iterator2.next());
}
info.setStringPermissions(permissions);
} catch (Exception e) {
e.printStackTrace();
}
return info;
}
}
九、将自定义Realm配置到shiro.ini中(包.类的形式)
[main]
authc.loginUrl=/login
roles.unauthorizedUrl=/unauthorized.jsp
perms.unauthorizedUrl=/unauthorized.jsp
myRealm=com.java1234.realm.MyRealm
securityManager.realms=$myRealm
[urls]
/login=anon
/admin?=authc
/student=roles[teacher]
/teacher=perms["user:create"]
十、测试
(1)用户java123456登录

后台打印:
admin
user:*
admin
user:*
(2) 用户jack登录

后台打印:
teacher
student:*
teacher
student:*

浙公网安备 33010602011771号