1. 概述
在本例子中使用Apache Shiro在Web应用中实现身份认证,将Shiro与Spring进行集成,使用内嵌的derby数据库存储用户信息。
持久层为Hibernate,数据库连接池为alibaba druid。
2. 准备
创建一个内嵌的derby数据库,本例使用的是db-derby-10.10.1.1。
2.1 建表
Create table users(
Id int primary key,
Name varchar(20),
Passwd varchar(20)
);
2.2 初始化数据
Insert into users values(1,’admin’,’admin’);
Insert into users values(2,’peter’,’peter’);
3. 配置
3.1 Web.xml
<!-- Apache Shiro --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3.2 ApplicationContext.xml
<!-- 安全认证过滤器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/index.do" /> <property name="filterChainDefinitions"> <value> /login.do = anon /** = authc </value> </property> </bean> <!-- 定义 Shiro 主要业务对象 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="systemAuthorizingRealm" /> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
4. 认证
登录JSP
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!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>Login</title> </head> <body> <form id="form1" name="form1" method="post" action="login.do"> <p align="center">用户登录</p> <table width="296" border="1" align="center" bgcolor="#00FF99"> <tr> <td width="98" height="34">用户名:</td> <td width="182"><label><input name="loginName" type="text" id="loginName" /> </label></td> </tr> <tr> <td height="36">密码:</td> <td><label> <input name="password" type="password" id="password" /> </label></td> </tr> <tr> <td height="35" colspan="2"><label> <input type="submit" name="Submit" value="提交" /> </label> <label> <input type="reset" name="Submit2" value="重置" /> </label></td> </tr> </table> </form> </body> </html>
Web控制器
@Controller public class LoginController { private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class); @RequestMapping(value = "/login.do", method = RequestMethod.POST) public String isLogin(HttpServletRequest request, PasswordAuthcInfo passwordAuthcInfo) { String loginName = passwordAuthcInfo.getLoginName(); String loginPassword = passwordAuthcInfo.getPassword(); LOGGER.info("loginName:" + loginName + ";loginPassword:" + loginPassword); HttpSession session = request.getSession(true); String errorMessage = ""; Subject user = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(loginName, loginPassword); token.setRememberMe(true); try { user.login(token); String userID = (String) user.getPrincipal(); LOGGER.info("User [" + userID + "] logged in successfully."); session.setAttribute("USERNAME", userID); return "success"; } catch (UnknownAccountException uae) { errorMessage = "用户认证失败:" + "username wasn't in the system."; LOGGER.info(errorMessage); } catch (IncorrectCredentialsException ice) { errorMessage = "用户认证失败:" + "password didn't match."; LOGGER.info(errorMessage); } catch (LockedAccountException lae) { errorMessage = "用户认证失败:" + "account for that username is locked - can't login."; LOGGER.info(errorMessage); } catch (AuthenticationException e) { errorMessage = "登录失败错误信息:" + e; LOGGER.error(errorMessage); e.printStackTrace(); token.clear(); } session.setAttribute("ErrorMessage", errorMessage); return "error"; } }
认证服务类
@Service public class SystemAuthorizingRealm extends AuthorizingRealm { @Resource(name = "userService") private UserService userService; // 授权 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) { // TODO Auto-generated method stub return null; } // 认证 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; Users user = userService.getUser(token.getUsername()); if (user != null) { return new SimpleAuthenticationInfo(user.getName(), user.getPassword(), ""); } else { return null; } } }
用户服务类
@Service("userService") public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; public Users getUser(String userName) { Users users = null; try { users = userDao.searchUser(userName); } catch (DataAccessException e) { e.printStackTrace(); } return users; } }
数据库操作类
@Repository("UserDao") public class UserDaoImpl extends BaseDaoImpl implements UserDao { public Users searchUser(String userName) throws DataAccessException{ Users users = null; try { Session session = sessionFactory.openSession(); Query query = session.createQuery("from Users a where a.name=:name").setString( "name", userName); users = (Users) query.uniqueResult(); session.close(); } catch (Throwable e) { throw new DataAccessException(e); } return users; } }
5. 内置表单过滤器
上面的程序是使用Spring的Web控制器来获取页面提交的数据,也可以使用Shiro内置的表单过滤器来实现页面数据提交。
修改applicationContext.xml增加过滤器
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/login.do" /> <property name="successUrl" value="/main.do" /> <property name="unauthorizedUrl" value="/error.do" /> <property name="filters"> <util:map> <entry key="authc"> <bean class="com.peter.smallshow.security.CustomFormAuthenticationFilter"> <property name="usernameParam" value="loginName" /> <property name="passwordParam" value="password" /> </bean> </entry> </util:map> </property> <property name="filterChainDefinitions"> <value> /index.do = anon /login.do = authc /** = authc </value> </property> </bean>
表单中的参数固定写法是username、password、rememberMe。
可以通过<property name="usernameParam" value="loginName" />来设置
自定义的表单过滤类
自定义的表单过滤类
@Service public class CustomFormAuthenticationFilter extends FormAuthenticationFilter { protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) { String username = getUsername(request); String password = getPassword(request); if (password == null) { password = ""; } boolean rememberMe = false; String host = getHost(request); return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host); } }
6.工程代码
源码:smallShow-v0.9.1.rar
http://download.csdn.net/detail/peterwanghao/6858101