在一头扎进Shiro-集成Web之前的博客,我们都是用shiro.ini保存用户、角色、权限信息,本篇文章我们将这些信息保存到数据库,通过自定义Realm完成身份验证和权限验证。
去掉用户、角色、权限信息,添加Realm信息的shiro.ini文件信息如下:
[main]
authc.loginUrl=/login
roles.unauthorizedUrl=/unauthorized.jsp
perms.unauthorizedUrl=/unauthorized.jsp
myRealm=com.tgb.realm.MyRealm
securityManager.realms=$myRealm
[urls]
/login=anon
/admin=authc
/student=roles[teacher]
/teacher=perms["user:create"]
首先和大家展示下LoginServlet和MyRealm的代码实现,然后结合代码讲解下面的三种验证过程。
LoginServlet:
package com.tgb.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("login doget");
req.getRequestDispatcher("login.jsp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("login dopost");
String userName = req.getParameter("userName");
String password = req.getParameter("password");
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userName,
password);
try {
subject.login(token);
resp.sendRedirect("success.jsp");
} catch (Exception e) {
e.printStackTrace();
req.setAttribute("errorInfo", "用户名或密码错误");
req.getRequestDispatcher("login.jsp").forward(req, resp);
}
}
}
MyRealm:
package com.tgb.realm;
import java.sql.Connection;
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.tgb.dao.UserDao;
import com.tgb.entity.User;
import com.tgb.util.DbUtil;
public class MyRealm extends AuthorizingRealm {
private UserDao userDao = new UserDao();
private DbUtil dbUtil = new DbUtil();
/**
* 为当前登录的用户授予权限
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
String userName = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
Connection con = null;
try {
con = dbUtil.getCon();
authorizationInfo.setRoles(userDao.getRoles(con, userName));
authorizationInfo.setStringPermissions(userDao.getPermissions(con,
userName));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
dbUtil.closeCon(con);
} catch (Exception e) {
}
}
return authorizationInfo;
}
/**
* 验证当前登录的用户
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
String userName = (String) token.getPrincipal();
Connection con = null;
try {
con = dbUtil.getCon();
User user = userDao.getByUserName(con, userName);
if (user != null) {
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(
user.getUserName(), user.getPassword(), "xx");
return authcInfo;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
dbUtil.closeCon(con);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
success.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="UTF-8"%>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
welcome!
<shiro:hasRole name="admin">
welcome admin user!
</shiro:hasRole>
<shiro:hasPermission name="student:create">
welcome student:create user!<shiro:principal/>
</shiro:hasPermission>
</body>
</html>
用户名不存在验证
当我们在浏览器输入“http://localhost:8080/ShiroWeb/login”,使用不存在的用户名进行登录后,程序会进入到LoginServlet的subject.login(token)方法,F8执行过,会跳转到MyRealm的doGetAuthenticationInfo(AuthenticationToken token)方法进行身份验证,如果用户名不存在,则通过userDao.getByUserName返回的User实体为空,直接返回到login登录页。
用户名存在、密码不正确验证
如果我们在登录页输入的用户名正确、密码不正确,则在MyRealm的doGetAuthenticationInfo(AuthenticationToken token)方法中使用AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUserName(), user.getPassword(), "xx")方法,将用户输入保存在token中的用户名、密码和从数据库中查询出的用户名、密码进行比对,比对后发现密码不正确,直接返回到login登录页。
用户名、密码正确验证
如果我们在登录页输入的用户名、密码都正确,则在MyRealm中的doGetAuthenticationInfo(AuthenticationToken token)身份验证通过,继续在MyRealm的doGetAuthorizationInfo(PrincipalCollection principals)进行权限验证。
通过authorizationInfo.setRoles(userDao.getRoles(con, userName))和authorizationInfo.setStringPermissions(userDao.getPermissions(con,userName))把根据当前用户名查询出当前用户的角色和权限信息保存到SimpleAuthorizationInfo对象中。
这样shiro框架便可以根据SimpleAuthorizationInfo对象中的信息判断success.jsp页面中的哪些shiro标签内容可以显示。
通过上述验证过程我们可以发现,shiro更多的是帮助我们完成验证过程。我们需要从数据库查询当前用户的角色、权限,把这些信息告诉shiro框架,同时在jsp页面定义好哪些内容哪些角色哪些权限可以访问,剩下的就是shiro框架的事儿了。
shiro是不是很简单?