Shiro搭建

来源:互联网 发布:windows 10更新 编辑:程序博客网 时间:2024/06/05 00:51

shiro学习参考

<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.2.0</version></dependency>


1.web.xml 里加入

<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>

2.applicationContext里加入

<import resource="classpath:spring/shiro.xml" />

3.创建shiro.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"default-lazy-init="true"><description>Shiro Configuration</description><!-- <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.ServletContainerSessionManager" />  --><!-- 不用此功能建议删除,找不到类报错 --><!-- <bean id="kickoutSessionControlFilter" class="com.impay.smsboss.filter.KickoutSessionControlFilter">          <property name="cacheManager" ref="shiroCacheManager"/>          <property name="sessionManager" ref="securityManager"/>         是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户         <property name="kickoutAfter" value="false"/>          同一个用户最大的会话数,默认1;比如2的意思是同一个用户允许最多同时两个人登录        <property name="maxSession" value="1"/>          <property name="kickoutUrl" value="/login"/>      </bean>  <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.MemorySessionDAO" /><bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"><property name="sessionDAO" ref="sessionDAO"/></bean> --> <!-- Shiro's main business-tier object for web-enabled applications --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="shiroDbRealm" /><property name="cacheManager" ref="shiroCacheManager" /><!-- <property name="sessionManager" ref="sessionManager" /> --></bean><!-- 用来做登录用户验证 --><bean id="shiroDbRealm" class="com.impay.auth.ShiroDbRealm" /><!-- Shiro Filter --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager" /><property name="loginUrl" value="/login" /><property name="successUrl" value="/welcome" /><property name="filters"><map><entry key="authc" value-ref="authc" /><!-- <entry key="kickout" value-ref="kickoutSessionControlFilter"/> --></map></property><property name="filterChainDefinitions"><value><!-- anon:游客,authc:必须通过认证,user:上一次登陆过 -->/callback/** = anon <!-- 指定不需要拦截的路径 -->/sms_check_file/** = anon/login = authc/logout = logout/images/** = anon/scripts/** = anon/uploads/** = anon/account/cashReturnData/** = anon/thems/** = anon/servlet/** = anon/*.ico = anon/hello = anon/tfb* = anon/veer.* = anon    /** = user </value></property></bean> <!-- 用户授权信息Cache --><bean id="shiroCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /><!-- 保证实现了Shiro内部lifecycle函数的bean执行 --><bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/><!-- AOP式方法级权限检查  --><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"><property name="proxyTargetClass" value="true" /></bean><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">    <property name="securityManager" ref="securityManager"/></bean></beans>


4.ShiroDbRealm(验证、授权类)

