認證服務
阿新 • • 發佈:2022-03-09
建立認證模組
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
相關配置
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);
}