前沿拓展:
exchange服務(wù)
可以, 可以在設(shè)置-應(yīng)用程序管理-全部 里找到exchange服務(wù),選擇后點(diǎn)關(guān)閉就ok了,以后這個(gè)再不會(huì)啟動(dòng)了,跟卸載差不多了,其它程序也是一樣。想啟動(dòng)的話進(jìn)去點(diǎn)啟動(dòng)就好了。
前置知識(shí)
我們將采用Nacos作為注冊(cè)中心,Gateway作為**,使用Sa-Token提供的微服務(wù)權(quán)限解決方案,此方案是基于之前的解決方案改造的
應(yīng)用架構(gòu)
還是和之前方案差不多的思路,認(rèn)證服務(wù)負(fù)責(zé)登錄處理,**負(fù)責(zé)登錄認(rèn)證和權(quán)限認(rèn)證,其他API服務(wù)負(fù)責(zé)處理自己的業(yè)務(wù)邏輯。為了能在多個(gè)服務(wù)**享Sa-Token的Session,所有服務(wù)都需要集成Sa-Token和Redis。
micro-sa-token-common:通用工具包,其他服務(wù)公用的用戶類UserDTO和通用返回結(jié)果類CommonResult被抽取到了這里。micro-sa-token-gateway:**服務(wù),負(fù)責(zé)請(qǐng)求轉(zhuǎn)發(fā)、登錄認(rèn)證和權(quán)限認(rèn)證。micro-sa-token-auth:認(rèn)證服務(wù),僅包含一個(gè)登錄接口,調(diào)用Sa-Token的API實(shí)現(xiàn)。micro-sa-token-api:受保護(hù)的API服務(wù),用戶通過(guò)**鑒權(quán)通過(guò)后可以訪問(wèn)該服務(wù)。方案實(shí)現(xiàn)
接下來(lái)實(shí)現(xiàn)下這套解決方案,依次搭建**服務(wù)、認(rèn)證服務(wù)和API服務(wù)。
micro-sa-token-gateway
我們第一來(lái)搭建下**服務(wù),它將負(fù)責(zé)整個(gè)微服務(wù)的登錄認(rèn)證和權(quán)限認(rèn)證。
除了通用的Gateway依賴,我們還需要在pom.xml中添加如下依賴,包括Sa-Token的Reactor響應(yīng)式依賴,整合Redis實(shí)現(xiàn)分布式Session的依賴以及我們的micro-sa-token-common依賴;<dependencies>
<!– Sa-Token 權(quán)限認(rèn)證(Reactor響應(yīng)式集成) –>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-reactor-spring-boot-starter</artifactId>
<version>1.24.0</version>
</dependency>
<!– Sa-Token 整合 Redis (使用jackson序列化方式) –>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.24.0</version>
</dependency>
<!– 提供Redis連接池 –>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!– micro-sa-token通用依賴 –>
<dependency>
<groupId>com.macro.cloud</groupId>
<artifactId>micro-sa-token-common</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>接下來(lái)修改配置文件application.yml,添加Redis配置和Sa-Token的配置,如果你看過(guò)之前那篇Sa-Token使用教程的話,基本就知道這些配置的作用了;spring:
redis:
database: 0
port: 6379
host: localhost
password:
# Sa-Token配置
sa-token:
# token名稱 (同時(shí)也是cookie名稱)
token-name: Authorization
# token有效期,單位秒,-1代表**過(guò)期
timeout: 2592000
# token臨時(shí)有效期 (指定時(shí)間內(nèi)無(wú)**作就視為token過(guò)期),單位秒
activity-timeout: -1
# 是否允許同一賬號(hào)并發(fā)登錄 (為false時(shí)新登錄擠掉舊登錄)
is-concurrent: true
# 在多人登錄同一賬號(hào)時(shí),是否共用一個(gè)token (為false時(shí)每次登錄新建一個(gè)token)
is-share: false
# token風(fēng)格
token-style: uuid
# 是否輸出**作日志
is-log: false
# 是否從cookie中讀取token
is-read-cookie: false
# 是否從head中讀取token
is-read-head: true添加Sa-Token的配置類SaTokenConfig,注入一個(gè)過(guò)濾器用于登錄認(rèn)證和權(quán)限認(rèn)證,在setAuth方法中添加路由規(guī)則,在setError方法中添加鑒權(quán)失敗的回調(diào)處理;@Configuration
public class SaTokenConfig {
/**
* 注冊(cè)Sa-Token全局過(guò)濾器
*/
@Bean
public SaReactorFilter getSaReactorFilter() {
return new SaReactorFilter()
// 攔截地址
.addInclude("/**")
// 開(kāi)放地址
.addExclude("/favicon.ico")
// 鑒權(quán)方法:每次訪問(wèn)進(jìn)入
.setAuth(r -> {
// 登錄認(rèn)證:除登錄接口都需要認(rèn)證
SaRouter.match("/**", "/auth/user/login", StpUtil::checkLogin);
// 權(quán)限認(rèn)證:不同接口訪問(wèn)權(quán)限不同
SaRouter.match("/api/test/hello", () -> StpUtil.checkPermission("api:test:hello"));
SaRouter.match("/api/user/info", () -> StpUtil.checkPermission("api:user:info"));
})
// setAuth方法異常處理
.setError(e -> {
// 設(shè)置錯(cuò)誤返回格式為JSON
ServerWebExchange exchange = SaReactorSyncHolder.getContent();
exchange.getResponse().getHeaders().set("Content-Type", "application/json; charset=utf-8");
return SaResult.error(e.getMessage());
});
}
}擴(kuò)展下Sa-Token提供的StpInterface接口,用于獲取用戶的權(quán)限,我們?cè)谟脩舻卿浺院髸?huì)把用戶信息存到Session中去,權(quán)限信息也會(huì)在里面,所以權(quán)限碼只要從Session中獲取即可。/**
* 自定義權(quán)限驗(yàn)證接口擴(kuò)展
*/
@Component
public class StpInterfaceImpl implements StpInterface {
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
// 返回此 loginId 擁有的權(quán)限碼列表
UserDTO userDTO = (UserDTO) StpUtil.getSession().get("userInfo");
return userDTO.getPermissionList();
}
@Override
public List<String> getRoleList(Object loginId, String loginType) {
// 返回此 loginId 擁有的角色碼列表
return null;
}
}micro-sa-token-auth
接下來(lái)我們來(lái)搭建下認(rèn)證服務(wù),只要集成Sa-Token并實(shí)現(xiàn)登錄接口即可,非常簡(jiǎn)單。
第一在pom.xml中添加相關(guān)依賴,包括Sa-Token的SpringBoot依賴、整合Redis實(shí)現(xiàn)分布式Session的依賴以及我們的micro-sa-token-common依賴;<dependencies>
<!– Sa-Token 權(quán)限認(rèn)證 –>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.24.0</version>
</dependency>
<!– Sa-Token 整合 Redis (使用jackson序列化方式) –>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.24.0</version>
</dependency>
<!– 提供Redis連接池 –>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!– micro-sa-token通用依賴 –>
<dependency>
<groupId>com.macro.cloud</groupId>
<artifactId>micro-sa-token-common</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>接下來(lái)修改配置文件application.yml,照抄之前**的配置即可;spring:
redis:
database: 0
port: 6379
host: localhost
password:
# Sa-Token配置
sa-token:
# token名稱 (同時(shí)也是cookie名稱)
token-name: Authorization
# token有效期,單位秒,-1代表**過(guò)期
timeout: 2592000
# token臨時(shí)有效期 (指定時(shí)間內(nèi)無(wú)**作就視為token過(guò)期),單位秒
activity-timeout: -1
# 是否允許同一賬號(hào)并發(fā)登錄 (為false時(shí)新登錄擠掉舊登錄)
is-concurrent: true
# 在多人登錄同一賬號(hào)時(shí),是否共用一個(gè)token (為false時(shí)每次登錄新建一個(gè)token)
is-share: false
# token風(fēng)格
token-style: uuid
# 是否輸出**作日志
is-log: false
# 是否從cookie中讀取token
is-read-cookie: false
# 是否從head中讀取token
is-read-head: true在UserController中定義好登錄接口,登錄成功后返回Token,具體實(shí)現(xiàn)在UserServiceImpl類中;/**
* 自定義Oauth2獲取令牌接口
* Created by macro on 2020/7/17.
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserServiceImpl userService;
@RequestMapping(value = "/login", method = RequestMethod.POST)
public CommonResult login(@RequestParam String username, @RequestParam String password) {
SaTokenInfo saTokenInfo = userService.login(username, password);
if (saTokenInfo == null) {
return CommonResult.validateFailed("用戶名或密碼錯(cuò)誤");
}
Map<String, String> tokenMap = new HashMap<>();
tokenMap.put("token", saTokenInfo.getTokenValue());
tokenMap.put("tokenHead", saTokenInfo.getTokenName());
return CommonResult.success(tokenMap);
}
}在UserServiceImpl中添加登錄的具體邏輯,第一驗(yàn)證密碼,密碼校驗(yàn)成功后,通知下Sa-Token登錄的用戶ID,第二把用戶信息直接存儲(chǔ)到Session中去;/**
* 用戶管理業(yè)務(wù)類
* Created by macro on 2020/6/19.
*/
@Service
public class UserServiceImpl{
private List<UserDTO> userList;
public SaTokenInfo login(String username, String password) {
SaTokenInfo saTokenInfo = null;
UserDTO userDTO = loadUserByUsername(username);
if (userDTO == null) {
return null;
}
if (!SaSecureUtil.md5(password).equals(userDTO.getPassword())) {
return null;
}
// 密碼校驗(yàn)成功后登錄,一行代碼實(shí)現(xiàn)登錄
StpUtil.login(userDTO.getId());
// 將用戶信息存儲(chǔ)到Session中
StpUtil.getSession().set("userInfo",userDTO);
// 獲取當(dāng)前登錄用戶Token信息
saTokenInfo = StpUtil.getTokenInfo();
return saTokenInfo;
}
}這里有一點(diǎn)需要提醒下,Sa-Token的Session并不是我們平時(shí)理解的HttpSession,而是它自己實(shí)現(xiàn)的類似Session的機(jī)制。micro-sa-token-api
接下來(lái)我們來(lái)搭建一個(gè)受保護(hù)的API服務(wù),實(shí)現(xiàn)獲取登錄用戶信息的接口和需要特殊權(quán)限才能訪問(wèn)的測(cè)試接口。
第一在pom.xml中添加相關(guān)依賴,和上面的micro-sa-token-auth一樣;<dependencies>
<!– Sa-Token 權(quán)限認(rèn)證 –>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.24.0</version>
</dependency>
<!– Sa-Token 整合 Redis (使用jackson序列化方式) –>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.24.0</version>
</dependency>
<!– 提供Redis連接池 –>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!– micro-sa-token通用依賴 –>
<dependency>
<groupId>com.macro.cloud</groupId>
<artifactId>micro-sa-token-common</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>接下來(lái)修改配置文件application.yml,照抄之前**的配置即可;spring:
redis:
database: 0
port: 6379
host: localhost
password:
# Sa-Token配置
sa-token:
# token名稱 (同時(shí)也是cookie名稱)
token-name: Authorization
# token有效期,單位秒,-1代表**過(guò)期
timeout: 2592000
# token臨時(shí)有效期 (指定時(shí)間內(nèi)無(wú)**作就視為token過(guò)期),單位秒
activity-timeout: -1
# 是否允許同一賬號(hào)并發(fā)登錄 (為false時(shí)新登錄擠掉舊登錄)
is-concurrent: true
# 在多人登錄同一賬號(hào)時(shí),是否共用一個(gè)token (為false時(shí)每次登錄新建一個(gè)token)
is-share: false
# token風(fēng)格
token-style: uuid
# 是否輸出**作日志
is-log: false
# 是否從cookie中讀取token
is-read-cookie: false
# 是否從head中讀取token
is-read-head: true添加獲取用戶信息的接口,由于使用了Redis實(shí)現(xiàn)分布式Session,直接從Session中獲取即可,是不是非常簡(jiǎn)單!/**
* 獲取登錄用戶信息接口
* Created by macro on 2020/6/19.
*/
@RestController
@RequestMapping("/user")
public class UserController{
@GetMapping("/info")
public CommonResult<UserDTO> userInfo() {
UserDTO userDTO = (UserDTO) StpUtil.getSession().get("userInfo");
return CommonResult.success(userDTO);
}
}添加需要api:test:hello權(quán)限訪問(wèn)的測(cè)試接口,預(yù)置的admin用戶擁有該權(quán)限,而macro用戶是沒(méi)有的。/**
* 測(cè)試接口
* Created by macro on 2020/6/19.
*/
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/hello")
public CommonResult hello() {
return CommonResult.success("Hello World.");
}
}功能演示
三個(gè)服務(wù)搭建完成后,我們用Postman來(lái)演示下微服務(wù)的認(rèn)證授權(quán)功能。
第一啟動(dòng)Nacos和Redis服務(wù),第二再啟動(dòng)micro-sa-token-gateway、micro-sa-token-auth和micro-sa-token-api服務(wù),啟動(dòng)順序無(wú)所謂;
直接通過(guò)**訪問(wèn)登錄接口獲取Token,訪問(wèn)地址:http://localhost:9201/auth/user/login
通過(guò)**訪問(wèn)API服務(wù),不帶Token調(diào)用獲取用戶信息的接口,無(wú)**常訪問(wèn),訪問(wèn)地址:http://localhost:9201/api/user/info
通過(guò)**訪問(wèn)API服務(wù),帶Token調(diào)用獲取用戶信息的接口,可以正常訪問(wèn);
通過(guò)**訪問(wèn)API服務(wù),使用macro用戶訪問(wèn)需api:test:hello權(quán)限的測(cè)試接口,無(wú)**常訪問(wèn),訪問(wèn)地址:http://localhost:9201/api/test/hello
登錄切換為admin用戶,該用戶具有api:test:hello權(quán)限;
通過(guò)**訪問(wèn)API服務(wù),使用admin用戶訪問(wèn)測(cè)試接口,可以正常訪問(wèn)。
小編綜合來(lái)說(shuō)
對(duì)比之前使用Spring Security的微服務(wù)權(quán)限解決方案,Sa-Token的解決方案更簡(jiǎn)單、更優(yōu)雅。使用Security我們需要定義鑒權(quán)管理器、分別處理未認(rèn)證和未授權(quán)的情況、還要自己定義認(rèn)證和資源服務(wù)器配置,使用非常繁瑣。而使用Sa-Token,只要在**上配置過(guò)濾器實(shí)現(xiàn)認(rèn)證和授權(quán),第二調(diào)用API實(shí)現(xiàn)登錄及權(quán)限分配即可。具體區(qū)別可以參考下圖。
項(xiàng)目源碼地址
https://github.com/macrozheng/springcloud-learning/tree/master/micro-sa-token
拓展知識(shí):
exchange服務(wù)
Exchange服務(wù)是一種收發(fā)郵件的協(xié)議。
原創(chuàng)文章,作者:九賢生活小編,如若轉(zhuǎn)載,請(qǐng)注明出處:http://m.xiesong.cn/12043.html