Spring Cloud下实现用户鉴权的方案

网友投稿 730 2022-11-20

Spring Cloud下实现用户鉴权的方案

Spring Cloud下实现用户鉴权的方案

目录一、整体架构二、实现步骤三、其它问题四、完整代码

java下常用的安全框架主要有Spring Security和shiro,都可提供非常强大的功能,但学习成本较高。在微服务下鉴权多多少少都会对服务有一定的入侵性。 为了降低依赖,减少入侵,让鉴权功能相对应用服务透明,我们采用网关拦截资源请求的方式进行鉴权。

一、整体架构

用户鉴权模块位于API GateWay服务中,所有的API资源请求都需要从此通过。

做身份认证,通过则缓存用户权限数据,不通过返回401

做用户鉴权,比对当前访问资源(URI和Method)是否在已缓存的用户权限数据中,在则转发请求给对应应用服务,不在则返回403

二、实现步骤

1. 用户登陆

public LoginUser login(String userName, String password){

// 检查密码

User user = userService.checkUser(userName, password);

LoginUser loginUser = LoginUser.builder()

.userName(userName)

.realName(user.getRealName())

.userToken(UUID.randomUUID().toString())

.loginTime(new Date())

.build();

// 保存session

session.saveSession(loginUser);

// 查询权限

List permissions = permissionRepository.findByUserName(userName);

// 保存用户权限到缓存中

session.http://saveUserPermissions(userName, permissions);

return loginUser;

}

// ...

// 缓存用户权限到Redis

public void saveUserPermissions(String userName, List permissions) {

String key = String.format("login:permission:%s", userName);

HashOperations hashOperations = redisTemplate.opsForHash();

hashOperations.putAll(key, permissions.stream().collect(

Collectors.toMap(p -> p.getMethod().concat(":").concat(p.getUri()),

Permission::getName, (k1, k2) -> k2)));

if (expireTime != null) {

redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);

}

}

用户验证通过后,下发userToken,保存当前登陆信息,缓存用户授权列表

缓存授权列表时,为了方便读取使用hash方式保存为list,切勿直接将数组对象保存为一个object

2. 拦截请求

@Slf4j

@Component

public class AuthorizationFilter extends AbstractGatewayFilterFactory {

@Autowired

private Session session;

@Override

public GatewayFilter apply(Object config) {

return (exchange, chain) -> {

ServerHttpRequest request = exchange.getRequest();

ServerHttpResponse response = exchange.getResponse();

String uri = request.getURI().getPath();

String method = request.getMethodValue();

// 1.从AuthenticationFilter中获取userName

String key = "X-User-Name";

if (!request.getHeaders().containsKey(key)) {

response.setStatusCode(HttpStatus.FORBIDDEN);

return response.setComplete();

}

String userName = Objects.requireNonNull(request.getHeaders().get(key)).get(0);

// 2.验证权限

if (!session.checkPermissions(userName, uri, method)) {

log.info("用户:{}, 没有权限", userName);

response.setStatusCode(HttpStatus.FORBIDDEN);

return response.setComplete();

}

return chain.filter(exchange);

};

}

}

第一步从取出身份认证模块传递的X-User-Name

第二步去缓存中检查是否有相应的权限

public boolean checkPermissions(String userName, String uri, String method) {

String key = String.format("login:permission:%s", userName);

String hashKey = String.format("%s:%s", method, uri);

if (redisTemplate.opsForHash().hasKey(key, hashKey)){

return true;

}

String allKey = "login:permission:all";

// 权限列表中没有则通过

return !redisTemplate.opsForHash().hasKey(allKey, hashKey);

}

权限列表中没有则通过 主要是放过一些没有必要配置的公共资源,默认都可以访问的资源

login:permission:all 所有配置过的权限列表需要在程序启动时放入缓存,并需要保持数据的更新

3. 鉴权Filter配置

spring:

cloud:

gateway:

routes:

- id: cloud-user

RGKWYSyX uri: lb://cloud-user # 后端服务名

predicates:

- Path=/user/** # 路由地址

filters:

- name: AuthenticationFilter # 身份认证

- name: AuthorizationFilter # 用户鉴权

- StripPrefix=1 # 去掉前缀

特别注意filter的顺序,必须先做身份认证后再进行鉴权

如果有较多的路由都需要配置,可使用default-filters默认Filter配置

三、其它问题

在做单元测试时,如遇到如下错误

nested exception is java.lang.NoClassDefFoundError: javax/validation/ValidationException

请升级依赖包版本:

org.hibernate.validator

hibernate-validator

6.0.5.Final

javax.validation

validation-api

2.0.1.Final

四、完整代码

代码

以上就是Spring Cloud下实现用户鉴权的方案的详细内容,更多关于Spring Cloud 用户鉴权的资料请关注我们其它相关文章!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:centeros 部署 .netcore
下一篇:centos7更换yum源 一条命令搞定
相关文章

 发表评论

暂时没有评论,来抢沙发吧~