1. 实名认证开发 117
业务逻辑
1.1 实名认证配置类 118
micr-web
JdwxRealnameConfig
package com.bjpowernode.front.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 实名认证配置类 118
*/
@Component
@ConfigurationProperties(prefix = "jdwx.realname")
public class JdwxRealnameConfig {
private String url;
private String appkey;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getAppkey() {
return appkey;
}
public void setAppkey(String appkey) {
this.appkey = appkey;
}
}
1.2 配置文件 118
micr-web
application.yml
#短信配置 85
jdwx:
sms:
url: https://way.jd.com/chuangxin/dxjk
appkey: 3680fa919b771148da626bbcbd459475
content: 【大富科技】你的验证码是:%s,3分钟内有效,请勿泄露给他人
login-text: 【大富科技】登录验证码是:%s,3分钟内有效,请勿泄露给他人
realname: #实名认证 118
url: https://way.jd.com/youhuoBeijing/test
appkey: 3680fa919b771148da626bbcbd459475
1.3 实名认证实体类 118
micr-web
RealnameVO
package com.bjpowernode.front.vo;
/**
* 实名认证实体类 118
*/
public class RealnameVO {
private String phone;
private String name;
private String idCard;
private String code;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
1.4 实名认证实现类 119
发送HttpClientUtils的工具类 119
micr-common
E:\java学习\盈利宝\资料\资料\04-httpclient\HttpClient\src\main\java\com\bjpowernode\http
业务接口 120
micr-api
UserService
//更新实名认证的信息 120
boolean modifyRealname(String phone, String name, String idCard);
业务接口实现类 120
micr-dataservice
UserServiceImpl
//更新实名认证的信息的实现类 120
@Override
public boolean modifyRealname(String phone, String name, String idCard) {
int rows = 0;
if(!StringUtils.isAnyBlank(phone,name,idCard)){
rows = userMapper.updateRealname(phone,name,idCard);
}
return rows > 0 ;
}
在mapper中定义方法 120
micr-dataservice
UserMapper
//更新实名认证的信息 120
int updateRealname(String phone, String name, String idCard);
编写sql 120
micr-dataservice
UserMapper.xml
<!--更新实名认证的信息 120-->
<update id="updateRealname">
update u_user set name=#{name} , id_card = #{idCard} where phone = #{phone}
</update>
实名认证实现类RealnameServiceImpl 119
micr-web
RealnameServiceImpl
package com.bjpowernode.front.service;
import com.alibaba.fastjson.JSONObject;
import com.bjpowernode.api.model.User;
import com.bjpowernode.api.service.UserService;
import com.bjpowernode.common.util.HttpClientUtils;
import com.bjpowernode.front.config.JdwxRealnameConfig;
import com.fasterxml.jackson.databind.node.POJONode;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
/**
* 实名认证实现类 119
*/
@Service
public class RealnameServiceImpl {
@Resource
private JdwxRealnameConfig realnameConfig;
//120
@DubboReference(interfaceClass = UserService.class,version = "1.0")
private UserService userService;
/*true:认证通过*/
public boolean handleRealname(String phone,String name,String idCard){
boolean realname = false;
Map<String, String> params = new HashMap<>();
params.put("cardNo",idCard);
params.put("realName",name);
params.put("appkey",realnameConfig.getAppkey());
try {
//我们为了方便查询注释真实发送,就模拟成功发送
// String resp = HttpClientUtils.doGet(realnameConfig.getUrl(),params);
String resp="{\n" +
" \"code\": \"10000\",\n" +
" \"charge\": false,\n" +
" \"remain\": 1305,\n" +
" \"msg\": \"查询成功\",\n" +
" \"result\": {\n" +
" \"error_code\": 0,\n" +
" \"reason\": \"成功\",\n" +
" \"result\": {\n" +
" \"realname\": \""+name+"\",\n" +
" \"idcard\": \"350721197702134399\",\n" +
" \"isok\": true\n" +
" }\n" +
" }\n" +
"}";
if(StringUtils.isNotBlank(resp)){
JSONObject respObject = JSONObject.parseObject(resp);
if( "10000".equalsIgnoreCase(respObject.getString("code"))){
//解析result
realname = respObject.getJSONObject("result")
.getJSONObject("result")
.getBooleanValue("isok");
//处理更新数据库
boolean modifyResult = userService.modifyRealname(phone,name,idCard);
realname = modifyResult;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return realname;
}
}
1.5 消费者controller 119-120
添加枚举类 120
micr-common
micr-web
UserController
//实名认证 118
@ApiOperation(value = "实名认证",notes = "提供手机号和姓名,身份证号。认证姓名和身份证号是否一致")
@PostMapping("/realname")
public RespResult userRealname(@RequestBody RealnameVO realnameVO){
RespResult result = RespResult.fail();
result.setRCode(RCode.REQUEST_PARAM_ERR);
//1验证请求参数 119
if( CommonUtil.checkPhone(realnameVO.getPhone())){
if(StringUtils.isNotBlank(realnameVO.getName()) &&
StringUtils.isNotBlank(realnameVO.getIdCard())){
//判断用户已经做过
User user = userService.queryByPhone(realnameVO.getPhone());
if( user != null ){
if( StringUtils.isNotBlank(user.getName())){
result.setRCode(RCode.REALNAME_RETRY);
} else {
//有短信验证码,先不写
//调用第三方接口,判断认证结果 120
boolean realnameResult = realnameService.handleRealname(
realnameVO.getPhone(),realnameVO.getName(),
realnameVO.getIdCard());
if( realnameResult == true ){
result = RespResult.ok();
} else {
result.setRCode(RCode.REALNAME_FAIL);
}
}
}
}
}
return result;
}
3.6 小测试 121
使用postman
http://localhost:8000/api/v1/user/realname
这里提示参数的身份证号就写这个,因为后端我没改
发送请求,成功
看看数据库,ok没问题
2. 实名认证前端 115
2.1 添加路由 115
index.js
{
path: '/page/user/realname',
name: 'RealNameView',
component: () => import('../views/RealNameView.vue')
}
添加按钮 122
2.2 创建页面 115、122-123
RealNameView.vue
<template>
<div>
<Header> </Header>
<div class="login-content">
<div class="login-flex">
<div class="login-left"></div>
<!---->
<div class="login-box">
<h3 class="login-title">实名认证</h3>
<form action="" id="renZ_Submit">
<div class="alert-input">
<input type="text" class="form-border user-name" name="username" v-model="name" @blur="checkName" placeholder="请输入您的真实姓名">
<div class="err">{{nameErr}}</div>
<p class="prompt_name"></p>
<input type="text" class="form-border user-sfz" name="sfz" v-model="idCard" @blur="checkIdCard" placeholder="请输入15位或18位身份证号">
<div class="err">{{idCardErr}}</div>
<p class="prompt_sfz"></p>
<input type="text" class="form-border user-num" name="mobile" v-bind:value="phone" readonly placeholder="请输入11位手机号">
<p class="prompt_num"></p>
<div class="form-yzm form-border">
<input class="yzm-write" type="text" v-model="code" @blur="checkCode" placeholder="输入短信验证码">
<input class="yzm-send" type="text" value="获取验证码" disabled="disabled" id="yzmBtn" readonly="readonly" >
</div>
<div class="err">{{codeErr}}</div>
<p class="prompt_yan"></p>
</div>
<div class="alert-input-agree">
<input type="checkbox" v-model="agree">我已阅读并同意<a href="javascript:;" target="_blank">《动力金融网注册服务协议》</a>
</div>
<div class="alert-input-btn">
<input type="button" @click="requestRealname" class="login-submit" value="认证">
</div>
</form>
<div class="login-skip">
暂不认证? <a href="javascript:;" @click="goLink('/page/user/usercenter')">跳过</a>
</div>
</div>
</div>
</div>
<Footer></Footer>
</div>
</template>
<script>
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
import {doPostJson} from "@/api/httpRequest";
import layx from "vue-layx";
export default {
name: "RealNameView",
components: {
// eslint-disable-next-line vue/no-unused-components
Header,
// eslint-disable-next-line vue/no-unused-components
Footer
},
data(){
return {
name:'',
nameErr:'',
idCard:'350721197702134399',
idCardErr:'',
code:'1234',
codeErr:'',
phone:'',
agree:false
}
},
mounted() {
//获取localStorage中的用户数据
let userinfo = window.localStorage.getItem("userinfo");
if( userinfo ){
this.phone = JSON.parse(userinfo).phone;
}
},
methods:{
goLink(url,params){
//使用router做页面跳转, vue中的对象
this.$router.push({
path: url,
query: params
})
},
checkName(){
if( this.name == '' || this.name == null ){
this.nameErr = '必须输入姓名';
} else if( this.name.length < 2 ){
this.nameErr = '姓名不正确';
} else if( !/^[\u4e00-\u9fa5]{0,}$/.test(this.name)){
this.nameErr ='姓名必须是中文';
} else {
this.nameErr = '';
}
},
checkIdCard(){
if( this.idCard == '' || this.idCard == null){
this.idCardErr = '请输入身份证号';
} else if(!/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(this.idCard)){
this.idCardErr='身份证号格式不正确';
} else {
this.idCardErr = '';
}
},
checkCode() {
if (this.code == '' || this.code == undefined) {
this.codeErr = '必须输入验证码';
} else if (this.code.length != 4) {
this.codeErr = '验证码是4位的';
} else {
this.codeErr = '';
}
},
requestRealname(){ //发送请求 124
if(this.agree == false ){
layx.msg('请阅读注册协议.',{dialogIcon:'warn',position:'ct'});
return;
}
this.checkName();
this.checkIdCard();
this.checkCode();
if( this.codeErr == '' && this.nameErr == '' && this.idCardErr == ''){
let param = {
name:this.name,
phone:this.phone,
idCard:this.idCard,
code:this.code
}
doPostJson('/v1/user/realname',param).then(resp=>{
if(resp && resp.data.code == 1000){
//跳转到用户中心
this.$router.push({
path:'/page/user/usercenter'
})
}
})
}
}
}
}
</script>
<style scoped>
.err {
color: red;
font-size: 18px;
}
</style>
测试
填好参数
发送
跳转到了认证空间,成功
看看数据库
在次重新认证会提示
3. 前端请求拦截器 携带token 126
httpRequest.js
//创建拦截器 126
axios.interceptors.request.use(function(config){
//在需要用户登录后的操作,在请求的url中加入token
//判断访问服务器的url地址, 需要提供身份信息,加入token
console.log("url==="+config.url);
if( config.url == '/v1/user/realname') {
let storageToken = window.localStorage.getItem("token");
let userinfo = window.localStorage.getItem("userinfo");
if( storageToken && userinfo ){
//在header中传递token 和一个userId
config.headers['Authorization']='Bearer ' + storageToken;
config.headers['uid'] = JSON.parse(userinfo).uid;
}
}
return config;
},function(err){
console.log("请求错误"+err);
})
测试一下
认证,当我们发送认证请求时,会同时发两个请求一个是我们真正的实名post请求,一个是被前端拦截的OPTIONS
经过前端拦截器拦截后,我们的认证请求会被携带token等相关数据
4. 后端验证token 127
4.1 读取token 128
micr-common
JwtUtil
//读取jwt 128
public Claims readJwt(String jwt) throws Exception{
SecretKey secretKey = Keys.hmacShaKeyFor(selfKey.getBytes(StandardCharsets.UTF_8));
Claims body = Jwts.parserBuilder().setSigningKey(secretKey)
.build().parseClaimsJws(jwt).getBody();
return body;
}
4.2 拦截器 127
添加枚举类
micr-common
TokenInterceptor 127-129
micr-web
package com.bjpowernode.front.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.bjpowernode.common.enums.RCode;
import com.bjpowernode.common.util.JwtUtil;
import com.bjpowernode.front.view.RespResult;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
//拦截器,验证token 127
public class TokenInterceptor implements HandlerInterceptor {
private String secret = "";
public TokenInterceptor(String secret) {
this.secret = secret;
}
// 127
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//如果是OPTIONS,放行
if("OPTIONS".equalsIgnoreCase(request.getMethod())){
return true;
}
//获取token,进行验证 128
boolean requestSend = false;
try{
//2.获取token的,进行验证
String headerUid = request.getHeader("uid");
String headerToken = request.getHeader("Authorization");
if(StringUtils.isNotBlank(headerToken)){
//Bearer eyxxxxx
String jwt = headerToken.substring(7);
//读jwt
JwtUtil jwtUtil = new JwtUtil(secret);
Claims claims = jwtUtil.readJwt(jwt);
//获取jwt中的数据,uid
Integer jwtUid = claims.get("uid",Integer.class);
if( headerUid.equals( String.valueOf(jwtUid))){
//token和发起请求用户是同一个。 请求可以被处理
requestSend = true;
}
}
}catch (Exception e){
requestSend = false;
e.printStackTrace();
}
//token没有验证通过,需要给vue错误提示
if( requestSend == false ){
//返回json数据给前端
RespResult result = RespResult.fail();
result.setRCode(RCode.TOKEN_INVALID);
//使用HttpServletResponse输出 json
String respJson = JSONObject.toJSONString(result);
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
out.print(respJson);
out.flush();
out.close();
}
return requestSend;
}
}
4.3 在全局配置类中添加拦截器 130
micr-web
WebMvcConfiguration
//配置拦截器 130
@Value("${jwt.secret}")
private String jwtSecret;
//增加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//创建一个拦截器
TokenInterceptor tokenInterceptor = new TokenInterceptor(jwtSecret);
//addPath是要拦截的地址,后面还可以加
String [] addPath = {"/v1/user/realname"};
registry.addInterceptor(tokenInterceptor)
.addPathPatterns(addPath);
}
4.4 测试
首先我们去登录
登录成功,token和用户数据也被存入了Local Storage中了
下面开始认证
请求别拦截器拦截
携带了token
看看后端,在debug模式下成功被后端拦截
结束,成功
5. 前端应答拦截器 131
httpRequest.js 131
//创建应答拦截器,统一对错误处理, 后端返回 code > 1000 都是错误 131
axios.interceptors.response.use(function(resp){
if(resp && resp.data.code > 1000 ){
let code = resp.data.code;
if( code == 3000){
//token无效,重新登录
window.location.href='/page/user/login';
} else {
layx.msg(resp.data.msg,{dialogIcon:'warn',position:'ct'});
}
}
return resp;
},function (err){
console.log("应答拦截器错误:"+err)
//回到首页
window.location.href = '/';
})
测试 131
被拦截跳转登录界面
标签:code,String,idCard,认证,实名,import,public,name From: https://blog.51cto.com/u_15784725/7176739