使用shiro实现多Realm认证——用户名密码、手机短信验证

为了在网欲音乐系统中实现登入功能,在此使用到了shiro这个安全框架,从而使用到了多Realm认证——用户名密码、手机短信验证。特整理这篇文章希望能让后来者少踩一点坑。

本篇文章环境:SpringBoot 2.0 + shiro+ redis
使用阿里云手机号发送短信验证码

效果展示

  • 用户名密码登入

在这里插入图片描述

  • 手机短语登入

在这里插入图片描述

核心代码刨析

1、用户密码登录realm

package com.music.system.shiro.realm;

import com.music.model.User;
import com.music.service.impl.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 用户密码登录realm
 */
@Slf4j
public class UserPasswordRealm extends AuthorizingRealm {
    
    
    @Autowired
    private UserService userService;


    @Override
    public String getName() {
    
    
        return LoginType.USER_PASSWORD.getType();
    }

    @Override
    public boolean supports(AuthenticationToken token) {
    
    
        if (token instanceof UserToken) {
    
    
            return ((UserToken) token).getLoginType() == LoginType.USER_PASSWORD;
        } else {
    
    
            return false;
        }
    }

    @Override
    public void setAuthorizationCacheName(String authorizationCacheName) {
    
    
        super.setAuthorizationCacheName(authorizationCacheName);
    }

    @Override
    protected void clearCachedAuthorizationInfo(PrincipalCollection principals) {
    
    
        super.clearCachedAuthorizationInfo(principals);
    }

    /**
     * 认证信息.(身份验证) : Authentication 是用来验证用户身份
     *
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
    
    
        log.info("---------------- 用户密码登录 ----------------------");
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        String name = token.getUsername();
        // 从数据库获取对应用户名密码的用户
        User user = userService.findUserByName(name);
        if (user != null) {
    
    
            // 用户为禁用状态
            if (!user.getShow()) {
    
    
                throw new DisabledAccountException();
            }
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    user, //用户
                    user.getPassword(), //密码
                    getName()  //realm name
            );
            return authenticationInfo;
        }
        throw new UnknownAccountException();
    }

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    
    
        return null;
    }
}

2、手机验证码登录realm

package com.music.system.shiro.realm;


import com.music.model.User;
import com.music.service.impl.UserService;
import com.music.utils.JedisClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;

/**
 * 手机验证码登录realm
 */
@Slf4j
public class UserPhoneRealm extends AuthorizingRealm {
    
    

    @Autowired
    private UserService userService;
    @Resource
    JedisClient jedisClient;

    @Override
    public String getName() {
    
    
        return LoginType.USER_PHONE.getType();
    }

    @Override
    public boolean supports(AuthenticationToken token) {
    
    
        if (token instanceof UserToken) {
    
    
            return ((UserToken) token).getLoginType() == LoginType.USER_PHONE;
        } else {
    
    
            return false;
        }
    }


    @Override
    public void setAuthorizationCacheName(String authorizationCacheName) {
    
    
        super.setAuthorizationCacheName(authorizationCacheName);
    }

    @Override
    protected void clearCachedAuthorizationInfo(PrincipalCollection principals) {
    
    
        super.clearCachedAuthorizationInfo(principals);
    }

