springmvc拦截器实现登录验证
首先创建一个实体类:
Customer:
1 package com.petcare.pojo.base; 2 3 import java.sql.Date; 4 import java.sql.Timestamp; 5 6 /** 7 * Created by frank on 2017/5/7. 8 */ 9 10 public class Customer { 11 private Long customerId; 12 private String account; 13 private String passwd; 14 private String customerName; 15 private String wechat; 16 private String mobile; 17 18 public Long getCustomerId() { 19 return customerId; 20 } 21 public void setCustomerId(Long customerId) { 22 this.customerId = customerId; 23 } 24 public String getAccount() { 25 return account; 26 } 27 public void setAccount(String account) { 28 this.account = account; 29 } 30 public String getPasswd() { 31 return passwd; 32 } 33 public void setPasswd(String passwd) { 34 this.passwd = passwd; 35 } 36 public String getCustomerName() { 37 return customerName; 38 } 39 public void setCustomerName(String customerName) { 40 this.customerName = customerName; 41 } 42 public String getWechat() { 43 return wechat; 44 } 45 public void setWechat(String wechat) { 46 this.wechat = wechat; 47 } 48 public String getMobile() { 49 return mobile; 50 } 51 public void setMobile(String mobile) { 52 this.mobile = mobile; 53 } 54 55 @Override 56 public boolean equals(Object o) { 57 if (this == o) return true; 58 if (o == null || getClass() != o.getClass()) return false; 59 60 Customer customer = (Customer) o; 61 62 if (customerId != customer.customerId) return false; 63 if (account != null ? !account.equals(customer.account) : customer.account != null) return false; 64 if (passwd != null ? !passwd.equals(customer.passwd) : customer.passwd != null) return false; 65 if (customerName != null ? !customerName.equals(customer.customerName) : customer.customerName != null) 66 return false; 67 if (wechat != null ? !wechat.equals(customer.wechat) : customer.wechat != null) return false; 68 if (mobile != null ? !mobile.equals(customer.mobile) : customer.mobile != null) return false; 69 if (homephone != null ? !homephone.equals(customer.homephone) : customer.homephone != null) return false; 70 if (customerSex != null ? !customerSex.equals(customer.customerSex) : customer.customerSex != null) 71 return false; 72 if (customerBirth != null ? !customerBirth.equals(customer.customerBirth) : customer.customerBirth != null) 73 return false; 74 if (address != null ? !address.equals(customer.address) : customer.address != null) return false; 75 if (createSeid != null ? !createSeid.equals(customer.createSeid) : customer.createSeid != null) return false; 76 if (createTime != null ? !createTime.equals(customer.createTime) : customer.createTime != null) return false; 77 if (updateTime != null ? !updateTime.equals(customer.updateTime) : customer.updateTime != null) return false; 78 79 return true; 80 } 81 82 @Override 83 public int hashCode() { 84 int result = (int) (customerId ^ (customerId >>> 32)); 85 result = 31 * result + (account != null ? account.hashCode() : 0); 86 result = 31 * result + (passwd != null ? passwd.hashCode() : 0); 87 result = 31 * result + (customerName != null ? customerName.hashCode() : 0); 88 result = 31 * result + (wechat != null ? wechat.hashCode() : 0); 89 result = 31 * result + (mobile != null ? mobile.hashCode() : 0); 90 result = 31 * result + (homephone != null ? homephone.hashCode() : 0); 91 result = 31 * result + (customerSex != null ? customerSex.hashCode() : 0); 92 result = 31 * result + (customerBirth != null ? customerBirth.hashCode() : 0); 93 result = 31 * result + (address != null ? address.hashCode() : 0); 94 result = 31 * result + (createSeid != null ? createSeid.hashCode() : 0); 95 result = 31 * result + (createTime != null ? createTime.hashCode() : 0); 96 result = 31 * result + (updateTime != null ? updateTime.hashCode() : 0); 97 return result; 98 } 99 }
controller层;
1 @Controller 2 public class LoginController { 3 4 private Logger log = LoggerFactory.getLogger(getClass()); 5 6 public static final AjaxResponse ACCOUNT_NOT_EXIST = new AjaxResponse(-100101, "账号不存在"); 7 public static final AjaxResponse PASSWORD_NOT_PASSED = new AjaxResponse(-100102, "您输入密码错误"); 8 public static final AjaxResponse SYSTEM_BUSY = new AjaxResponse(-100000, "系统繁忙"); 9 public static final AjaxResponse ACCOUNT_LOCKED = new AjaxResponse(-100103, "您的帐号被锁定"); 10 11 12 @Autowired 13 private CustomerService customerService; 14 15 @RequestMapping(value = "/login", method = RequestMethod.GET) 16 public String loginPage(){ 17 return "/login"; 18 } 19 20 @RequestMapping(value = "/login", method = RequestMethod.POST) 21 @ResponseBody 22 public AjaxResponse login(String u , String p, HttpSession session){ 23 24 // 封装令牌 25 UsernamePasswordToken token = new UsernamePasswordToken(u,p); 26 Subject subject = null; 27 try { 28 subject = SecurityUtils.getSubject(); 29 // 用令牌登陆,如果登陆失败,则抛出异常 30 subject.login(token); 31 token.clear(); 32 } catch (AccountNotExistException ex) { 33 return ACCOUNT_NOT_EXIST; 34 } catch (PasswordWrongException ex) { 35 return PASSWORD_NOT_PASSED; 36 } 37 catch (AccountLockedException ex) { 38 return ACCOUNT_LOCKED; 39 } 40 catch (Exception ex) { 41 log.error("login error happend.", ex); 42 return SYSTEM_BUSY; 43 } 44 45 Customer c = customerService.getBaseCustomer(u); 46 47 // 保存会话 48 session.setAttribute(Const.SESSION_SUBJECT, subject); // shiro已登录用户 49 session.setAttribute(Const.SESSION_USER_KEY,c );// 登陆用户 50 return AjaxResponse.OK; 51 52 } 53 }
UsernamePasswordToken源码:
package org.apache.shiro.authc; /** * Constructs a new UsernamePasswordToken encapsulating the username and password submitted * during an authentication attempt, with a <tt>null</tt> {@link #getHost() host} and a * <tt>rememberMe</tt> default of <tt>false</tt>. * * @param username the username submitted for authentication * @param password the password character array submitted for authentication */ public UsernamePasswordToken(final String username, final char[] password) { this(username, password, false, null); } /** * Constructs a new UsernamePasswordToken encapsulating the username and password submitted * during an authentication attempt, with a <tt>null</tt> {@link #getHost() host} and * a <tt>rememberMe</tt> default of <tt>false</tt> * <p/> * <p>This is a convience constructor and maintains the password internally via a character * array, i.e. <tt>password.toCharArray();</tt>. Note that storing a password as a String * in your code could have possible security implications as noted in the class JavaDoc.</p> * * @param username the username submitted for authentication * @param password the password string submitted for authentication */ public UsernamePasswordToken(final String username, final String password) { this(username, password != null ? password.toCharArray() : null, false, null); }
getSubject()源码:
1 package org.apache.shiro; 2 3 import org.apache.shiro.mgt.SecurityManager; 4 import org.apache.shiro.subject.Subject; 5 import org.apache.shiro.util.ThreadContext; 6 7 8 /** 9 * Accesses the currently accessible {@code Subject} for the calling code depending on runtime environment. 10 * 11 * @since 0.2 12 */ 13 public abstract class SecurityUtils { 14 15 /** 16 * ONLY used as a 'backup' in VM Singleton environments (that is, standalone environments), since the 17 * ThreadContext should always be the primary source for Subject instances when possible. 18 */ 19 private static SecurityManager securityManager; 20 21 /** 22 * Returns the currently accessible {@code Subject} available to the calling code depending on 23 * runtime environment. 24 * <p/> 25 * This method is provided as a way of obtaining a {@code Subject} without having to resort to 26 * implementation-specific methods. It also allows the Shiro team to change the underlying implementation of 27 * this method in the future depending on requirements/updates without affecting your code that uses it. 28 * 29 * @return the currently accessible {@code Subject} accessible to the calling code. 30 * @throws IllegalStateException if no {@link Subject Subject} instance or 31 * {@link SecurityManager SecurityManager} instance is available with which to obtain 32 * a {@code Subject}, which which is considered an invalid application configuration 33 * - a Subject should <em>always</em> be available to the caller. 34 */ 35 public static Subject getSubject() { 36 Subject subject = ThreadContext.getSubject(); 37 if (subject == null) { 38 subject = (new Subject.Builder()).buildSubject(); 39 ThreadContext.bind(subject); 40 } 41 return subject; 42 } 43 }
login源码:
1 /** 2 * Performs a login attempt for this Subject/user. If unsuccessful, 3 * an {@link AuthenticationException} is thrown, the subclass of which identifies why the attempt failed. 4 * If successful, the account data associated with the submitted principals/credentials will be 5 * associated with this {@code Subject} and the method will return quietly. 6 * <p/> 7 * Upon returning quietly, this {@code Subject} instance can be considered 8 * authenticated and {@link #getPrincipal() getPrincipal()} will be non-null and 9 * {@link #isAuthenticated() isAuthenticated()} will be {@code true}. 10 * 11 * @param token the token encapsulating the subject's principals and credentials to be passed to the 12 * Authentication subsystem for verification. 13 * @throws org.apache.shiro.authc.AuthenticationException 14 * if the authentication attempt fails. 15 * @since 0.9 16 */ 17 void login(AuthenticationToken token) throws AuthenticationException;
clear源码:
1 /*-------------------------------------------- 2 | M E T H O D S | 3 ============================================*/ 4 5 /** 6 * Clears out (nulls) the username, password, rememberMe, and inetAddress. The password bytes are explicitly set to 7 * <tt>0x00</tt> before nulling to eliminate the possibility of memory access at a later time. 8 */ 9 public void clear() { 10 this.username = null; 11 this.host = null; 12 this.rememberMe = false; 13 14 if (this.password != null) { 15 for (int i = 0; i < password.length; i++) { 16 this.password[i] = 0x00; 17 } 18 this.password = null; 19 } 20 21 }
四个异常类,此时产生一个疑问,怎么验证数据那,此时需要一个配置我文件spring-shiro:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee" 4 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" 7 default-lazy-init="true"> 8 9 <!-- 安全管理器 --> 10 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> 11 <property name="realm" ref="shiroDBRealm" /> 12 <!--<property name="cacheManager" ref="cacheManager" />--> 13 </bean> 14 <!--<bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />--> 15 16 <!-- shiro过滤器 --> 17 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 18 <property name="securityManager" ref="securityManager" /> 19 <property name="loginUrl" value="/login.action" /> 20 <property name="successUrl" value="/welcome.action" /> 21 <property name="unauthorizedUrl" value="/login.action" /> 22 <property name="filterChainDefinitions"> 23 <value> 24 </value> 25 </property> 26 </bean> 27 <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> 28 29 <!-- 验证数据类 --> 30 <bean id="shiroDBRealm" class="com.petcare.admin.security.shiro.ShiroDBRealm" /> 31 32 </beans>
类shiroDBRealm:
1 /** 2 * Specl.com Inc. 3 * Copyright (c) 2010-2011 All Rights Reserved. 4 */ 5 package com.petcare.admin.security.shiro; 6 7 import com.petcare.admin.service.CustomerService; 8 import com.petcare.pojo.base.Customer; 9 import org.apache.commons.lang.StringUtils; 10 import org.apache.shiro.authc.*; 11 import org.apache.shiro.authz.AuthorizationInfo; 12 import org.apache.shiro.authz.SimpleAuthorizationInfo; 13 import org.apache.shiro.realm.AuthorizingRealm; 14 import org.apache.shiro.subject.PrincipalCollection; 15 import org.slf4j.Logger; 16 import org.slf4j.LoggerFactory; 17 18 import javax.annotation.Resource; 19 20 21 22 /** 23 * 权限数据访问类。 24 * 25 * 26 */ 27 public class ShiroDBRealm extends AuthorizingRealm { 28 29 private Logger log = LoggerFactory.getLogger(this.getClass()); 30 31 /** 32 * 账号访问层。 33 */ 34 @Resource 35 private CustomerService customerService; 36 37 /** 38 * 认证方法。 39 */ 40 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { 41 42 log.debug("do authentication ,token data [{}]", authcToken); 43 44 UsernamePasswordToken token = (UsernamePasswordToken) authcToken; 45 46 if (token.getUsername() == null) { 47 return null; 48 } 49 50 // 根据账户名获得账户 51 Customer customer = customerService.getBaseCustomer(token.getUsername()); 52 53 // 当账号密码不存在 54 if (customer == null) { 55 log.debug("customer not exist."); 56 throw new AccountNotExistException(); 57 } 58 59 // 当密码错误 60 if (!StringUtils.equals(customer.getPasswd(), new String(token.getPassword()))) { 61 log.debug("password not equals."); 62 throw new PasswordWrongException(); 63 } 64 65 // if(customer.getIsDelete()==1) { 66 // log.debug("customer is locked."); 67 // throw new AccountLockedException(); 68 // } 69 return new SimpleAuthenticationInfo(customer.getAccount(), customer.getPasswd(), getName()); 70 } 71 72 /** 73 * 授权方法。 74 */ 75 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 76 77 log.debug("do authortization , principals data [{}]", principals); 78 79 // String username = (String) principals.fromRealm(getName()).iterator().next(); 80 // 81 // // 根据账户名获得账户 82 // CustomerAccount account = customerAccountDao.getAccountByUsername(username); 83 // 84 // if (account == null) { 85 // log.debug("account not exist."); 86 // throw new AccountNotExistException(); 87 // } 88 89 // 封装授权信息 90 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 91 // 将用户的角色字符,进行授权 92 // info.addRoles(account.getRoleStringList()); 93 // 将用户的权限字符,进行授权 94 // info.addStringPermissions(account.getPermissionStringList()); 95 return info; 96 } 97 }
web.xml:
有待修改:
1 <!-- listeners --> 2 <listener> 3 <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> 4 </listener> 5 <listener> 6 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 7 </listener> 8 9 10 <!-- shiro,find spring bean by filter name is 'shiroFilter' --> 11 <filter> 12 <filter-name>shiroFilter</filter-name> 13 <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 14 <init-param> 15 <param-name>targetFilterLifecycle</param-name> 16 <param-value>true</param-value> 17 </init-param> 18 </filter>