天天看點

shiro的使用2 靈活使用shiro的密碼服務子產品

shiro的使用2 靈活使用shiro的密碼服務子產品

package com.util; 

import com.domain.User; 

import com.google.common.base.Preconditions; 

import com.google.common.base.Strings; 

import com.sun.crypto.provider.AESKeyGenerator; 

import org.apache.shiro.codec.Base64; 

import org.apache.shiro.codec.CodecSupport; 

import org.apache.shiro.codec.H64; 

import org.apache.shiro.codec.Hex; 

import org.apache.shiro.crypto.AesCipherService; 

import org.apache.shiro.crypto.SecureRandomNumberGenerator; 

import org.apache.shiro.crypto.hash.Md5Hash; 

import java.security.Key; 

/** 

* User: cutter.li 

* Date: 2014/6/27 0027 

* Time: 16:49 

* 備注: shiro進行加密解密的工具類封裝 

*/ 

public final class EndecryptUtils { 

    /** 

     * base64進制加密 

     * 

     * @param password 

     * @return 

     */ 

    public static String encrytBase64(String password) { 

        Preconditions.checkArgument(!Strings.isNullOrEmpty(password), "不能為空"); 

        byte[] bytes = password.getBytes(); 

        return Base64.encodeToString(bytes); 

    } 

     * base64進制解密 

     * @param cipherText 