    /**
     * 认证信息.(身份验证) : Authentication 是用来验证用户身份
     *
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
    
    
        log.info("---------------- 手机验证码登录 ----------------------");
        UserToken token = (UserToken) authcToken;
        String phone = token.getUsername();
        // 手机验证码
        String validCode = String.valueOf(token.getPassword());
        System.out.println("validCode------>"+validCode);
        // 这里从redis中获取了验证码为 123456,并对比密码是否正确
        String redisCode = jedisClient.get(phone+"code");
        System.out.println("redisCode------>"+redisCode);
        //线上用redisCode取代123456
        if(!"123456".equals(validCode)){
    
    
            log.debug("验证码错误,手机号为:{}", phone);
            throw new IncorrectCredentialsException();
        }

        User user = userService.findUserByPhone(phone);
        if(user == null){
    
    
            throw new UnknownAccountException();
        }
        // 用户为禁用状态
        if(!user.getShow()){
    
    
            throw new DisabledAccountException();
        }

        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user, //用户
                validCode, //密码
                getName()  //realm name
        );
        return authenticationInfo;
    }

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
    
        return null;
    }

}

ShiroConfig

package com.music.system.config;

import com.music.system.shiro.CredentialsMatcher;
import com.music.system.shiro.MyModularRealmAuthenticator;
import com.music.system.shiro.SessionManager;
import com.music.system.shiro.filter.AuthcShiroFilter;
import com.music.system.shiro.filter.SessionControlFilter;
import com.music.system.shiro.realm.AuthorizationRealm;
import com.music.system.shiro.realm.LoginType;
import com.music.system.shiro.realm.UserPasswordRealm;
import com.music.system.shiro.realm.UserPhoneRealm;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Configuration
public class ShiroConfig {
    
    

    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.port}")
    private int redisPort;

    @Value("${spring.redis.password}")
    private String redisPassword;
    @Value("${spring.redis.database}")
    private int database;

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
    
    
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 由于已经重写了authc的拦截器,此处设置的loginUrl和unauthorizedUrl已经没有用了
        // 没有登陆的用户只能访问登陆页面,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
        //shiroFilterFactoryBean.setLoginUrl("/common/unauth");
        // 登录成功后要跳转的链接
        //shiroFilterFactoryBean.setSuccessUrl("/auth/index");
        // 未授权界面;
        //shiroFilterFactoryBean.setUnauthorizedUrl("common/unauth");

        //自定义拦截器
        Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
        //自定义authc访问拦截器
        filtersMap.put("authc", new AuthcShiroFilter());
        //限制同一帐号同时在线的个数。
        filtersMap.put("kickout", kickoutSessionControlFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);

        // 权限控制map.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 公共请求
        filterChainDefinitionMap.put("/common/**", "anon");
        // 静态资源
        filterChainDefinitionMap.put("/static/**", "anon");
        // 登录方法
        filterChainDefinitionMap.put("/admin/*ogin*", "anon"); // 表示可以匿名访问
        filterChainDefinitionMap.put("/admin/sentCode", "anon"); // 表示可以匿名访问
        filterChainDefinitionMap.put("/admin/query", "anon"); // 表示可以匿名访问

        //此处需要添加一个kickout,上面添加的自定义拦截器才能生效
        filterChainDefinitionMap.put("/admin/**", "authc,kickout");// 表示需要认证才可以访问
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * SecurityManager 是 Shiro 架构的核心,通过它来链接Realm和用户(文档中称之为Subject.)
     */
    @Bean
    public SecurityManager securityManager() {
    
    
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setAuthenticator(modularRealmAuthenticator());

        List<Realm> realms = new ArrayList<>();
        // 统一角色权限控制realm
        realms.add(authorizingRealm());
        // 用户密码登录realm
        realms.add(userPasswordRealm());
        // 用户手机号验证码登录realm
        realms.add(userPhoneRealm());

        securityManager.setRealms(realms);
        // 自定义缓存实现 使用redis
        securityManager.setCacheManager(cacheManager());
        // 自定义session管理 使用redis
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    /**
     * 自定义的Realm管理,主要针对多realm
     */
    @Bean("myModularRealmAuthenticator")
    public MyModularRealmAuthenticator modularRealmAuthenticator() {
    
    
        MyModularRealmAuthenticator customizedModularRealmAuthenticator = new MyModularRealmAuthenticator();
        // 设置realm判断条件
        customizedModularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());

        return customizedModularRealmAuthenticator;
    }

    @Bean
    public AuthorizingRealm authorizingRealm(){
    
    
        AuthorizationRealm authorizationRealm = new AuthorizationRealm();
        authorizationRealm.setName(LoginType.COMMON.getType());

        return authorizationRealm;
    }
    /**
     * 密码登录realm
     *
     * @return
     */
    @Bean
    public UserPasswordRealm userPasswordRealm() {
    
    
        UserPasswordRealm userPasswordRealm = new UserPasswordRealm();
        userPasswordRealm.setName(LoginType.USER_PASSWORD.getType());
        // 自定义的密码校验器
        userPasswordRealm.setCredentialsMatcher(credentialsMatcher());
        return userPasswordRealm;
    }


    /**
     * 手机号验证码登录realm
     * @return
     */
    @Bean
    public UserPhoneRealm userPhoneRealm(){
    
    
        UserPhoneRealm userPhoneRealm = new UserPhoneRealm();
        userPhoneRealm.setName(LoginType.USER_PHONE.getType());

        return userPhoneRealm;
    }

    @Bean
    public CredentialsMatcher credentialsMatcher() {
    
    
        return new CredentialsMatcher();
    }

