SpringBoot下token短信驗證登入登出(token存放redis)
不對SpringBoot進行介紹,具體的可以參考官方文檔
介紹:token基本使用,redis基本使用
思路:獲取短信(驗證並限制發送次數,將code存放redis)-->登入(驗證並限制錯誤次數,將用戶信息及權限放token,token放redis)-->查詢操作(略),主要將前兩點,不足的希望指出,謝謝
步驟:
1.整合Redis需要的依賴,yml自行配置,ali短信接口依賴(使用引入外部包的方式)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>ali</groupId>
<artifactId>taobao-sdk-java-auto</artifactId>
<scope>system</scope>
<!--將jar包放在項目/libs/xxx.jar-->
<systemPath>${project.basedir}/libs/taobao-sdk-java-auto.jar</systemPath>
</dependency>
.......
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!--打包的時候引用該屬性的包-->
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
2.ali短信接口工具類,發送驗證碼
@Autowired
private StringRedisTemplate redisTemplate;
....略....
//查詢是否有此用戶,記錄單位時間內發送短信次數,並限制發送次數
Account account = accountService.findByUserName(phone);
if (account==null){
return ResultVOUtil.erro(0,"未註冊用戶");
}
ValueOperations<String, String> ops = redisTemplate.opsForValue();
String getTimes = ops.get(account + "code");
Integer gts=getTimes==null?0:Integer.valueOf(getTimes);
if (gts>5){
return ResultVOUtil.erro(0,"獲取短信次數過多,請稍後再試");
}
ops.set(account+"code",String.valueOf(gts+1),5,TimeUnit.MINUTES);
NoteUtils noteUtils=new NoteUtils();
String validCode = UidUtil.getValidCode(); //生成隨機數
try {
String yzmcode = noteUtils.yzmcode(validCode, phone);
//redis設置驗證碼有效時間5分組
ops.set(phone,validCode,5,TimeUnit.MINUTES);
}catch (Exception e){
throw new YunExceptions(0,"獲取驗證碼服務器bug");
}
//短信接口工具類
public class NoteUtils {
//僅當示例:具體參考官方文檔
public String url="***************";
public String appkey="****************";
public String secret="*********************";
public String yzmcode(String code,String telnum) throws ApiException, JSONException {
TaobaoClient client = new DefaultTaobaoClient(url, appkey, secret);
AlibabaAliqinFcSmsNumSendRequest req = new AlibabaAliqinFcSmsNumSendRequest();
req.setExtend( "extend" );
req.setSmsType( "normal" );
req.setSmsFreeSignName( "*************" );
req.setSmsParamString( "{code:'"+code+"'}" );
req.setRecNum(telnum);
req.setSmsTemplateCode( "******************" );
AlibabaAliqinFcSmsNumSendResponse rsp = client.execute(req);
return "true";
}
}
3.登入驗證,並將權限保存在token,以下有token工具類,可直接copy使用
public ResultVo login(String phone, String code, HttpServletResponse response, HttpServletRequest request){
ValueOperations<String, String> ops = redisTemplate.opsForValue();
String validcode = ops.get(phone);
String outtimes=ops.get(phone+"wrong");
Integer ots=outtimes==null?0:Integer.valueOf(outtimes);
if (ots>5){
return ResultVOUtil.erro(0,"錯誤次數過多,請稍後再試");
}
if (validcode!=null){
String vcode=validcode.toString();
if (code.equalsIgnoreCase(vcode)){
Account account = accountService.findByUserName(phone);
if (account!=null){
//記錄登入信息,獲取權限,字符串類型a,b,c,d
String token = TokenUtils.tokenGet(phone, account.getDbids());
Loglogin loglogin=new Loglogin();
loglogin.setActionid(200);
loglogin.setUserip(request.getRemoteAddr());
loglogin.setUsername(phone);
loglogin.setLogtime(Timestamp.valueOf(TimeUtil.getCurDate()));
loglogin.setUserid(account.getUserId());
logloginService.save(loglogin);
設置token時效
ops.set(phone+"token",token,60,TimeUnit.MINUTES);
return ResultVOUtil.success(token);
}else {
return ResultVOUtil.erro(0,"沒有此賬戶");
}
}else {
ops.set(phone+"wrong",String.valueOf(ots+1),5,TimeUnit.MINUTES);
return ResultVOUtil.erro(0,"驗證碼錯誤");
}
}else {
return ResultVOUtil.erro(0,"請先獲取驗證碼");
}
}
//token工具類
public class TokenUtils {
public static String tokenGet(String username,String limits){
Map<String,Object> map=new HashMap<>();
map.put("alg","HS256");
map.put("typ","JWT");
try {
Algorithm algorithm=Algorithm.HMAC256("*******");
String token = JWT.create()
.withHeader(map)
/*設置 載荷 Payload*/
.withClaim("loginName", username)
.withClaim("limits",limits)
//設置過期時間-->間隔一定時間驗證是否本人登入
.withExpiresAt(new Date(System.currentTimeMillis()+3600000*5))
.withIssuer("****")//簽名是有誰生成 例如 服務器
.withSubject("*****")//簽名的主題
.withAudience("*****")//簽名的觀衆 也可以理解誰接受簽名的
/*簽名 Signature */
.sign(algorithm);
return token;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
public static String validToken(String token, String dbid){
try {
Algorithm algorithm = Algorithm.HMAC256("*******");
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("SERVICE")
.build();
DecodedJWT jwt = verifier.verify(token);
String subject = jwt.getSubject();
List<String> audience = jwt.getAudience();
Map<String, Claim> claims = jwt.getClaims();
Claim limits = claims.get("limits");
//驗證操作權限,set長度改變說明權限不一致
String ss = limits.asString();
String[] split = ss.split(",");
Set<String> set=new HashSet<>(Arrays.asList(split));
int size = set.size();
set.add(dbid);
if (set.size()!=size){
return null;
}else {
Claim name = claims.get("loginName");
return name.asString();
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
4.接下來都比較簡單
4.1獲取數據-->前端傳參數,後臺驗證即可,
4.2退出的時候,清除redis裏的token數據即可,