Satoken+Redis實現(xiàn)短信登錄、注冊、鑒權(quán)功能
Springboot集成Satoken
添加依賴
注:如果你使用的是 SpringBoot 3.x,只需要將 sa-token-spring-boot-starter 修改為 sa-token-spring-boot3-starter 即可。
<!-- Sa-Token 權(quán)限認證,在線文檔:https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.34.0</version>
</dependency>設(shè)置配置文件
# 端口 server.port=8081 ############## Sa-Token 配置 (文檔: https://sa-token.cc) ############## # token名稱 (同時也是cookie名稱) sa-token.token-name=satoken # token有效期,單位s 默認30天, -1代表永不過期 sa-token.timeout=2592000 # token臨時有效期 (指定時間內(nèi)無操作就視為token過期) 單位: 秒 sa-token.activity-timeout=-1 # 是否允許同一賬號并發(fā)登錄 (為true時允許一起登錄, 為false時新登錄擠掉舊登錄) sa-token.is-concurrent=true # 在多人登錄同一賬號時,是否共用一個token (為true時所有登錄共用一個token, 為false時每次登錄新建一個token) sa-token.is-share=true # token風格 sa-token.token-style=uuid # 是否輸出操作日志 sa-token.is-log=false
啟動類
在項目中新建包 com.pj ,在此包內(nèi)新建主類 SaTokenDemoApplication.java,復制以下代碼:
@SpringBootApplication
public class SaTokenDemoApplication {
public static void main(String[] args) throws JsonProcessingException {
SpringApplication.run(SaTokenDemoApplication.class, args);
System.out.println("啟動成功:Sa-Token配置如下:" + SaManager.getConfig());
}
}登錄
用戶輸入手機號,調(diào)用登錄接口,根據(jù)手機號查詢是否存在該用戶

@PostMapping("/login")
public Boolean login(@RequestBody String phone) {
//從數(shù)據(jù)庫查詢該手機號的用戶
User user = userInfoDao.selectUser(phone);
//若不存在該用戶返回false,存在返回true
return user == null ? false : true;
}確認用戶存在后就可以調(diào)用發(fā)送驗證碼接口,再校驗驗證碼是否正確

/**
* 發(fā)送驗證碼:
* 在redis中用hash存儲用戶的相關(guān)信息,用PHONE_NUM+手機號作為用戶hash的key,
* “code”作為用戶信息hash中驗證碼的小key,查詢redis中用戶的驗證碼信息,
* "num"是驗證次數(shù)的小key
*/
@PostMapping("/sendCaptcha")
public String sendCaptcha(String phone){
//驗證碼verCode
String verCode;
String key = "PHONE_NUM"+phone;
//如果redis中有緩存的驗證碼
Object object = redisTemplate.opsForHash().get(key, "code");
if(null != object){
throw Error("該用戶驗證碼已發(fā)送,且未過期,請輸入驗證碼登錄或注冊!");
}else {
Random r = new Random(System.currentTimeMillis());
int low = 100000;
int high = 999999;
//根據(jù)時間隨機生成驗證碼verCode,將其放入redis中
int code = (r.nextInt(high - low) + low);
verCode = String.valueOf(code);
redisTemplate.opsForHash().put(key,"code",verCode);
//放入檢驗次數(shù)num=5
redisTemplate.opsForHash().put(key,"num",5);
//設(shè)置過期時間
redisTemplate.expire(key,60*5,TimeUnit.SECONDS);
}
try {
//調(diào)用發(fā)送驗證碼的接口發(fā)送驗證碼
String smsResult= sendMsg(phone, verCode);
}catch (Throwable throwable){
redisTemplate.delete(key);
throw Error("短信發(fā)送失??!");
}
return "發(fā)送成功";
}重點?。。?/strong>
/**
* 校驗驗證碼:
* 驗證成功就StpUtil.login(user.getId())進行登錄,自動生成token并寫入cookie中
*/
@PostMapping("/checkCaptcha")
public String checkCaptcha(String phone,String verCode){
if(phone==null||verCode==null||phone==""||verCode==""){
throw Errorr("請輸入手機及驗證碼!");
}
//從redis中獲取該手機號用戶的信息
String key = "PHONE_NUM"+phone;
Object object = redisTemplate.opsForHash().get(key, "code");
if(null == object){
throw Error("未請求驗證碼或驗證碼已失效,請重新登錄!");
}
String code= object.toString();
if(code.equals(verCode)){
//驗證碼比對正確,刪除redis中驗證碼記錄
redisTemplate.delete(key);
//從數(shù)據(jù)庫查詢出該用戶的信息,并調(diào)用stputil進行登錄
User user = userService.findUser(phone);
StpUtil.login(user.getId());
return "登陸成功";
}else{
//驗證碼比對錯誤,校驗次數(shù)減1
double num = redisTemplate.opsForHash().increment(key,"num",-1);
//若校驗次數(shù)小于0則驗證碼失效,不小于0則拋出驗證碼錯誤
if(num < 0 ){
redisTemplate.delete(key);
return "未請求驗證碼或驗證碼已失效,請重新登錄!";
} else {
return "驗證碼錯誤!";
}
}
}注銷
@PostMapping("/logout")
public Boolean logout() {
if (!StpUtil.isLogin()) {
throw Error("未檢測到登錄信息,請先登錄!");
}
StpUtil.logout();
return true;
}注冊
填入手機號后,若調(diào)用登錄接口根據(jù)手機號查詢數(shù)據(jù)庫發(fā)現(xiàn)不存在該用戶,自動跳轉(zhuǎn)到注冊頁面