    /**
     * cacheManager 缓存 redis实现
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    public RedisCacheManager cacheManager() {
    
    
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        //redis中针对不同用户缓存(此处的id需要对应user实体中的id字段,用于唯一标识)
        redisCacheManager.setPrincipalIdFieldName("id");
        redisCacheManager.setKeyPrefix("SPRINGBOOT_CACHE:");   //设置前缀
        return redisCacheManager;
    }

    /**
     * RedisSessionDAO shiro sessionDao层的实现 通过redis
     * 使用的是shiro-redis开源插件
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
    
    
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        redisSessionDAO.setKeyPrefix("SPRINGBOOT_SESSION:");
        return redisSessionDAO;
    }

    /**
     * Session Manager
     * 使用的是shiro-redis开源插件
     */
    @Bean
    public SessionManager sessionManager() {
    
    
        SimpleCookie simpleCookie = new SimpleCookie("Token");
        simpleCookie.setPath("/");
        simpleCookie.setHttpOnly(false);

        SessionManager sessionManager = new SessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        sessionManager.setSessionIdCookieEnabled(false);
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionIdCookie(simpleCookie);
        return sessionManager;
    }


    /**
     * 配置shiro redisManager
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    public RedisManager redisManager() {
    
    
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(redisHost);
        redisManager.setPort(redisPort);
        redisManager.setTimeout(1800); //设置过期时间
        redisManager.setPassword(redisPassword);
        redisManager.setDatabase(database);
        return redisManager;
    }

    /**
     * 限制同一账号登录同时登录人数控制
     *
     * @return
     */
    // 这里的@Bean不要启用了,自定义的filter不要交由Spring创建,否则会出现被标记为anon的url仍然会执行该自定义过滤器。 updated 2020.06.05
    //@Bean
    public SessionControlFilter kickoutSessionControlFilter() {
    
    
        SessionControlFilter kickoutSessionControlFilter = new SessionControlFilter();
        kickoutSessionControlFilter.setCache(cacheManager());
        kickoutSessionControlFilter.setSessionManager(sessionManager());
        kickoutSessionControlFilter.setKickoutAfter(false);
        kickoutSessionControlFilter.setMaxSession(1);
        kickoutSessionControlFilter.setKickoutUrl("/common/kickout");
        return kickoutSessionControlFilter;
    }

    /***
     * 授权所用配置
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
    
    
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /***
     * 使授权注解起作用不如不想配置可以在pom文件中加入
     * <dependency>
     *<groupId>org.springframework.boot</groupId>
     *<artifactId>spring-boot-starter-aop</artifactId>
     *</dependency>
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
    
    
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * Shiro生命周期处理器
     * 此方法需要用static作为修饰词,否则无法通过@Value()注解的方式获取配置文件的值
     *
     */
    @Bean
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
    
    
        return new LifecycleBeanPostProcessor();
    }
}

LoginType文件

package com.music.system.shiro.realm;

public enum LoginType {
    
    
    /**
     * 通用
     */
    COMMON("common_realm"),
    /**
     * 用户密码登录
     */
    USER_PASSWORD("user_password_realm"),
    /**
     * 手机验证码登录
     */
    USER_PHONE("user_phone_realm"),
    /**
     * 第三方登录(微信登录)
     */
    WECHAT_LOGIN("wechat_login_realm");

    private String type;

    private LoginType(String type) {
    
    
        this.type = type;
    }

    public String getType() {
    
    
        return type;
    }

    @Override
    public String toString() {
    
    
        return this.type.toString();
    }
}

LoginController

/*
  Created by IntelliJ IDEA.
  User: Kalvin
  Date: 2020/10/26
  Time: 12:29
*/
package com.music.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.music.model.User;
import com.music.service.IUserService;
import com.music.service.impl.UserService;
import com.music.system.enums.ResultStatusCode;
import com.music.system.shiro.realm.LoginType;
import com.music.system.shiro.realm.UserToken;
import com.music.system.vo.Result;
import com.music.utils.JedisClient;
import com.music.utils.OptionalLog;
import com.music.utils.PhoneCode;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;

import static com.music.system.shiro.realm.LoginType.USER_PASSWORD;
import static com.music.system.shiro.realm.LoginType.USER_PHONE;

