zoukankan      html  css  js  c++  java
  • shiro+密码匹配器验证登陆

    1.先上工具类MD5Util   目前真正用到的是直接MD5加密的方法   未使用自定义加工密码加密

    package cn.cjq.util;

    import cn.cjq.entity.User;

    import java.security.MessageDigest;
    import java.util.Random;

    public class MD5Util {

    /**
    * 加工密码,和登录一致。
    * @param user
    * @return
    */
    public static User md5Pswd(User user){
    //密码为 username + '#' + password,然后MD5
    user.setPassword(md5Pswd(user.getUsername(),user.getPassword()));
    return user;
    }
    /**
    * 字符串返回值
    * @param email
    * @param pswd
    * @return
    */
    public static String md5Pswd(String email ,String pswd){
    pswd = String.format("%s#%s", email,pswd);
    pswd = getMD5(pswd);
    return pswd;
    }


    /**
    * MD5 加密
    * @param str
    * @return
    * @throws Exception
    */
    public static String getMD5(String str) {
    MessageDigest messageDigest = null;
    try {
    messageDigest = MessageDigest.getInstance("MD5");
    messageDigest.reset();
    messageDigest.update(str.getBytes("UTF-8"));
    } catch (Exception e) {
    System.out.println("MD5转换异常!message:%s"+e.getMessage());
    }

    byte[] byteArray = messageDigest.digest();
    StringBuffer md5StrBuff = new StringBuffer();
    for (int i = 0; i < byteArray.length; i++) {
    if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
    md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
    else
    md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
    }
    return md5StrBuff.toString();
    }


    /**
    * 获取随机的数值。
    * @param length 长度
    * @return
    */
    public static String getRandom620(Integer length){
    String result = "";
    Random rand = new Random();
    int n = 20;
    if(null != length && length > 0){
    n = length;
    }
    boolean[] bool = new boolean[n];
    int randInt = 0;
    for(int i = 0; i < length ; i++) {
    do {
    randInt = rand.nextInt(n);

    }while(bool[randInt]);

    bool[randInt] = true;
    result += randInt;
    }
    return result;
    }

    /**
    * 加密解密算法 执行一次加密,两次解密
    */
    public static String convertMD5(String inStr){

    char[] a = inStr.toCharArray();
    for (int i = 0; i < a.length; i++){
    a[i] = (char) (a[i] ^ 't');
    }
    String s = new String(a);
    return s;

    }

    }

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    2.密码加密实例   注册时会使用(只需要将加密的密码存入数据库),传给UsernamePasswordToken的密码参数是未加密的密码,由密码匹配器去自动匹配 

    /**
    * 注册 && 登录
    * @param vcode 验证码
    * @return
    */
    @RequestMapping(value="subRegister")
    @ResponseBody
    @SystemControllerLog(description = "用户注册登陆")
    public Response subRegister(@RequestParam(value="userName",required=false,defaultValue="") String userName,
    @RequestParam(value="passWord",required=false,defaultValue="") String passWord,
    @RequestParam(value="realname",required=false,defaultValue="") String realname,
    @RequestParam(value="userType",required=false,defaultValue="") String userType,
    @RequestParam(value="vcode",required=false,defaultValue="") String vcode)throws Exception{
    //手机号不合法
    if(!isMobileNO(userName)){
    return new Response(ExceptionMsg.UserNameError);
    }
    //用户名已存在
    User user = userServiceImpl.findByUserName(userName);
    if(null != user){
    return new Response(ExceptionMsg.UserNameUsed);
    }
    //验证码错误
    KeyValue data=(KeyValue)stringRedisServiceImpl.get(userName);
    if(data==null){
    return new Response(ExceptionMsg.VcodeNotExists);
    }else if(!data.getValue().equals(vcode)){
    return new Response(ExceptionMsg.VcodeError);
    }
    //把密码md5
    String password = MD5Util.getMD5(passWord);
    //注册
    User newuser =new User();
    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
    newuser.setUerid(uuid);
    newuser.setAddtime(new Date());
    newuser.setCreateperson(uuid);
    newuser.setUsername(userName);
    newuser.setEnditime(new Date());
    newuser.setIsdelete(0);
    newuser.setStatus("1");
    newuser.setPassword(password);
    newuser.setRealname(realname);
    newuser.setPhone(userName);
    newuser.setDifference(1);
    userServiceImpl.insertuser(newuser);
    //登陆验证
    UsernamePasswordToken token = new UsernamePasswordToken(userName,passWord,false);
    SecurityUtils.getSubject().login(token);
    Session sessions = SecurityUtils.getSubject().getSession();
    sessions.setAttribute("user",newuser );
    //清理内存
    stringRedisServiceImpl.remove(userName);
    return new Response(ExceptionMsg.SUCCESS);
    }
    --------------------------------------------------------------------------------------------------------------------------
    3.shiro.xml配置密码匹配器 两个bean 配置在自定义的realm里
    属性hashIterations的值目前为1,代表加密一次,其他值未试过,不明觉厉,待续
    <!-- 凭证匹配器-->
    <bean id="credentialsMatcher" class="cn.cjq.util.shiro.RetryLimitHashedCredentialsMatcher">
    <constructor-arg ref="cacheManager"/>
    <property name="hashAlgorithmName" value="md5"/>
    <property name="hashIterations" value="1"/>
    <property name="storedCredentialsHexEncoded" value="true"/>
    </bean>
    <bean id="myShiroRealm" class="cn.cjq.util.shiro.UserRealm">
    <!-- 配置密码匹配器 -->
    <property name="credentialsMatcher" ref="credentialsMatcher"/>
    <property name="cachingEnabled" value="true"/>
    <property name="authenticationCachingEnabled" value="true"/>
    <property name="authenticationCacheName" value="authenticationCache"/>
    <property name="authorizationCachingEnabled" value="true"/>
    <property name="authorizationCacheName" value="authorizationCache"/>
    </bean>
    --------------------- ----------------------------------------------------------------------------------------------------------------
    4.自定义的密码匹配器 目前使用的md5
    package cn.cjq.util.shiro;

    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 RetryLimitHashedCredentialsMatcher extends
    HashedCredentialsMatcher {
    private Cache<String, AtomicInteger> passwordRetryCache;

    public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
    passwordRetryCache = cacheManager.getCache("passwordRetryCache");
    }

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
    String username = (String)token.getPrincipal();
    //retry count + 1
    AtomicInteger retryCount = passwordRetryCache.get(username);
    if(retryCount == null) {
    retryCount = new AtomicInteger(0);
    passwordRetryCache.put(username, retryCount);
    }
    if(retryCount.incrementAndGet() > 5) {
    //if retry count > 5 throw
    throw new ExcessiveAttemptsException();
    }

    boolean matches = super.doCredentialsMatch(token, info);
    if(matches) {
    //clear retry count
    passwordRetryCache.remove(username);
    }
    return matches;
    }
    }
  • 相关阅读:
    多线程爬取图片(生产者-消费者模式)
    数据结构1_C---单链表的逆转
    Java基础面试知识点总结
    Java工程师必备书单
    Java工程师修炼之路(校招总结)
    Java秋招面经大合集
    我的秋招经验分享(已拿BAT头条网易滴滴)
    听说go语言越来越火了?那么请收下这一份go语言书单吧!
    2020还是AI最火?推荐几本深度学习的书籍帮你入门!
    人工智能真的有那么神秘么,推荐一份机器学习入门书单搞定它!
  • 原文地址:https://www.cnblogs.com/1234cjq/p/8143745.html
Copyright © 2011-2022 走看看