@PostMapping("/regist)
public Boolean regist(String userName,String verCode) {
if(userName==null||verCode==null||userName==""||verCode==""){
throw Errorr("請輸入用戶名或驗證碼!");
}
查詢數(shù)據(jù)庫檢查該用戶名是否已經(jīng)被用;
調(diào)用上面登錄里的校驗用戶驗證碼的方法;
用戶名未被占用且驗證碼正確,則向數(shù)據(jù)庫用戶表插入該用戶信息,得到用戶id;
//調(diào)用stputil進行登錄
StpUtil.login(userId());
return true;
}重寫獲取權(quán)限或角色的接口
接口的調(diào)用往往需要權(quán)限的校驗,一般的系統(tǒng)會給用戶綁定某種角色,再給此角色分配權(quán)限,設(shè)置權(quán)限碼,具有此角色或者權(quán)限碼才放行請求。sa-token實現(xiàn)權(quán)限需要進行自定義擴展,下面是獲取一個用戶權(quán)限碼集合和角色標識集合的類:
/**
* 自定義權(quán)限驗證接口擴展
*/
@Component // 保證此類被SpringBoot掃描,完成Sa-Token的自定義權(quán)限驗證擴展
public class StpInterfaceImpl implements StpInterface {
/**
* 返回一個賬號所擁有的權(quán)限碼集合
*/
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
List<String> list = new ArrayList<String>();
//1.先從redis中根據(jù)loginId取該用戶的權(quán)限,有則直接返回
//2.若是redis中沒有,則從數(shù)據(jù)庫中查詢,再把結(jié)果添加到redis中
return list;
// 比如:
// list.add("101");
// list.add("user.add");
// list.add("user.update");
// list.add("user.get");
// list.add("user.delete");
// list.add("art.*");
}
/**
* 返回一個賬號所擁有的角色標識集合 (權(quán)限與角色可分開校驗)
*/
@Override
public List<String> getRoleList(Object loginId, String loginType) {
List<String> list = new ArrayList<String>();
//1.先從redis中根據(jù)loginId取該用戶的角色集合,有則直接返回
//2.若是redis中沒有,則從數(shù)據(jù)庫中查詢,再把結(jié)果添加到redis中
return list;
// 比如:
// list.add("admin");
// list.add("super-admin");
}
}路由攔截實現(xiàn)鑒權(quán)
在調(diào)用后臺服務(wù)時,我們可以在路由時做一些攔截,例如添加登陸權(quán)限攔截、放開一些接口白名單等。(一定要排除 登錄、注冊、發(fā)送驗證碼等接口 的攔截)
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
// 注冊 Sa-Token 的攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注冊路由攔截器,自定義認證規(guī)則
registry.addInterceptor(new SaInterceptor(handler -> {
//SaRouter.match(參數(shù)一:需要攔截的路由,
參數(shù)二:可排除的路由,
參數(shù)三:用來檢驗是否通過攔截的方法)
// 登錄校驗 -- 用是否登錄攔截所有路由,
// 在最下面的.excludePathPatterns中并排除登錄等接口的攔截
SaRouter.match("/**", r -> StpUtil.checkLogin());
// 角色校驗 -- 攔截以 admin 開頭的路由,必須具備 admin 角色或者 super-admin 角色才可以通過認證
SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));
// 權(quán)限校驗 -- 不同模塊校驗不同權(quán)限
SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
SaRouter.match("/notice/**", r -> StpUtil.checkPermission("notice"));
SaRouter.match("/comment/**", r -> StpUtil.checkPermission("comment"));
// 甚至你可以隨意的寫一個打印語句
SaRouter.match("/**", r -> System.out.println("----啦啦啦----"));
// 連綴寫法
SaRouter.match("/**").check(r -> System.out.println("----啦啦啦----"));
})).addPathPatterns("/**")
// 排除登錄、注冊、發(fā)送驗證碼等接口 的攔截
.excludePathPatterns("/user/login")
.excludePathPatterns("/user/sendCaptcha")
.excludePathPatterns("/user/checkCaptcha")
.excludePathPatterns("/user/regist")
;
}
}到此這篇關(guān)于Satoken+Redis實現(xiàn)短信登錄、注冊、鑒權(quán)的文章就介紹到這了,更多相關(guān)Redis短信登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring?boot集成redis基礎(chǔ)入門實例詳解
redis在spring?boot項目開發(fā)中是常用的緩存套件,常見使用的是spring-boot-starter-data-redis,這篇文章主要介紹了spring?boot集成redis基礎(chǔ)入門,本文結(jié)合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-10-10
如何使用Redis實現(xiàn)電商系統(tǒng)的庫存扣減
在日常開發(fā)中有很多地方都有類似扣減庫存的操作,本文主要介紹了如何使用Redis實現(xiàn)電商系統(tǒng)的庫存扣減,具有一定的參考價值,感興趣的可以了解一下2022-01-01
Redis擊穿穿透雪崩產(chǎn)生原因分析及解決思路面試
這篇文章主要為大家介紹了Redis擊穿穿透雪崩產(chǎn)生原因及解決思路的面試問題答案參考,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進步2022-03-03
Windows設(shè)置Redis為開機自啟動的流程步驟
Redis作為當前最常用的當前緩存技術(shù),基本上Web應(yīng)用中都有使用,所以,每次我們在本地啟動項目前,都必須將Redis服務(wù)端啟動,但是,每次都要去啟動Redis就很麻煩,本文主要就是介紹Windows系統(tǒng)如何配置開機啟動Redis,需要的朋友可以參考下2024-05-05