@CrossOrigin
@RestController
@RequestMapping("admin")
public class LoginController {
    
    
    @Autowired
    private UserService userService;
    @Resource
    JedisClient jedisClient;
    /**
     * 用户密码登录
     */
    @RequestMapping("/login")
    public Result login(HttpServletRequest request){
    
    
        String loginName = request.getParameter("name");
        String password = request.getParameter("password");
        request.getSession().setAttribute("loginName",loginName);
        System.out.println("我是登录页的"+request.getSession().getAttribute("loginName"));
        System.out.println(loginName+"---->"+password);
        UserToken token = new UserToken(LoginType.USER_PASSWORD, loginName, password);
        return shiroLogin(token,LoginType.USER_PASSWORD);
    }



    /**
     * 用户点击获取验证码请求
     * */
    @RequestMapping("/sentCode")
    public Result sentCode(@RequestBody Map map){
    
    
        String phone = (String)map.get("phone");
        System.out.println("phone----->"+phone);
       // PhoneCode.getPhonemsg(phone,jedisClient);         //上线打开注释
        return new Result(1);
    }

    /**
     * 手机验证码登录
     */
    @RequestMapping("/loginByPhone")
    public Result loginByPhone(@RequestBody Map map){
    
    
        String phone = (String)map.get("phone");
        String code = (String)map.get("code");
        System.out.println(phone+"---->"+code);
        UserToken token = new UserToken(LoginType.USER_PHONE, phone, code);
        System.out.println("token---->"+token);
        return shiroLogin(token,LoginType.USER_PHONE);
    }
    


    @OptionalLog(modules="操作日志", methods="查询操作日志")
    @RequestMapping("/query")
    public void listLogInfo(){
    
    
        System.out.println("我进入来了。。。。");
    }

    public Result shiroLogin(UserToken token,LoginType loginType){
    
    
        User user = null;
        String userName = null;
        String phone = null;
        try {
    
    
            //登录不在该处处理,交由shiro处理
            Subject subject = SecurityUtils.getSubject();
            System.out.println("subject-------->"+subject);
            if(LoginType.USER_PASSWORD.equals(loginType)){
    
    
                userName = token.getUsername();
                user = userService.findUserByName(userName);
            }else if(LoginType.USER_PHONE.equals(loginType)){
    
    
                phone = token.getUsername();
                user = userService.findUserByPhone(phone);
            }

            System.out.println(phone+"================="+userName);
            //出现异常
            subject.login(token);

            if (subject.isAuthenticated()&&user!=null) {
    
    
                JSON json = new JSONObject();
                ((JSONObject) json).put("token", subject.getSession().getId());
                ((JSONObject) json).put("user",user);
                return new Result(ResultStatusCode.OK, json);
            }else{
    
    

                return new Result(ResultStatusCode.SHIRO_ERROR);
            }
        }catch (IncorrectCredentialsException | UnknownAccountException e){
    
    
            e.printStackTrace();
            return new Result(ResultStatusCode.NOT_EXIST_USER_OR_ERROR_PWD);
        }catch (LockedAccountException e){
    
    
            e.printStackTrace();
            return new Result(ResultStatusCode.USER_FROZEN);
        }catch (Exception e){
    
    
            e.printStackTrace();
            return new Result(ResultStatusCode.SYSTEM_ERR);
        }
    }
}

自定义多realm登录策略

package com.music.system.shiro;


import com.music.system.shiro.realm.LoginType;
import com.music.system.shiro.realm.UserToken;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.realm.Realm;

import java.util.Collection;
import java.util.HashMap;

/**
 * 自定义多realm登录策略
 */
public class MyModularRealmAuthenticator extends ModularRealmAuthenticator {
    
    
    @Override
    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
    
    
        // 判断getRealms()是否返回为空
        assertRealmsConfigured();

        // 所有Realm
        Collection<Realm> realms = getRealms();
        // 登录类型对应的所有Realm
        HashMap<String, Realm> realmHashMap = new HashMap<>(realms.size());
        for (Realm realm : realms) {
    
    
            realmHashMap.put(realm.getName(), realm);
        }

        UserToken token = (UserToken) authenticationToken;
        System.out.println("token------>"+token);
        // 登录类型
        LoginType loginType = token.getLoginType();

        if (realmHashMap.get(loginType.getType()) != null) {
    
    
            return doSingleRealmAuthentication(realmHashMap.get(loginType.getType()), token);
        } else {
    
    
            return doMultiRealmAuthentication(realms, token);
        }
    }
}

JedisClient Java操作redis工具(可扩展)

/*
  Created by IntelliJ IDEA.
  User: Kalvin
  Date: 2020/5/13
  Time: 14:21
*/
package com.music.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
public class JedisClient {
    
    

    @Autowired
    private StringRedisTemplate redisTemplate;

    // Key(键),简单的key-value操作
    /**
     * 实现命令:TTL key,以秒为单位,返回给定 key的剩余生存时间(TTL, time to live)。
     *
     * @param key
     * @return
     */
    public long ttl(String key) {
    
    
        return redisTemplate.getExpire(key);
    }

    /**
     * 实现命令:expire 设置过期时间,单位秒
     *
     * @param key
     * @return
     */
    public void expire(String key, long timeout) {
    
    
        redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 实现命令:INCR key,增加key一次
     *
     * @param key
     * @return
     */
    public long incr(String key, long delta) {
    
    
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 实现命令:KEYS pattern,查找所有符合给定模式 pattern的 key
     */
    public Set<String> keys(String pattern) {
    
    
        return redisTemplate.keys(pattern);
    }

    /**
     * 实现命令:DEL key,删除一个key
     *
     * @param key
     */
    public void del(String key) {
    
    
        redisTemplate.delete(key);
    }


    // String(字符串)
    /**
     * 实现命令:SET key value,设置一个key-value(将字符串值 value关联到 key)
     *
     * @param key
     * @param value
     */
    public void set(String key, String value) {
    
    
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 实现命令:SET key value EX seconds,设置key-value和超时时间(秒)
     *
     * @param key
     * @param value
     * @param timeout
     *            (以秒为单位)
     */
    public void set(String key, String value, long timeout) {
    
    
        redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 实现命令:GET key,返回 key所关联的字符串值。
     *
     * @param key
     * @return value
     */
    public String get(String key) {
    
    
        return (String)redisTemplate.opsForValue().get(key);
    }


    // Hash(哈希表)
    /**
     * 实现命令:HEXISTS key field,查找哈希表中是否包含指定键值对 key中给定域 field的值
     * @param key
     * @param field
     * @return
     */
    public Boolean hexists(String key, String field){
    
    
        return redisTemplate.opsForHash().hasKey(key, field);
    }

    /**
     * 实现命令:HSET key field value,将哈希表 key中的域 field的值设为 value
     *
     * @param key
     * @param field
     * @param value
     */
    public void hset(String key, String field, Object value) {
    
    
        redisTemplate.opsForHash().put(key, field, value);
    }

    /**
     * 实现命令:HGET key field,返回哈希表 key中给定域 field的值
     *
     * @param key
     * @param field
     * @return
     */
    public String hget(String key, String field) {
    
    
        return (String) redisTemplate.opsForHash().get(key, field);
    }

    /**
     * 实现命令:HDEL key field [field ...],删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
     *
     * @param key
     * @param fields
     */
    public void hdel(String key, Object... fields) {
    
    
        redisTemplate.opsForHash().delete(key, fields);
    }

    /**
     * 实现命令:HGETALL key,返回哈希表 key中,所有的域和值。
     *
     * @param key
     * @return
     */
    public Map<Object, Object> hgetall(String key) {
    
    
        return redisTemplate.opsForHash().entries(key);
    }

    // List(列表)

    /**
     * 实现命令:LPUSH key value,将一个值 value插入到列表 key的表头
     *
     * @param key
     * @param value
     * @return 执行 LPUSH命令后,列表的长度。
     */
    public long lpush(String key, String value) {
    
    
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 实现命令:LPOP key,移除并返回列表 key的头元素。
     *
     * @param key
     * @return 列表key的头元素。
     */
    public String lpop(String key) {
    
    
        return (String)redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 实现命令:RPUSH key value,将一个值 value插入到列表 key的表尾(最右边)。
     *
     * @param key
     * @param value
     * @return 执行 LPUSH命令后,列表的长度。
     */
    public long rpush(String key, String value) {
    
    
        return redisTemplate.opsForList().rightPush(key, value);
    }


}

有关使用阿里云手机发送短信验证码,下篇文章详细介绍。这里只是分享核心代码,帮助理解记忆。

有兴趣的小伙伴可以关注微信公众号:幽灵邀请函 回复:网欲音乐 获取更多项目资料及完整项目,一起学习可以加QQ:2817670312

猜你喜欢

转载自blog.csdn.net/qq_43900677/article/details/112912929