    public static String decryptBase64(String cipherText) { 

        Preconditions.checkArgument(!Strings.isNullOrEmpty(cipherText), "消息摘要不能為空"); 

        return Base64.decodeToString(cipherText); 

     * 16進制加密 

    public static String encrytHex(String password) { 

        return Hex.encodeToString(bytes); 

     * 16進制解密 

    public static String decryptHex(String cipherText) { 

        return new String(Hex.decode(cipherText)); 

    public static String generateKey() 

    { 

        AesCipherService aesCipherService=new AesCipherService(); 

        Key key=aesCipherService.generateNewKey(); 

        return Base64.encodeToString(key.getEncoded()); 

     * 對密碼進行md5加密,并傳回密文和salt,包含在User對象中 

     * @param username 使用者名 

     * @param password 密碼 

     * @return 密文和salt 

    public static User md5Password(String username,String password){ 

        Preconditions.checkArgument(!Strings.isNullOrEmpty(username),"username不能為空"); 

        Preconditions.checkArgument(!Strings.isNullOrEmpty(password),"password不能為空"); 

        SecureRandomNumberGenerator secureRandomNumberGenerator=new SecureRandomNumberGenerator(); 

        String salt= secureRandomNumberGenerator.nextBytes().toHex(); 

        //組合username,兩次疊代,對密碼進行加密 

        String password_cipherText= new Md5Hash(password,username+salt,2).toBase64(); 

        User user=new User(); 

        user.setPassword(password_cipherText); 

        user.setSalt(salt); 

        user.setUsername(username); 

        return user; 

    public static void main(String[] args) { 

        String password = "admin"; 

        String cipherText = encrytHex(password); 

        System.out.println(password + "hex加密之後的密文是:" + cipherText); 

        String decrptPassword=decryptHex(cipherText); 

        System.out.println(cipherText + "hex解密之後的密碼是:" + decrptPassword); 

        String cipherText_base64 = encrytBase64(password); 

        System.out.println(password + "base64加密之後的密文是:" + cipherText_base64); 

        String decrptPassword_base64=decryptBase64(cipherText_base64); 

        System.out.println(cipherText_base64 + "base64解密之後的密碼是:" + decrptPassword_base64); 

        String h64=  H64.encodeToString(password.getBytes()); 

        System.out.println(h64); 

        String salt="7road"; 

        String cipherText_md5= new Md5Hash(password,salt,4).toHex(); 

        System.out.println(password+"通過md5加密之後的密文是:"+cipherText_md5); 

        System.out.println(generateKey()); 

        System.out.println("=========================================================="); 

        aesCipherService.setKeySize(128); 

        String aes_cipherText= aesCipherService.encrypt(password.getBytes(),key.getEncoded()).toHex(); 

        System.out.println(password+" aes加密的密文是:"+aes_cipherText); 

        String aes_mingwen=new String(aesCipherService.decrypt(Hex.decode(aes_cipherText),key.getEncoded()).getBytes()); 

        System.out.println(aes_cipherText+" aes解密的明文是:"+aes_mingwen); 

}

package com.util.cache; 

import net.sf.ehcache.Cache; 

import net.sf.ehcache.CacheManager; 

import net.sf.ehcache.Element; 

import net.sf.ehcache.config.CacheConfiguration; 

import net.sf.ehcache.store.MemoryStoreEvictionPolicy; 

* Date: 2014/6/30 0030 

* Time: 15:32 

* 備注: ehcache的緩存工具類 

public final class EhcacheUtil { 

    private static final CacheManager cacheManager = CacheManager.getInstance(); 

     * 建立ehcache緩存,建立之後的有效期是1小時 

   private static Cache cache = new Cache(new CacheConfiguration("systemCache", 5000).memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.FIFO).timeoutMillis(300).timeToLiveSeconds( 60 * 60)); 

    static { 

        cacheManager.addCache(cache); 

    public static void putItem(String key, Object item) { 

        if (cache.get(key) != null) { 

            cache.remove(key); 

        } 

        Element element = new Element(key, item); 

        cache.put(element); 

    public static void removeItem(String key) { 

        cache.remove(key); 

    public static void updateItem(String key, Object value) { 

        putItem(key, value); 

    public static Object getItem(String key) { 

        Element element=  cache.get(key); 

        if(null!=element) 

        { 

            return element.getObjectValue(); 

        return null; 

        String password_cipherText= new Md5Hash(password,username+salt,2).toHex(); 

     * 通過username,password,salt,校驗密文是否比對 ,校驗規則其實在配置檔案中,這裡為了清晰,寫下來 

     * @param password 原密碼 

     * @param salt  鹽 

     * @param md5cipherText 密文 

    public static  boolean checkMd5Password(String username,String password,String salt,String md5cipherText) 

        Preconditions.checkArgument(!Strings.isNullOrEmpty(md5cipherText),"md5cipherText不能為空"); 

        String password_cipherText= new Md5Hash(password,username+salt,2).toHex(); 

        return md5cipherText.equals(password_cipherText); 

    }

   <bean id="myRealm" class="com.util.MysqlJdbcRealM"> 

        <property name="credentialsMatcher" ref="passwordMatcher"></property> 

    </bean> 

    <bean id="passwordMatcher" class="com.util.LimitRetryHashedMatcher"> 

   <property name="hashAlgorithmName" value="md5"></property> 

        <property name="hashIterations" value="2"></property> 

        <property name="storedCredentialsHexEncoded" value="true"></property> 

    </bean>

  /** 

     * 使用者注冊 

     * @param entity 

    @Override 

    public ResponseEntity<Map> createSubmit(User entity) { 

        //加密使用者輸入的密碼,得到密碼的摘要和鹽,儲存到資料庫 

      User user = EndecryptUtils.md5Password(entity.getUsername(), entity.getPassword()); 

        entity.setPassword(user.getPassword()); 

        entity.setSalt(user.getSalt()); 

        Map<String, Object> map = Maps.newHashMap(); 

        try { 

            boolean createResult = service.modify(entity, OperationType.create); 

            map.put("success", createResult); 

        } catch (Exception e) { 

            e.printStackTrace(); 

        return new ResponseEntity<Map>(map, HttpStatus.OK); 

------------------------------------------------------------------華麗的分割線--------------------------------------------------------------------------------------------------- 

  @RequestMapping(value = "login", method = RequestMethod.POST) 

    public ResponseEntity<Message> loginSubmit(String username, String password, String vcode, HttpServletRequest request) { 

        message.setSuccess(); 

        validateLogin(message, username, password, vcode); 

//            String code = request.getSession().getAttribute(AppConstant.KAPTCHA_SESSION_KEY).toString(); 

//            if (!vcode.equalsIgnoreCase(code)) { 

//                message.setCode(AppConstant.VALIDCODE_ERROR); 

//                message.setMsg("驗證碼錯誤"); 

//            } 

            if (message.isSuccess()) { 

                Subject subject = SecurityUtils.getSubject(); 

                subject.login(new UsernamePasswordToken(username, password,false)); 

                if (subject.isAuthenticated()) { 

                        message.setMsg("登入成功"); 

                } else { 

                    message.setCode(AppConstant.USERNAME_NOTEXIST); 

                    message.setMsg("使用者名/密碼錯誤"); 

                } 

            } 

        }catch (ExcessiveAttemptsException ex) 

            message.setCode(AppConstant.USERNAME_NOTEXIST); 

            message.setMsg("帳号被鎖定1小時"); 

            ex.printStackTrace(); 

        catch (AuthenticationException ex){ 

            message.setMsg("使用者名/密碼錯誤"); 

        finally { 

            return new ResponseEntity<Message>(message, HttpStatus.OK); 

---------------------------------------------------------------認證的修改------------------------------------------------------------------------------------- 

    //登入認證 

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 

        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; 

        String username = String.valueOf(usernamePasswordToken.getUsername()); 

        User user = userService.findByUserName(username); 

        SimpleAuthenticationInfo authenticationInfo = null; 

        if (null != user) { 

            String password = new String(usernamePasswordToken.getPassword()); 

//密碼校驗移交給了shiro的提供的一個接口實作類,是以這裡注釋掉 

//            if (EndecryptUtils.checkMd5Password(username,password,user.getSalt(),user.getPassword())) { 

                authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName()); 

                authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(username+user.getSalt())); 

        return authenticationInfo; 

5,重寫密碼校驗的方法

import com.util.cache.EhcacheUtil; 

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 java.util.concurrent.atomic.AtomicInteger; 

* Time: 15:22 

* 備注: 限制登入次數,如果5次出錯,鎖定1個小時 

public class LimitRetryHashedMatcher extends HashedCredentialsMatcher { 

    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { 

        String username = (String) token.getPrincipal(); 

//retrycount + 1 

        Object element = EhcacheUtil.getItem(username); 

        if (element == null) { 

            EhcacheUtil.putItem(username, 1); 

            element=0; 

        }else{ 

            int count=Integer.parseInt(element.toString())+1; 

            element=count; 

            EhcacheUtil.putItem(username,element); 

        AtomicInteger retryCount = new AtomicInteger(Integer.parseInt(element.toString())); 

        if (retryCount.incrementAndGet() > 5) { 

//if retrycount >5 throw 

            throw new ExcessiveAttemptsException(); 

        boolean matches = super.doCredentialsMatch(token, info); 

        if (matches) { 

//clear retrycount 

            EhcacheUtil.removeItem(username); 

        return matches; 

連續輸錯5次密碼之後,出現如下提示;

shiro的使用2 靈活使用shiro的密碼服務子產品

通過封裝常用的加密解密工具類,降低了對jdk自帶密碼工具類的學習成本;

可以靈活定義密碼的生成和判斷方式,并改變密碼判斷過程的邏輯;

no pays,no gains!

來源:http://www.cnblogs.com/snidget/p/3817763.html