package com.impay.smsboss.auth;import java.sql.SQLException;import java.util.List;import javax.servlet.http.HttpServletRequest;import org.apache.commons.lang.StringUtils;import org.apache.shiro.SecurityUtils;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.credential.HashedCredentialsMatcher;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.crypto.hash.Md5Hash;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import com.impay.smsboss.domain.SysAuth;import com.impay.smsboss.domain.SysUser;import com.impay.smsboss.service.SysUserService;/** * 登录系统后,对用户进行检验,包括严重和授权 *  * @author dj *  */@Componentpublic class ShiroDbRealm extends AuthorizingRealm {private static final Logger log = LoggerFactory.getLogger(ShiroDbRealm.class);@Autowiredprivate SysUserService userService;// 设置密码加密方式为MD5public ShiroDbRealm() {HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(Md5Hash.ALGORITHM_NAME);setCredentialsMatcher(matcher);}// 用户验证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {UsernamePasswordCaptchaToken token2 = (UsernamePasswordCaptchaToken) token;//System.out.println(token.getUsername() + "====="); // 增加判断验证码逻辑 String captcha = token2.getCaptcha(); String exitCode = (String) SecurityUtils.getSubject().getSession().getAttribute(CaptchaServlet.KEY_CAPTCHA);//"SE_KEY_MM_CODE" if (null == captcha || !captcha.equalsIgnoreCase(exitCode)) { throw new CaptchaException("验证码错误"); }if (token.getPrincipal() == null)return null;log.info("User login: {}", token.getPrincipal());SysUser user = null;try {user = userService.getByUserName((String) token.getPrincipal());//根据用户名得到用户信息} catch (Exception e) {log.error("query user exception", e);}if (user == null) {return null;}String username = (String) token.getPrincipal();HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();try {if (userService.getAuthSize(user.getId()).equals("0")) {//没有任何权限request.setAttribute("UNAUTH","UnknownAuthAccountException");request.setAttribute("USERNAME",username);return null;}else if(userService.getAuthSize(user.getId()).equals("1")){//状态异常request.setAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME,"UnknownAccountException");return null;}} catch (SQLException e) {e.printStackTrace();}return new SimpleAuthenticationInfo(user, user.getPassword(), getName());}// 用户授权// TODO@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {SysUser ru = (SysUser) principals.fromRealm(getName()).iterator().next();if (ru == null) {return null;}SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();List<SysAuth> ra;try {ra = userService.getAuthList(ru.getId());//获取权限列表for (SysAuth r : ra) {info.addStringPermission(StringUtils.trim(r.getAuthCode()));}} catch (SQLException e) {e.printStackTrace();}return info;}@Overridepublic boolean supports(AuthenticationToken token) {return super.supports(token);}}


5.ShiroAuthcFilter

package com.ssm.auth;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Map;import javax.annotation.Resource;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpSession;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.subject.Subject;import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;import org.apache.shiro.web.util.WebUtils;import org.springframework.stereotype.Component;import com.ssm.domain.SysUser;import com.ssm.service.SysUserService;/** * 表单认证过滤器,可以在这里记录登录成功后的日志记录等操作 *  * @author dj *  */@Component("authc")public class ShiroAuthcFilter extends FormAuthenticationFilter {@Resourceprivate SysUserService userService;public static final String DEFAULT_CAPTCHA_PARAM = "captcha";private String captchaParam = DEFAULT_CAPTCHA_PARAM;public String getCaptchaParam() {return captchaParam;}protected String getCaptcha(ServletRequest request) {return WebUtils.getCleanParam(request, getCaptchaParam());}protected AuthenticationToken createToken(ServletRequest request,ServletResponse response) {String username = getUsername(request);String password = getPassword(request) == null ? "" : getPassword(request);String captcha = getCaptcha(request);boolean rememberMe = isRememberMe(request);String host = getHost(request);return new UsernamePasswordCaptchaToken(username,password.toCharArray(), rememberMe, host, captcha);}// 登录成功操作,这里设置了代理商常用信息@Overrideprotected boolean onLoginSuccess(AuthenticationToken token,Subject subject, ServletRequest request, ServletResponse response)throws Exception {SysUser sysUser = (SysUser) SecurityUtils.getSubject().getPrincipal();HttpSession session = WebUtils.toHttp(request).getSession(true);session.setAttribute("user", sysUser);//session.setAttribute("power", userService.checkPower(riskUser.getId()));Map<String, String> param = new HashMap<String, String>();WebUtils.issueRedirect(request, response, getSuccessUrl(), param, true);// save logString ip = request.getRemoteAddr();userService.updateUserLoginTime(sysUser);//修改用户最后登录时间Date date=sysUser.getLastLoginTime();String newDate="";if(date!=null){SimpleDateFormat dataTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    newDate= dataTimeFormat.format(date);}session.setAttribute("last_login_time", date==null?null:newDate);Map<String,Object> map = userService.findUserLastLoginLog(sysUser.getId()+"");//根据用户信息获取登录记录表信息if(map!=null){//之前登陆过session.setAttribute("login_location",  map.get("location"));}userService.saveLog(ip, sysUser);//登录记录表里加本次登录数据return false;}}


6.UsernamePasswordCaptchaToken(shiro内部实体类)

package com.impay.smsboss.auth;import org.apache.shiro.authc.UsernamePasswordToken;public class UsernamePasswordCaptchaToken extends UsernamePasswordToken {private static final long serialVersionUID = 1L;private String captcha;public String getCaptcha() {return captcha;}public void setCaptcha(String captcha) {this.captcha = captcha;}public UsernamePasswordCaptchaToken() {super();}public UsernamePasswordCaptchaToken(String username, char[] password,boolean rememberMe, String host, String captcha) {super(username, password, rememberMe, host);this.captcha = captcha;}}




7.SysUser(系统domain)

package com.ssm.domain;import java.io.Serializable;import java.util.Date;public class SysUser extends ToString implements Serializable{private static final long serialVersionUID = 1L;private Long id;    private String userName;    private String realName;    private String email;    private String status;    private String password;    private Long failTimes;    private String deptCode;    private Long createOperatorId;    private Date updatePasswTime;    private String remark;    private Long parentId;    private Date createTime;    private String operatorId;    private Date operatorTime;    private Date lastLoginTime;    private Long deptId;    private String saleFlag;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getUserName() {        return userName;    }    public void setUserName(String userName) {        this.userName = userName == null ? null : userName.trim();    }    public String getRealName() {        return realName;    }    public void setRealName(String realName) {        this.realName = realName == null ? null : realName.trim();    }    public String getEmail() {        return email;    }    public void setEmail(String email) {        this.email = email == null ? null : email.trim();    }    public String getStatus() {        return status;    }    public void setStatus(String status) {        this.status = status == null ? null : status.trim();    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password == null ? null : password.trim();    }    public Long getFailTimes() {        return failTimes;    }    public void setFailTimes(Long failTimes) {        this.failTimes = failTimes;    }    public String getDeptCode() {        return deptCode;    }    public void setDeptCode(String deptCode) {        this.deptCode = deptCode == null ? null : deptCode.trim();    }    public Long getCreateOperatorId() {        return createOperatorId;    }    public void setCreateOperatorId(Long createOperatorId) {        this.createOperatorId = createOperatorId;    }    public Date getUpdatePasswTime() {        return updatePasswTime;    }    public void setUpdatePasswTime(Date updatePasswTime) {        this.updatePasswTime = updatePasswTime;    }    public String getRemark() {        return remark;    }    public void setRemark(String remark) {        this.remark = remark == null ? null : remark.trim();    }    public Long getParentId() {        return parentId;    }    public void setParentId(Long parentId) {        this.parentId = parentId;    }    public Date getCreateTime() {        return createTime;    }    public void setCreateTime(Date createTime) {        this.createTime = createTime;    }    public String getOperatorId() {        return operatorId;    }    public void setOperatorId(String operatorId) {        this.operatorId = operatorId == null ? null : operatorId.trim();    }    public Date getOperatorTime() {        return operatorTime;    }    public void setOperatorTime(Date operatorTime) {        this.operatorTime = operatorTime;    }    public Date getLastLoginTime() {        return lastLoginTime;    }    public void setLastLoginTime(Date lastLoginTime) {        this.lastLoginTime = lastLoginTime;    }    public Long getDeptId() {        return deptId;    }    public void setDeptId(Long deptId) {        this.deptId = deptId;    }    public String getSaleFlag() {        return saleFlag;    }    public void setSaleFlag(String saleFlag) {        this.saleFlag = saleFlag == null ? null : saleFlag.trim();    }}




8.ToString(系统domain)

package com.impay.smsboss.domain;import org.apache.commons.lang.builder.ToStringBuilder;import org.apache.commons.lang.builder.ToStringStyle;/** * @Title ToString.java * @Description 重写toString方法,打印方便 * @author dongjie.wang,<a href="mailto:wangdj@cnepay.com">wangdj@cnepay.com</a> * @date 2012-5-17 下午10:08:55 * @version V1.0 */public class ToString{@Overridepublic String toString() {return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);}}

9.CaptchaServlet

package com.impay.smsboss.auth;import java.awt.image.BufferedImage;import java.io.IOException;import javax.imageio.ImageIO;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;public class CaptchaServlet extends HttpServlet {private static final long serialVersionUID = -124247581620199710L;public static final String KEY_CAPTCHA = "SE_KEY_MM_CODE";@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {// 设置相应类型,告诉浏览器输出的内容为图片resp.setContentType("image/jpeg");// 不缓存此内容resp.setHeader("Pragma", "No-cache");resp.setHeader("Cache-Control", "no-cache");resp.setDateHeader("Expire", 0);try {HttpSession session = req.getSession();CaptchaUtil tool = new CaptchaUtil();StringBuffer code = new StringBuffer();BufferedImage image = tool.genRandomCodeImage(code);session.removeAttribute(KEY_CAPTCHA);session.setAttribute(KEY_CAPTCHA, code.toString());// 将内存中的图片通过流动形式输出到客户端ImageIO.write(image, "JPEG", resp.getOutputStream());} catch (Exception e) {e.printStackTrace();}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {doGet(req, resp);}}

10.CaptchaUtil(验证码类)

package com.impay.smsboss.auth;import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import java.awt.image.BufferedImage;import java.io.File;import java.io.FileOutputStream;import java.util.Random;import javax.imageio.ImageIO;public class CaptchaUtil {// 随机产生的字符串//private static final String RANDOM_STRS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";private static final String RANDOM_STRS = "0123456789";private static final String FONT_NAME = "Arial";private static final int FONT_SIZE = 18;private Random random = new Random();private int width = 80;// 图片宽private int height = 25;// 图片高private int lineNum = 50;// 干扰线数量private int strNum = 4;// 随机产生字符数量/** *  * 生成随机图片 */public BufferedImage genRandomCodeImage(StringBuffer randomCode) {// BufferedImage类是具有缓冲区的Image类BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_BGR);// 获取Graphics对象,便于对图像进行各种绘制操作Graphics g = image.getGraphics();// 设置背景色g.setColor(getRandColor(200, 250));g.fillRect(0, 0, width, height);// 设置干扰线的颜色g.setColor(getRandColor(110, 120));// 绘制干扰线for (int i = 0; i <= lineNum; i++) {drowLine(g);}// 绘制随机字符g.setFont(new Font(FONT_NAME, Font.ROMAN_BASELINE, FONT_SIZE));for (int i = 1; i <= strNum; i++) {randomCode.append(drowString(g, i));}g.dispose();return image;}/** *  * 给定范围获得随机颜色 */private Color getRandColor(int fc, int bc) {if (fc > 255)fc = 255;if (bc > 255)bc = 255;int r = fc + random.nextInt(bc - fc);int g = fc + random.nextInt(bc - fc);int b = fc + random.nextInt(bc - fc);return new Color(r, g, b);}/** *  * 绘制字符串 */private String drowString(Graphics g, int i) {g.setColor(new Color(random.nextInt(101), random.nextInt(111), random.nextInt(121)));String rand = String.valueOf(getRandomString(random.nextInt(RANDOM_STRS.length())));g.translate(random.nextInt(3), random.nextInt(3));g.drawString(rand, 13 * i, 16);return rand;}/** *  * 绘制干扰线 */private void drowLine(Graphics g) {int x = random.nextInt(width);int y = random.nextInt(height);int x0 = random.nextInt(16);int y0 = random.nextInt(16);g.drawLine(x, y, x + x0, y + y0);}/** *  * 获取随机的字符 */private String getRandomString(int num) {return String.valueOf(RANDOM_STRS.charAt(num));}public static void main(String[] args) {CaptchaUtil tool = new CaptchaUtil();StringBuffer code = new StringBuffer();BufferedImage image = tool.genRandomCodeImage(code);System.out.println(">>> random code =: " + code);try {// 将内存中的图片通过流动形式输出到客户端ImageIO.write(image, "JPEG", new FileOutputStream(new File("random-code.jpg")));} catch (Exception e) {e.printStackTrace();}}}

11.CaptchaException(shiro异常类)

package com.impay.smsboss.auth;import org.apache.shiro.authc.AuthenticationException;public class CaptchaException extends AuthenticationException {private static final long serialVersionUID = 1L;public CaptchaException() {super();}public CaptchaException(String message, Throwable cause) {super(message, cause);}public CaptchaException(String message) {super(message);}public CaptchaException(Throwable cause) {super(cause);}}

12.SysAuth(权限表,系统domain)

package com.impay.smsboss.domain;import java.util.Date;/** *  * @author donjek *  */public class SysAuth {private Long id;private String authCode;private String authName;private String remark;private Date createTime;private Long parentId;private Long categoryId;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getAuthCode() {return authCode;}public void setAuthCode(String authCode) {this.authCode = authCode;}public String getAuthName() {return authName;}public void setAuthName(String authName) {this.authName = authName;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}public Long getParentId() {return parentId;}public void setParentId(Long parentId) {this.parentId = parentId;}public Long getCategoryId() {return categoryId;}public void setCategoryId(Long categoryId) {this.categoryId = categoryId;}}

13.login.jsp

<%@page import="org.springframework.web.servlet.mvc.condition.ParamsRequestCondition"%><%@page pageEncoding="utf8"%><%@include file="/tag.jsp"%><%@ page isELIgnored="false"%><%@ page import="org.apache.shiro.web.filter.authc.FormAuthenticationFilter" %><!DOCTYPE html><html><head><meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8" /><meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /><title>----平台</title><link type="image/x-icon" href="${ ctx}/images/favicon.ico" rel="icon"/><link rel="stylesheet" type="text/css" href="${ ctx}/thems/login.css?12" /><script type="text/javascript" src="${ctx }/scripts/jquery-1.4.4.min.js"></script><script type="text/javascript">    function refreshCaptcha() {    var _captcha_id = document.getElementById("img_captcha");        _captcha_id.src="servlet/captchaCode?t=" + Math.random();    }      //判断当前窗口是否有顶级窗口,如果有就让当前的窗口的地址栏发生变化,       function loadTopWindow(){           if (window.top!=null && window.top.document.URL!=document.URL){               window.top.location= document.URL; //这样就可以让登陆窗口显示在整个窗口了           }       }              $(function() {        var msg = $("#msg").val();if ($.trim(msg).length > 0) {alert(msg);}        //判断当前窗口是否有顶级窗口,如果有就让当前的窗口的地址栏发生变化,        /* if (window.top!=null && window.top.document.URL!=document.URL){                window.top.location= document.URL; //这样就可以让登陆窗口显示在整个窗口了                return;         }   */        loadTopWindow();    var ret_user_name = $("#ret_user_name").val();if (ret_user_name != "" && ret_user_name != "null") {$("#username").val(ret_user_name);}});        </script></head><body style="background-color: #FFF"><div id="login"><div id="login_main"><form:form id="loginForm" action="${ctx}/login" method="post" ><div class="login_form"><table cellpadding="0" cellspacing="0"><tr><td colspan="2" valign="middle"><input id="username" name="username" maxlength="20"  value="" /></td></tr><tr><td colspan="2" valign="middle"><input type="password" id="password" name="password" maxlength="20" value=""/></td></tr><tr><td valign="middle"><input type="text" id="captcha"name="captcha" size="4" maxlength="4" class="required" /></td><td valign="middle" align="right"><img title="点击更换"id="img_captcha" onclick="javascript:refreshCaptcha();"src="servlet/captchaCode"></td></tr></table></div><div class="login_btn"><input name="submit" class="login_button" type="submit" id="submit"   value=""/></div><%String msg = "";String error = (String) request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);String flag = (String) request.getAttribute("LOGINFLAG");String auth = (String) request.getAttribute("UNAUTH");String username = (String) request.getAttribute("USERNAME");if(flag!=null){if(flag.endsWith("NoUpdatePasswordException")){msg = "口令过期";}else if(flag.endsWith("USERISLOGINING")){msg = "该用户已经登录";}}else if(error != null){if(error.endsWith("UnknownAccountException")){msg = "用户状态异常或用户名不存在";}if(error.endsWith("FailTimesException")){msg = "密码错误次数超限";}if(error.endsWith("IncorrectCredentialsException")){msg = "用户名或密码错";}if(error.endsWith("CaptchaException")){msg = "验证码错误,请重试.";}}if(auth!=null){if(auth.endsWith("UnknownAuthAccountException")){msg = "没有任何权限,请联系管理员.";}}%>        <input type="hidden" value="<%=msg %>" id="msg" /><input type="hidden" value="<%=username %>" id="ret_user_name" /></form:form></div><div id="login_bottom"></div></div></body></html>

14.tag.jsp

<%@ page pageEncoding="utf-8" trimDirectiveWhitespaces="true"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/functions"%><%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt"%><%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%><%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %><%@ taglib prefix ="pagebar" uri="/WEB-INF/pagebar.tld" %><%@ taglib prefix ="u" uri="/WEB-INF/util.tld" %><c:set var="ctx" value="${pageContext.request.contextPath}" />

15.MainController

package com.impay.smsboss.controller;import java.io.IOException;import java.util.Map;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.shiro.SecurityUtils;import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import com.impay.smsboss.domain.SysUser;import com.impay.smsboss.service.SysUserService;import com.impay.smsboss.utils.MD5;/** * 系统登录,注销,首页等 *  * @author dj *  */@Controllerpublic class MainController extends BaseController {@Resourceprivate SysUserService userService;// private ReentrantLock  lock=new ReentrantLock();// 系统登录后的首页@RequestMapping(value = "/")public String main(Model model) {return "index";}// 系统登录后的首页@RequestMapping(value = "/welcome")public String welcome(Model model) {return "index";}// 用于未通过系统验证输入URL的跳转页面@RequestMapping(value = { "/login" }, method = RequestMethod.GET)public String login(Model model, HttpServletRequest request,HttpServletResponse response) throws IOException {return "login";}// 用户登录验证,用于提交form表单数据验证@RequestMapping(value = "/login", method = RequestMethod.POST)public String login(@RequestParam Map<String, String> params,HttpServletRequest request, Model model) {SysUser user = null;try {user = userService.getUserByPwd((String) params.get("username"),MD5.toMD5((String) params.get("password")));} catch (Exception e) {e.printStackTrace();}finally{// lock.unlock();}if (SecurityUtils.getSubject().isAuthenticated() && user != null&& Integer.parseInt(user.getStatus()) != 0) {//登录通过return "redirect:/";} else {user = userService.getByUserName(params.get("username"));if (null != user && null != user.getFailTimes()) {if (user.getFailTimes() > 6) {userService.updateStatus(params.get("username"), 0);}}String errorStr = (String) request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);if(errorStr!=null&&!errorStr.endsWith("CaptchaException")){userService.failTimes(params.get("username"));//登录失败次数加1}}if (user == null) {request.setAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME,"IncorrectCredentialsException");}return "login";}}


16.BaseController(封装基础类)

package com.impay.smsboss.controller;import java.util.HashMap;import java.util.Map;import javax.servlet.http.HttpServletResponse;import net.sf.json.JSONObject;import org.apache.shiro.SecurityUtils;import com.impay.smsboss.domain.SysUser;/** * 提供获取request,session,转换json等常用方法 *  * @author dj *  */public class BaseController {// header 常量定义private static final String DEFAULT_ENCODING = "GBK";private static final boolean DEFAULT_NOCACHE = true;// Content Type 常量定义public static final String TEXT_TYPE = "text/plain";public static final String JSON_TYPE = "application/json";public static final String XML_TYPE = "text/xml";public static final String HTML_TYPE = "text/html";public static final String JS_TYPE = "text/javascript";public static final String EXCEL_TYPE = "application/vnd.ms-excel";public static int PAGE_NUMERIC = 20;protected String getAgentNo() {String agentNo = (String) SecurityUtils.getSubject().getSession().getAttribute("agentNo");return agentNo;}protected SysUser getUser() {SysUser bossUser = (SysUser) SecurityUtils.getSubject().getSession().getAttribute("user");return bossUser;}/** * 直接输出内容的简便函数. */protected void render(final String contentType, final String content,final HttpServletResponse response) {HttpServletResponse resp = initResponseHeader(contentType, response);try {resp.getWriter().write(content);resp.getWriter().flush();} catch (Exception e) {e.printStackTrace();}}/** * 直接输出文本. */protected void outText(final String text, final HttpServletResponse response) {render(TEXT_TYPE, text, response);}/** * 直接输出HTML. */protected void outHtml(final String html, final HttpServletResponse response) {render(HTML_TYPE, html, response);}/** * 直接输出XML. */protected void outXml(final String xml, final HttpServletResponse response) {render(XML_TYPE, xml, response);}/** * 输出JSON,可以接收参数如: [{'name':'www'},{'name':'www'}],['a','b'],new * String[]{'a','b'},合并如下:jsonString = "{TOTALCOUNT:" + totalCount + ", * ROOT:" + jsonString + "}"; *  * @param jsonString *            json字符串. *  */protected void outJson(final String json, final HttpServletResponse response) {render(JSON_TYPE, json, response);}/** * 设置让浏览器弹出下载对话框的Header. *  * @param fileName *            下载后的文件名. */protected void setFileDownloadHeader(HttpServletResponse response,String fileName) {try {// 中文文件名支持String encodedfileName = new String(fileName.getBytes(),"ISO8859-1");response.setHeader("Content-Disposition", "attachment; filename=\""+ encodedfileName + "\"");} catch (Exception e) {e.printStackTrace();}}/** * 分析并设置contentType与headers. */protected HttpServletResponse initResponseHeader(final String contentType,final HttpServletResponse response) {// 分析headers参数String encoding = DEFAULT_ENCODING;boolean noCache = DEFAULT_NOCACHE;// 设置headers参数String fullContentType = contentType + ";charset=" + encoding;response.setContentType(fullContentType);if (noCache) {setNoCacheHeader(response);}return response;}/** * 设置客户端无缓存Header. */protected void setNoCacheHeader(HttpServletResponse response) {// Http 1.0 headerresponse.setDateHeader("Expires", 0);response.addHeader("Pragma", "no-cache");// Http 1.1 headerresponse.setHeader("Cache-Control", "no-cache");}protected void outJsonMap(int flag, String errorMessage, HttpServletResponse response){Map<String, Object> jsonMap = new HashMap<String, Object>();jsonMap.put("flag", flag);jsonMap.put("errorMessage", errorMessage);String json = JSONObject.fromObject(jsonMap).toString();outJson(json, response);}}

17.import net.sf.json.JSONObject;

pom.xml
<dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.4</version><classifier>jdk15</classifier></dependency>


18.MD5工具类

package com.impay.smsboss.utils;import java.io.UnsupportedEncodingException;import java.security.SignatureException;import org.apache.commons.codec.digest.DigestUtils;public class MD5 {static final int S11 = 7;static final int S12 = 12;static final int S13 = 17;static final int S14 = 22;static final int S21 = 5;static final int S22 = 9;static final int S23 = 14;static final int S24 = 20;static final int S31 = 4;static final int S32 = 11;static final int S33 = 16;static final int S34 = 23;static final int S41 = 6;static final int S42 = 10;static final int S43 = 15;static final int S44 = 21;static final byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0 };/* * 下面的三个成员是MD5计算过程中用到的3个核心数据,在原始的C实现中 被定义到MD5_CTX结构中 */private long[] state = new long[4]; // state (ABCD)private long[] count = new long[2]; // number of bits, modulo 2^64 (lsb// first)private byte[] buffer = new byte[64]; // input buffer/* * digestHexStr是MD5的唯一一个公共成员,是最新一次计算结果的 16进制ASCII表示. */public String digestHexStr;/* * digest,是最新一次计算结果的2进制内部表示,表示128bit的MD5值. */private byte[] digest = new byte[16];/* * getMD5ofStr是类MD5最主要的公共方法,入口参数是你想要进行MD5变换的字符串 * 返回的是变换完的结果,这个结果是从公共成员digestHexStr取得的. */public String getMD5ofStr(String inbuf) {md5Init();md5Update(inbuf.getBytes(), inbuf.length());md5Final();digestHexStr = "";for (int i = 0; i < 16; i++) {digestHexStr += byteHEX(digest[i]);}return digestHexStr;}// 这是MD5这个类的标准构造函数,JavaBean要求有一个public的并且没有参数的构造函数public MD5() {md5Init();return;}/* md5Init是一个初始化函数,初始化核心变量,装入标准的幻数 */private void md5Init() {count[0] = 0L;count[1] = 0L;// /* Load magic initialization constants.state[0] = 0x67452301L;state[1] = 0xefcdab89L;state[2] = 0x98badcfeL;state[3] = 0x10325476L;return;}/* * F, G, H ,I 是4个基本的MD5函数,在原始的MD5的C实现中,由于它们是 * 简单的位运算,可能出于效率的考虑把它们实现成了宏,在java中,我们把它们 实现成了private方法,名字保持了原来C中的。 */private long F(long x, long y, long z) {return (x & y) | ((~x) & z);}private long G(long x, long y, long z) {return (x & z) | (y & (~z));}private long H(long x, long y, long z) {return x ^ y ^ z;}private long I(long x, long y, long z) {return y ^ (x | (~z));}/* * FF,GG,HH和II将调用F,G,H,I进行近一步变换 FF, GG, HH, and II transformations for * rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent * recomputation. */private long FF(long a, long b, long c, long d, long x, long s, long ac) {a += F(b, c, d) + x + ac;a = ((int) a << s) | ((int) a >>> (32 - s));a += b;return a;}private long GG(long a, long b, long c, long d, long x, long s, long ac) {a += G(b, c, d) + x + ac;a = ((int) a << s) | ((int) a >>> (32 - s));a += b;return a;}private long HH(long a, long b, long c, long d, long x, long s, long ac) {a += H(b, c, d) + x + ac;a = ((int) a << s) | ((int) a >>> (32 - s));a += b;return a;}private long II(long a, long b, long c, long d, long x, long s, long ac) {a += I(b, c, d) + x + ac;a = ((int) a << s) | ((int) a >>> (32 - s));a += b;return a;}/* * md5Update是MD5的主计算过程,inbuf是要变换的字节串,inputlen是长度,这个 * 函数由getMD5ofStr调用,调用之前需要调用md5init,因此把它设计成private的 */private void md5Update(byte[] inbuf, int inputLen) {int i, index, partLen;byte[] block = new byte[64];index = (int) (count[0] >>> 3) & 0x3F;// /* Update number of bits */if ((count[0] += (inputLen << 3)) < (inputLen << 3))count[1]++;count[1] += (inputLen >>> 29);partLen = 64 - index;// Transform as many times as possible.if (inputLen >= partLen) {md5Memcpy(buffer, inbuf, index, 0, partLen);md5Transform(buffer);for (i = partLen; i + 63 < inputLen; i += 64) {md5Memcpy(block, inbuf, 0, i, 64);md5Transform(block);}index = 0;} elsei = 0;// /* Buffer remaining input */md5Memcpy(buffer, inbuf, index, i, inputLen - i);}/* * md5Final整理和填写输出结果 */private void md5Final() {byte[] bits = new byte[8];int index, padLen;// /* Save number of bits */Encode(bits, count, 8);// /* Pad out to 56 mod 64.index = (int) (count[0] >>> 3) & 0x3f;padLen = (index < 56) ? (56 - index) : (120 - index);md5Update(PADDING, padLen);// /* Append length (before padding) */md5Update(bits, 8);// /* Store state in digest */Encode(digest, state, 16);}/* * md5Memcpy是一个内部使用的byte数组的块拷贝函数,从input的inpos开始把len长度的 * 字节拷贝到output的outpos位置开始 */private void md5Memcpy(byte[] output, byte[] input, int outpos, int inpos,int len) {int i;for (i = 0; i < len; i++)output[outpos + i] = input[inpos + i];}/* * md5Transform是MD5核心变换程序,有md5Update调用,block是分块的原始字节 */private void md5Transform(byte block[]) {long a = state[0], b = state[1], c = state[2], d = state[3];long[] x = new long[16];Decode(x, block, 64);/* Round 1 */a = FF(a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */d = FF(d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */c = FF(c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */b = FF(b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */a = FF(a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */d = FF(d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */c = FF(c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */b = FF(b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */a = FF(a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */d = FF(d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */c = FF(c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */b = FF(b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */a = FF(a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */d = FF(d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */c = FF(c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */b = FF(b, c, d, a, x[15], S14, 0x49b40821L); /* 16 *//* Round 2 */a = GG(a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */d = GG(d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */c = GG(c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */a = GG(a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */d = GG(d, a, b, c, x[10], S22, 0x2441453L); /* 22 */c = GG(c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */a = GG(a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */d = GG(d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */c = GG(c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */b = GG(b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */a = GG(a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */c = GG(c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 *//* Round 3 */a = HH(a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */d = HH(d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */c = HH(c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */b = HH(b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */a = HH(a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */b = HH(b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */a = HH(a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */d = HH(d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */c = HH(c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */b = HH(b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */a = HH(a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */d = HH(d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */b = HH(b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 *//* Round 4 */a = II(a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */d = II(d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */c = II(c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */b = II(b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */a = II(a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */d = II(d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */c = II(c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */b = II(b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */a = II(a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */c = II(c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */b = II(b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */a = II(a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */d = II(d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */c = II(c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */b = II(b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */state[0] += a;state[1] += b;state[2] += c;state[3] += d;}/* * Encode把long数组按顺序拆成byte数组,因为java的long类型是64bit的, 只拆低32bit,以适应原始C实现的用途 */private void Encode(byte[] output, long[] input, int len) {int i, j;for (i = 0, j = 0; j < len; i++, j += 4) {output[j] = (byte) (input[i] & 0xffL);output[j + 1] = (byte) ((input[i] >>> 8) & 0xffL);output[j + 2] = (byte) ((input[i] >>> 16) & 0xffL);output[j + 3] = (byte) ((input[i] >>> 24) & 0xffL);}}/* * Decode把byte数组按顺序合成成long数组,因为java的long类型是64bit的, * 只合成低32bit,高32bit清零,以适应原始C实现的用途 */private void Decode(long[] output, byte[] input, int len) {int i, j;for (i = 0, j = 0; j < len; i++, j += 4)output[i] = b2iu(input[j]) | (b2iu(input[j + 1]) << 8)| (b2iu(input[j + 2]) << 16) | (b2iu(input[j + 3]) << 24);return;}/* * b2iu是我写的一个把byte按照不考虑正负号的原则的"升位"程序,因为java没有unsigned运算 */public static long b2iu(byte b) {return b < 0 ? b & 0x7F + 128 : b;}/* * byteHEX(),用来把一个byte类型的数转换成十六进制的ASCII表示, * 因为java中的byte的toString无法实现这一点,我们又没有C语言中的 sprintf(outbuf,"%02X",ib) */public static String byteHEX(byte ib) {char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A','B', 'C', 'D', 'E', 'F' };char[] ob = new char[2];ob[0] = Digit[(ib >>> 4) & 0X0F];ob[1] = Digit[ib & 0X0F];String s = new String(ob);return s;}// 加密public static String toMD5(String source) {MD5 md5 = new MD5();return md5.getMD5ofStr(source).toLowerCase();}  /**     * 签名字符�?     *     * @param text     *            �?要签名的字符�?     * @param key     *            密钥     * @param input_charset     *            编码格式     * @return 签名结果     */    public static String sign(String text, String key, String charset) throws Exception {        text = text + key;        return DigestUtils.md5Hex(getContentBytes(text, charset));    }        /**     * @param content     * @param charset     * @return     * @throws SignatureException     * @throws UnsupportedEncodingException     */    private static byte[] getContentBytes(String content, String charset) {        if (charset == null || "".equals(charset)) {            return content.getBytes();        }        try {            return content.getBytes(charset);        } catch (UnsupportedEncodingException e) {            throw new RuntimeException("签名过程中出现错�?,指定的编码集不对,您目前指定的编码集是:" + charset);        }    }}


18.web.xml

  <servlet>    <servlet-name>CaptchaServlet</servlet-name>    <servlet-class>com.impay.smsboss.auth.CaptchaServlet</servlet-class>  </servlet>  <servlet-mapping>    <servlet-name>CaptchaServlet</servlet-name>    <url-pattern>/servlet/captchaCode</url-pattern>  </servlet-mapping> <servlet-mapping>    <servlet-name>default</servlet-name>    <url-pattern>*.png</url-pattern>    <url-pattern>*.jpg</url-pattern>    <url-pattern>*.gif</url-pattern>    <url-pattern>*.js</url-pattern>    <url-pattern>*.css</url-pattern>    <url-pattern>*.ico</url-pattern>    <url-pattern>*.swf</url-pattern>    <url-pattern>*.zip</url-pattern>    <url-pattern>*.xml</url-pattern>  </servlet-mapping>

19.
   <!-- 防止 Xss 攻击过滤器 --> <filter>     <filter-name>XssSqlFilter</filter-name>     <filter-class>com.impay.smsboss.filter.XssFilter</filter-class>  </filter>  <filter-mapping>     <filter-name>XssSqlFilter</filter-name>     <url-pattern>/*</url-pattern>     <dispatcher>REQUEST</dispatcher>  </filter-mapping> 

20.XssFilter

package com.impay.smsboss.filter;import java.io.IOException;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;public class XssFilter implements Filter {FilterConfig filterConfig = null;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// TODO Auto-generated method stubthis.filterConfig = filterConfig;}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {// TODO Auto-generated method stubXssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);          chain.doFilter(xssRequest, response); }@Overridepublic void destroy() {// TODO Auto-generated method stubthis.filterConfig = null;}}

end....。。。

0 0
原创粉丝点击