认证服务

创建认证模块

在这里插入图片描述

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall-auth-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall-auth-server</name>
    <description>gulimall-auth-server</description>
    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.atguigu.gulimall</groupId>
            <artifactId>gulimall-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <groupId>com.baomidou</groupId>
                    <artifactId>mybatis-plus-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

application.properties

spring.application.name=gulimall-auth-server

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

server.port=20000

主启动类

package com.atguigu.gulimall.auth;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallAuthServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(GulimallAuthServerApplication.class, args);
    }

}

启动验证

启动服务,发现服务注册进 Nacos

在这里插入图片描述

页面及域名访问初始化

修改hosts实现域名访问

192.168.56.10	auth.gulimall.com

配置网关转发域名

spring:
  cloud:
    gateway:
      routes:
      
        - id: gulimall_auth_route
          uri: lb://gulimall-auth-server
          predicates:
            - Host=auth.gulimall.com

引入登录页面

将登录页面和注册页面放到 templates 下,静态文件可以选择 Nginx 动静分离配置。最终目录:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

认证服务-短信验证码

阿里云短信服务

https://www.aliyun.com/product/sms?spm=5176.159202.J_8058803260.68.64ae6a56APLp1H

参照文档:https://help.aliyun.com/document_detail/112148.htm?spm=a2c4g.11186623.0.0.6ccc3e0688ApNt#concept-mlr-q2b-fhb

相关配置

yaml配置

ipAddr: 192.168.56.10
spring:
  application:
    name: gulimall-auth-server
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        dashboard: localhost:8333
  thymeleaf:
    cache: false
  session:
    store-type: redis
  redis:
    host: ${ipAddr}
    port: 6379

发送验证码组件

package com.atguigu.gulimall.thirdparty.component;

import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.atguigu.common.utils.HttpUtils;
import lombok.Data;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * <p>Title: SmsComponent</p>
 * Description:
 * date:2020/6/25 14:23
 */
@Data
@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms")
@Component
public class SmsComponent {

	private String accessKeyId;

	private String secret;

	private String signName;

	private String templateCode;

	/**
	 * 发送短信验证码
	 * 示例: 您的验证码是:XXXXXX,10分钟内有效。如非本人操作请注意个人信息安全。
	 *
	 * @param phone 手机号
	 * @param code  验证码
	 * @return 发送结果
	 */
	public String sendCode(String phone, String code) {
		DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, secret);
		IAcsClient client = new DefaultAcsClient(profile);

		CommonRequest request = new CommonRequest();
		request.setSysMethod(MethodType.POST);
		request.setSysDomain("dysmsapi.aliyuncs.com");
		request.setSysVersion("2017-05-25");
		request.setSysProduct("Dysmsapi");
		request.setSysAction("SendSms");
		request.putQueryParameter("RegionId", "cn-hangzhou");
		request.putQueryParameter("PhoneNumbers", phone);//接收短信的手机号码
		request.putQueryParameter("SignName", signName);//短信签名名称
		request.putQueryParameter("TemplateCode", templateCode);//短信模板CODE
		request.putQueryParameter("TemplateParam", "{\"code\":\"" + code + "\"}");//短信模板变量对应的实际值
		CommonResponse response = null;
		try {
			response = client.getCommonResponse(request);
			System.out.println(response.getData());//{"RequestId":"51EE15A9-063F-5341-B2EC-D80E6CF0E305","Message":"OK","BizId":"167118146737237878^0","Code":"OK"}
			return response.getData();
		} catch (ServerException e) {
			e.printStackTrace();
		} catch (ClientException e) {
			e.printStackTrace();
		}
		return "fail_" + response.getHttpStatus();
	}
	
	// public String sendSmsCode(String phone, String code){
	// 	String method = "GET";
	// 	Map<String, String> headers = new HashMap<String, String>();
	// 	//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
	// 	headers.put("Authorization", "APPCODE " + this.appCode);
	// 	Map<String, String> querys = new HashMap<String, String>();
	// 	querys.put("code", code);
	// 	querys.put("phone", phone);
	// 	querys.put("skin", this.skin);
	// 	querys.put("sign", this.sign);
	// 	HttpResponse response = null;
	// 	try {
	// 		response = HttpUtils.doGet(this.host, this.path, method, headers, querys);
	// 		//获取response的body
	// 		if(response.getStatusLine().getStatusCode() == 200){
	// 			return EntityUtils.toString(response.getEntity());
	// 		}
	// 	} catch (Exception e) {
	// 		e.printStackTrace();
	// 	}
	// 	return "fail_" + response.getStatusLine().getStatusCode();
	// }
}

测试

    @Autowired
    SmsComponent smsComponent;

    @Test
    public void testSmsComponent() {
        smsComponent.sendCode("18070516157", "666666");
    }

发送短信接口

@Controller
@RequestMapping("/sms")
public class SmsSendController {

	@Autowired
	private SmsComponent smsComponent;

	/**
	 * 提供给别的服务进行调用的
	 */
	@GetMapping("/sendcode")
	public R sendCode(@RequestParam("phone") String phone, @RequestParam("code") String code){
		if(!"fail".equals(smsComponent.sendCode(phone, code).split("_")[0])){
			return R.ok();
		}
		return R.error(BizCodeEnum.SMS_SEND_CODE_EXCEPTION.getCode(), BizCodeEnum.SMS_SEND_CODE_EXCEPTION.getMsg());
	}
}

接口防刷和验证码再次校验

mall-auth-server LoginController.java

@ResponseBody
@GetMapping(value = "/sms/sendCode")
public R sendCode(@RequestParam("phone") String phone) {

    //1、接口防刷
    String redisCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);
    if (!StringUtils.isEmpty(redisCode)) {
        //活动存入redis的时间,用当前时间减去存入redis的时间,判断用户手机号是否在60s内发送验证码
        long currentTime = Long.parseLong(redisCode.split("_")[1]);
        if (System.currentTimeMillis() - currentTime < 60000) {
            //60s内不能再发
            return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(), BizCodeEnum.SMS_CODE_EXCEPTION.getMsg());
        }
    }

    //2、验证码的再次效验 redis.存key-phone,value-code
    int code = (int) ((Math.random() * 9 + 1) * 100000);
    String codeNum = String.valueOf(code);
    String redisStorage = codeNum + "_" + System.currentTimeMillis();

    //存入redis,防止同一个手机号在60秒内再次发送验证码
    stringRedisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone,
                                          redisStorage, 10, TimeUnit.MINUTES);

    thirdPartFeignService.sendCode(phone, codeNum);

    return R.ok();
}

认证服务-登录注册功能

参数校验补充

通过注解可以给前端传递过来的值进行校验,例如:

在这里插入图片描述

但是这个注解必须配合 @Valid 使用,完成对参数的校验:

在这里插入图片描述

而校验的结果,也会自动封装到 BindingResult 类型中,通过这个参数可以很方便的对错误的参数进行处理。

hasErrors() 可以判断是否有参数校验错误,如果有,可以通过 getFieldsErrors() 方法获取错误列表。

在这里插入图片描述

注意:@Valid 和 BindingResult 是一一对应的,多个 @Valid 标注的参数实体后面要对应各自的 BindingResult.

SpringMVC 重定向携带数据

在这里插入图片描述

MD5&MD5盐值加密

MD5

Message Digest algorithm 5,信息摘要算法

  • 压缩性:任意长度的数据,算出的 MD5 值长度都是固定的;

  • 容易计算:从原数据计算出 MD5 值很容易;

  • 抗修改性:对原数据进行任何改动,哪怕只修改 1 个字节,所得到的 MD5 值都有很大区别;

  • 强抗碰撞:想找到两个不同的数据,使它们具有相同的 MD5 值是非常困难的;

  • 不可逆

@Test
void contextLoads() {
    String s = DigestUtils.md5Hex("123456");
    System.out.println(s);
    // 盐值加密
    System.out.println(Md5Crypt.md5Crypt("123456".getBytes()));
    System.out.println(Md5Crypt.md5Crypt("123456".getBytes(), "$1$qqqqqqqq"));

    // Spring 盐值加密(使用这个方式加密)
    BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
    //$2a$10$GT0TjB5YK5Vx77Y.2N7hkuYZtYAjZjMlE6NWGE2Aar/7pk/Rmhf8S
    //$2a$10$cR3lis5HQQsQSSh8/c3L3ujIILXkVYmlw28vLA39xz4mHDN/NBVUi
    String encode = bCryptPasswordEncoder.encode("123456");
    boolean matches = bCryptPasswordEncoder.matches("123456", "$2a$10$GT0TjB5YK5Vx77Y.2N7hkuYZtYAjZjMlE6NWGE2Aar/7pk/Rmhf8S");
    System.out.println(encode + "==>" + matches);
}
posted @ 2022-03-09 19:19  chenfl  阅读(66)  评论(0编辑  收藏  举报