return SaResult.error(e.getMessage());
});
}
}
- 扩展下Sa-Token提供的StpInterface接口,用于获取用户的权限,我们在用户登录以后会把用户信息存到Session中去,权限信息也会在里面,所以权限码只要从Session中获取即可。
/**
- 自定义权限验证接口扩展
*/
@Component
public class StpInterfaceImpl implements StpInterface {
@Override
public List getPermissionList(Object loginId, String loginType) {
// 返回此 loginId 拥有的权限码列表
UserDTO userDTO = (UserDTO) StpUtil.getSession().get(“userInfo”);
return userDTO.getPermissionList();
}
@Override
public List getRoleList(Object loginId, String loginType) {
// 返回此 loginId 拥有的角色码列表
return null;
}
}
micro-sa-token-auth
===================
接下来我们来搭建下认证服务,只要集成Sa-Token并实现登录接口即可,非常简单。
- 首先在pom.xml中添加相关依赖,包括Sa-Token的SpringBoot依赖、整合Redis实现分布式Session的依赖以及我们的micro-sa-token-common依赖;
cn.dev33
sa-token-spring-boot-starter
1.24.0
cn.dev33
sa-token-dao-redis-jackson
1.24.0
org.apache.commons
commons-pool2
com.macro.cloud
micro-sa-token-common
1.0.0
- 接下来修改配置文件application.yml,照抄之前网关的配置即可;
spring:
redis:
database: 0
port: 6379
host: localhost
password:
Sa-Token配置
sa-token:
token名称 (同时也是cookie名称)
token-name: Authorization
token有效期,单位秒,-1代表永不过期
timeout: 2592000
token临时有效期 (指定时间内无操作就视为token过期),单位秒
activity-timeout: -1
是否允许同一账号并发登录 (为false时新登录挤掉旧登录)
is-concurrent: true
在多人登录同一账号时,是否共用一个token (为false时每次登录新建一个token)
is-share: false
token风格
token-style: uuid
是否输出操作日志
is-log: false
是否从cookie中读取token
is-read-cookie: false
是否从head中读取token
is-read-head: true
- 在UserController中定义好登录接口,登录成功后返回Token,具体实现在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(“用户名或密码错误”);
}
Map<String, String> tokenMap = new HashMap<>();
tokenMap.put(“token”, saTokenInfo.getTokenValue());
tokenMap.put(“tokenHead”, saTokenInfo.getTokenName());
return CommonResult.success(tokenMap);
}
}
- 在UserServiceImpl中添加登录的具体逻辑,首先验证密码,密码校验成功后,通知下Sa-Token登录的用户ID,然后把用户信息直接存储到Session中去;
/**
-
用户管理业务类
-
Created by macro on 2020/6/19.
*/
@Service
public class UserServiceImpl{
private List 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;
}
// 密码校验成功后登录,一行代码实现登录
StpUtil.login(userDTO.getId());
// 将用户信息存储到Session中
StpUtil.getSession().set(“userInfo”,userDTO);
// 获取当前登录用户Token信息
saTokenInfo = StpUtil.getTokenInfo();
return saTokenInfo;
}
}
- 这里有一点需要提醒下,Sa-Token的Session并不是我们平时理解的HttpSession,而是它自己实现的类似Session的机制。
micro-sa-token-api
==================
接下来我们来搭建一个受保护的API服务,实现获取登录用户信息的接口和需要特殊权限才能访问的测试接口。
- 首先在pom.xml中添加相关依赖,和上面的micro-sa-token-auth一样;
cn.dev33
sa-token-spring-boot-starter
1.24.0
cn.dev33
sa-token-dao-redis-jackson
1.24.0
org.apache.commons
commons-pool2
com.macro.cloud
micro-sa-token-common
1.0.0
- 接下来修改配置文件application.yml,照抄之前网关的配置即可;
spring:
redis:
database: 0
port: 6379
host: localhost
password:
Sa-Token配置
sa-token:
token名称 (同时也是cookie名称)
token-name: Authorization
token有效期,单位秒,-1代表永不过期
timeout: 2592000
token临时有效期 (指定时间内无操作就视为token过期),单位秒
activity-timeout: -1
是否允许同一账号并发登录 (为false时新登录挤掉旧登录)
is-concurrent: true
在多人登录同一账号时,是否共用一个token (为false时每次登录新建一个token)
is-share: false
token风格
token-style: uuid
是否输出操作日志
is-log: false
是否从cookie中读取token
is-read-cookie: false
是否从head中读取token
is-read-head: true
- 添加获取用户信息的接口,由于使用了Redis实现分布式Session,直接从Session中获取即可,是不是非常简单!
/**
-
获取登录用户信息接口
-
Created by macro on 2020/6/19.
*/
@RestController
@RequestMapping(“/user”)
public class UserController{
@GetMapping(“/info”)
public CommonResult userInfo() {
UserDTO userDTO = (UserDTO) StpUtil.getSession().get(“userInfo”);
return CommonResult.success(userDTO);
}
}
- 添加需要api:test:hello权限访问的测试接口,预置的admin用户拥有该权限,而macro用户是没有的。
/**
-
测试接口
-
Created by macro on 2020/6/19.
*/
@RestController
@RequestMapping(“/test”)
public class TestController {
@GetMapping(“/hello”)
public CommonResult hello() {
return CommonResult.success(“Hello World.”);
}
}
功能演示
====
三个服务搭建完成后,我们用Postman来演示下微服务的认证授权功能。
- 首先启动Nacos和Redis服务,然后再启动micro-sa-token-gateway、micro-sa-token-auth和micro-sa-token-api服务,启动顺序无所谓;
- 直接通过网关访问登录接口获取Token,访问地址:http://localhost:9201/auth/user/login
- 通过网关访问API服务,不带Token调用获取用户信息的接口,无法正常访问,访问地址:http://localhost:9201/api/user/info
- 通过网关访问API服务,带Token调用获取用户信息的接口,可以正常访问;
- 通过网关访问API服务,使用macro用户访问需api:test:hello权限的测试接口,无法正常访问,访问地址:http://localhost:9201/api/test/hello
- 登录切换为admin用户,该用户具有api:test:hello权限;
最后
ActiveMQ消息中间件面试专题
- 什么是ActiveMQ?
- ActiveMQ服务器宕机怎么办?
- 丢消息怎么办?
- 持久化消息非常慢怎么办?
- 消息的不均匀消费怎么办?
- 死信队列怎么办?
- ActiveMQ中的消息重发时间间隔和重发次数吗?
ActiveMQ消息中间件面试专题解析拓展:
redis面试专题及答案
- 支持一致性哈希的客户端有哪些?
- Redis与其他key-value存储有什么不同?
- Redis的内存占用情况怎么样?
- 都有哪些办法可以降低Redis的内存使用情况呢?
- 查看Redis使用情况及状态信息用什么命令?
- Redis的内存用完了会发生什么?
- Redis是单线程的,如何提高多核CPU的利用率?
Spring面试专题及答案
- 谈谈你对 Spring 的理解
- Spring 有哪些优点?
- Spring 中的设计模式
- 怎样开启注解装配以及常用注解
- 简单介绍下 Spring bean 的生命周期
Spring面试答案解析拓展
高并发多线程面试专题
- 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?
- Java 中新的 Lock 接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性。
- Java 中 wait 和 sleep 方法有什么区别?
- 如何在 Java 中实现一个阻塞队列?
- 如何在 Java 中编写代码解决生产者消费者问题?
- 写一段死锁代码。你在 Java 中如何解决死锁?
高并发多线程面试解析与拓展
jvm面试专题与解析
- JVM 由哪些部分组成?
- JVM 内存划分?
- Java 的内存模型?
- 引用的分类?
- GC什么时候开始?
JVM面试专题解析与拓展!
ng 中的设计模式
- 怎样开启注解装配以及常用注解
- 简单介绍下 Spring bean 的生命周期
Spring面试答案解析拓展
[外链图片转存中…(img-JZMKcyb9-1721187911640)]
高并发多线程面试专题
- 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?
- Java 中新的 Lock 接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性。
- Java 中 wait 和 sleep 方法有什么区别?
- 如何在 Java 中实现一个阻塞队列?
- 如何在 Java 中编写代码解决生产者消费者问题?
- 写一段死锁代码。你在 Java 中如何解决死锁?
高并发多线程面试解析与拓展
[外链图片转存中…(img-oS2ZToUt-1721187911641)]
jvm面试专题与解析
- JVM 由哪些部分组成?
- JVM 内存划分?
- Java 的内存模型?
- 引用的分类?
- GC什么时候开始?
JVM面试专题解析与拓展!
[外链图片转存中…(img-3dpezkSL-1721187911642)]