1. 程式人生 > 其它 >認證服務

認證服務

建立認證模組

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);
}