About shiro implementation of rememberme, before then we use the cookie to achieve, here too, the principle is the same;
But because the use of shiro framework, shiro need to configure cookie and cache, as well as manager object:
<! - Security Manager -> < bean the above mentioned id = "securityManager" class = "org.apache.shiro.web.mgt.DefaultWebSecurityManager" > <! - Cache Manager -> < Property name = "CacheManager" REF = "CacheManager" /> <-! mode sessions -> < Property name = "SessionMode" value = "Native" /> <-! configuration the realm -> < Property name = "Realms" REF = " myRealm "/> <property name="rememberMeManager" ref="rememberMeManager"/> </bean> <!--cookie对象--> <bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="rememberMe"/> <!--只有http的连接才使用cookie--> <property name="httpOnly" value="true"/> <!--cookie失效时间--> <property name="maxAge" value="#{60*60*24}"/> </bean> <!--记住我管理器对象--> <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <property name="cookie" ref="simpleCookie"/> </bean>
Controller:
@Controller public class UserController { private static final transient Logger log = LoggerFactory.getLogger(UserController.class); @RequestMapping("/login") public String login(User user,String rememberMe) throws Exception { Subject currentUser = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); //记住我 if (rememberMe != null &&rememberMe.equals("1")) { token.setRememberMe(true); } currentUser.login(token); return "redirect:/home"; } }
Front page:
<form action="../login" method="post"> <input type="text" name="username"> <input type="password" name="password"> <input type="checkbox" name="rememberMe" value="1">记住我 <input type="submit"> </form>
After the configuration, then the configuration file shiro path configuration:
Represents the emp / under request, the user can access and run tomcat, entry form information, I remember, and then log on, the login is successful, close the browser, close the browser at the same time, closed the session, but the cookie contains data , so you can directly access / emp / ** resources under, pro-test: If the problem can not get out Firefox effect, may be set Firefox to automatically clear the cache when you close the browser needs to close:
Repeatedly locked account login
Multiple login lock account: according to the name of this function, we can ideas, we want to log information on where? If you put a cookie, it will refresh every time you log registration data, there is no way the number of log records, records can be cached logins. To do:
1. Configure cache:
<? Xml Version = "1.0" encoding = "UTF-8" ?> < Ehcache name = "es" > < diskStore path = "java.io.tmpdir" /> <-! MaxEntriesLocalHeap: is used to limit the current cache the maximum number of elements in the heap memory can be saved eternal: whether false set of elemen cache never expires timeToLiveSeconds: the survival time of the object, the object refers to the time from creation to fail needs. Only the eternal is false is valid. The default value is 0, which means you can have access. (Unit: seconds) timeToIdleSeconds: When an object is idle, refers to how long the object will fail in not being accessed. Only the eternal is false is valid. The default value is 0. (Unit: seconds) -> <! - the default cache -> < defaultCache maxEntriesLocalHeap = "10000" Eternal = "false"="120" timeToLiveSeconds="120" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"/> <!-- 登录记录缓存 锁定10分钟 --> <cache name="passwordRetryCache" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="360" timeToLiveSeconds="360" overflowToDisk="false" statistics="true"> </cache> <cache name="authorizationCache" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0" overflowToDisk="false" statistics="true"> </cache> <cache name="authenticationCache" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0" overflowToDisk="false" statistics="true"> </cache> <cache name="shiro-activeSessionCache" maxEntriesLocalHeap="2000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0" overflowToDisk="false" statistics="true"> </cache> </ehcache>
2. shiro configuration file, configure the cache path:
3. Customize credentials match, a cache is introduced
package com.zs.credentials; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.ExcessiveAttemptsException; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheManager; import java.util.concurrent.atomic.AtomicInteger; public class MyMatcher extends HashedCredentialsMatcher { //Map:key,value //key:存用户名 value:次数 privateThe Cache <String, of AtomicInteger> passwordCache; public MyMatcher (the CacheManager CacheManager) { the this .passwordCache = cacheManager.getCache ( "passwordRetryCache" ); } // password matches @Override public Boolean doCredentialsMatch (AuthenticationToken token, AuthenticationInfo info) { // get the user name String username = (String) token.getPrincipal (); // Find the cache if there is to go to the information AtomicInteger retryCount = passwordCache.get (username); // the first time was null iF (retryCount == null ) { // Initial words: 0 retryCount = new new of AtomicInteger (0 ); // cached in passwordCache.put (username, retryCount); } @ increase in retryCount 1, and acquires the value IF (retryCount.incrementAndGet ()> . 3 ) { the throw new new ExcessiveAttemptsException ( "the account is locked" ); } // password matches Boolean Matcher = Super .doCredentialsMatch (token, info); // If the login is successful IF (Matcher) { // empty the cache data passwordCache.remove (username); } return Matcher ; } }
The certificate matcher disposed, and the introduction of the cache:
Then run logon test: three incorrect password, login, reported abnormal account locked:
Exception class:
package com.zs.controller; import com.zs.entity.Result; import org.apache.shiro.authc.AccountException; import org.apache.shiro.authc.ExcessiveAttemptsException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; @ControllerAdvice public class ExceptionController { @ExceptionHandler(Exception.class) @ResponseBody public Result error(Exception ex, Model model) { Result result = new Result(); if (ex instanceof AccountException) { if (ex instanceof ExcessiveAttemptsException) { result.setMessages("账户锁定"); } else { result.setStats(501); result.setMessages("账号错误"); } } else if (ex instanceof IncorrectCredentialsException) { result.setStats(502); result.setMessages("密码错误"); } else { result.setStats(503); result.setMessages("数据错误"); } return result; } }
运行结果: