基本验证流程
(一)用户登录
用户进入登录界面,输入用户名密码

对验证码校验

校验账号密码

登录成功,颁发token

(二)获取用户信息
客户端:携带token请求API

服务端:从请求头中获取token

服务端:提取token中隐藏的用户信息

服务端:返回用户信息

(三)鉴权
客户端:携带token请求API

服务端:从请求头中获取token

服务端:提取token中用户权限信息

服务端:鉴权

服务端:返回结果

(四)退出登录
客户端:携带token请求API

服务端:从请求头中获取token

服务端:把token作为key放进redis黑名单

服务端:返回登录成功

(五)验证用户token是否有效
客户端:携带token请求API

服务端:从请求头中获取token

服务端:把token作为key查询redis黑名单

  • 存在:用户token过期
  • 不存在:用户token正常

    服务端:返回登录成功

实际操作

 <!--图片验证码-->
 <dependency>
     <groupId>com.github.penggle</groupId>
     <artifactId>kaptcha</artifactId>
     <version>2.3.2</version>
 </dependency>
 <!--spring redis-->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>

xml配置 使用kaptcha生成验证码,需要将该类由spring管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">
        <property name="config">
            <bean class="com.google.code.kaptcha.util.Config">
                <constructor-arg type="java.util.Properties">
                    <props>
                        <prop key = "kaptcha.border ">yes</prop>
                        <prop key="kaptcha.border.color">105,179,90</prop>
                        <prop key="kaptcha.textproducer.font.color">blue</prop>
                        <prop key="kaptcha.image.width">100</prop>
                        <prop key="kaptcha.image.height">50</prop>
                        <prop key="kaptcha.textproducer.font.size">27</prop>
                        <prop key="kaptcha.session.key">code</prop>
                        <prop key="kaptcha.textproducer.char.length">4</prop>
                        <prop key="kaptcha.textproducer.font.names">宋体,楷体,微软雅黑</prop>
                        <prop key="kaptcha.textproducer.char.string">0123456789ABCEFGHIJKLMNOPQRSTUVWXYZ</prop>
                        <prop key="kaptcha.obscurificator.impl">com.google.code.kaptcha.impl.WaterRipple</prop>
                        <prop key="kaptcha.noise.color">black</prop>
                        <prop key="kaptcha.noise.impl">com.google.code.kaptcha.impl.DefaultNoise</prop>
                        <prop key="kaptcha.background.clear.from">185,56,213</prop>
                        <prop key="kaptcha.background.clear.to">white</prop>
                        <prop key="kaptcha.textproducer.char.space">3</prop>
                    </props>
                </constructor-arg>
            </bean>
        </property>
    </bean>
</beans>

properties


# redis
# 数据库索引,默认0
spring.redis.database=7
# 服务器IP地址
spring.redis.host: ***.***.***.**
# 连接端口
spring.redis.port: *****
# Redis服务器连接密码(默认为空)
spring.redis.password:******

# 连接池最大连接数(使用负值表示没有限制)
jedis.pool.max-active=800
# 连接池最大阻塞等待时间(使用负值表示没有限制)
jedis.pool.max-wait: 10000
# 连接池中的最大空闲连接
jedis.pool.max-idle: 20
# 连接池中的最小空闲连接
jedis.pool.min-idle: 2
# 连接超时时间(毫秒)
jedis.timeout: 30000
spring.cache.type=redis

application 在springboot启动类中添加下面一句使得spring能托管该类
@ImportResource(locations={“classpath:kaptcha.xml”}) //支持图片验证码

package com.macro.mall;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
import org.springframework.transaction.annotation.EnableTransactionManagement;


@SpringBootApplication
@MapperScan({"com.macro.mall.mapper","com.macro.mall.dao"})
@EnableTransactionManagement
@ImportResource(locations={"classpath:kaptcha.xml"}) //支持图片验证码
public class MallAdminApplication {
    public static void main(String[] args) {
        SpringApplication.run(MallAdminApplication.class, args);
    }
}

生成验证码

package com.macro.mall.controller;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@RestController
public class VerificationController {
    private static Logger logger = LoggerFactory.getLogger(VerificationController.class);

    @Autowired
    private DefaultKaptcha defaultKaptcha;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Value("${authCode.expire.seconds}")
    private Long AUTH_CODE_EXPIRE_SECONDS;
    @Value("${authCode.key}")
    private String authCodeKey;


    @ApiOperation(value = "图片验证码", notes = "图片验证码")
    @GetMapping("/****")//隐藏接口
    public void defaultKaptcha(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        byte[] captchaChallengeAsJpeg = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            //生产验证码字符串并保存到redis中
            String createText = defaultKaptcha.createText();
            logger.debug("image code is:"+createText);
            redisTemplate.opsForValue().set(authCodeKey,createText,AUTH_CODE_EXPIRE_SECONDS, TimeUnit.SECONDS);
            String ss = redisTemplate.opsForValue().get(authCodeKey).toString();
            //使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
            BufferedImage challenge = defaultKaptcha.createImage(createText);
            ImageIO.write(challenge, "jpg", jpegOutputStream);
        } catch (IllegalArgumentException e) {
            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        //定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组
        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
        httpServletResponse.setHeader("Cache-Control", "no-store");
        httpServletResponse.setHeader("Pragma", "no-cache");
        httpServletResponse.setDateHeader("Expires", 0);
        httpServletResponse.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream =
                httpServletResponse.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
}

登录

package com.macro.mall.controller;

import com.macro.mall.dto.CommonResult;
import com.macro.mall.dto.UmsAdminLoginParam;
import com.macro.mall.dto.UmsAdminParam;
import com.macro.mall.dto.UmsMemberParam;
import com.macro.mall.model.UmsAdmin;
import com.macro.mall.model.UmsMember;
import com.macro.mall.model.UmsPermission;
import com.macro.mall.model.UmsRole;
import com.macro.mall.service.UmsAdminService;
import com.macro.mall.service.UmsMerchantService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 商户端管理
 * Created by cui_yl on 2018/4/26.
 */
@RestController
@Api(tags = "UmsMerchantController", description = "商户端管理")
@RequestMapping("/merchant")
public class UmsMerchantController {
    private static Logger logger = LoggerFactory.getLogger(UmsMerchantController.class);

    @Autowired
    private UmsMerchantService umsMerchantService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Value("${authCode.key}")
    private String authCodeKey;

    //商铺用户登录
    @ApiOperation(value = "登录以后返回token")
    @PostMapping(value = "/***")
    public Object login(@RequestBody UmsMemberParam umsMemberParam) {
        try {
            if (null == umsMemberParam || StringUtils.isEmpty(umsMemberParam.getAuthCode())){
                return new CommonResult().validateFailed("验证码为空");
            }
            String verifyCode = String.valueOf(redisTemplate.opsForValue().get(authCodeKey));
            if (null != verifyCode && !(verifyCode.equals(umsMemberParam.getAuthCode()))){
                return new CommonResult().validateFailed("验证码错误");
            }
            if (StringUtils.isEmpty(umsMemberParam.getShopId()) || StringUtils.isEmpty(umsMemberParam.getPassword())){
                return new CommonResult().validateFailed("手机号或密码为空");
            }
            String token = umsMerchantService.login(umsMemberParam.getTelephone(), umsMemberParam.getPassword(), umsMemberParam.getShopId());
            if (token == null) {
                return new CommonResult().validateFailed("手机号或密码错误");
            }
            Map<String, String> tokenMap = new HashMap<>();
            tokenMap.put("token", token);
            tokenMap.put("tokenHead", tokenHead);
            return new CommonResult().success(tokenMap);
        }catch (Exception e){
            logger.error("登录失败"+e.getMessage(), e);
            return new CommonResult().failed(e.getMessage());
        }
    }
}

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