SpringCloud Alibaba入门教程六——登录保持与JWT

有状态 VS 无状态

有状态是后台session存储用户信息,每次前台如果从一个浏览器访问的同一个服务器,就会解析cookie携带的sessionID从而解析到用户实现登录状态。
无状态是后台不再使用session,而是使用一串编码过的字符串传递到前台,前台使用某种技术进行保存,每次会话都要携带token向后台发送请求 ,后台通过解析token分别身份(也可以将特定的身份保存在redis中),从而实现无状态的登录。
在这里插入图片描述

认证方案

  • 使用SpringCloud Security等框架
  • 使用网关、颁发、解密、认证,认证成功后微服务内部不再认证
  • 网关不认证,有专门的微服务进行token颁发、每个微服务在请求来到时都各自解析一遍token是否合法
  • 将token存放在指定的后台服务器中,每次请求来的时候验证,同最初使用session是一样的。适合于旧项目改造新项目使用。

访问控制模型

  • Access Control List (ACL)
  • Role-based access control (RBAC)
  • Attribute-based access control(ABAC)
  • Rule-based access control
  • Time-based access control

Role-based access control 用户 --(关联)-- 角色 --(关联)-- 权限

JWT

JWT操作工具类使用

AOP实现用户登录检查

笔者之前使用的是拦截器进行登录校验,因为SpringAOP是Spring比较重要的一环,所以这里再次使用SpringAOP进行登录校验。
引入spring-boot-starter-aop依赖,创建自定义注解创建一个切面使用其中的方法匹配注解并编写检查登录逻辑。

package com.itmuch.contentcenter.auth;

public @interface CheckLogin {
}

package com.itmuch.contentcenter.auth;

@Aspect
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class AuthAspect {
    private final JwtOperator jwtOperator;

    @Around("@annotation(com.itmuch.contentcenter.auth.CheckLogin)")
    public Object checkLogin(ProceedingJoinPoint point) throws Throwable {
        checkToken();
        return point.proceed();
    }

    private void checkToken() {
        try {
            // 1. 从header里面获取token
            HttpServletRequest request = getHttpServletRequest();

            String token = request.getHeader("X-Token");

            // 2. 校验token是否合法&是否过期;如果不合法或已过期直接抛异常;如果合法放行
            Boolean isValid = jwtOperator.validateToken(token);
            if (!isValid) {
                throw new SecurityException("Token不合法!");
            }

            // 3. 如果校验成功,那么就将用户的信息设置到request的attribute里面
            Claims claims = jwtOperator.getClaimsFromToken(token);
            request.setAttribute("id", claims.get("id"));
            request.setAttribute("wxNickname", claims.get("wxNickname"));
            request.setAttribute("role", claims.get("role"));
        } catch (Throwable throwable) {
            throw new SecurityException("Token不合法");
        }
    }
   //获取request
    private HttpServletRequest getHttpServletRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
        return attributes.getRequest();
    }

    @Around("@annotation(com.itmuch.contentcenter.auth.CheckAuthorization)")
    public Object checkAuthorization(ProceedingJoinPoint point) throws Throwable {
        try {
            // 1. 验证token是否合法;
            this.checkToken();
            // 2. 验证用户角色是否匹配
            HttpServletRequest request = getHttpServletRequest();
            String role = (String) request.getAttribute("role");

            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            CheckAuthorization annotation = method.getAnnotation(CheckAuthorization.class);

            String value = annotation.value();

            if (!Objects.equals(role, value)) {
                throw new SecurityException("用户无权访问!");
            }
        } catch (Throwable throwable) {
            throw new SecurityException("用户无权访问!", throwable);
        }
        return point.proceed();
    }
}

Feign实现token传递

  • @RequestHeader 在服务提供者以及Feign的调用方的Controller方法参数列表中中全部加上 @RequestHeader("token") String token
  • 使用RequestInterceptor
public class TokenRelayRequestIntecepor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        // 1. 获取到token
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = attributes.getRequest();
        String token = request.getHeader("X-Token");

        // 2. 将token传递
        if (StringUtils.isNotBlank(token)) {
            template.header("X-Token", token);
        }

    }
}

这个配置在2-9一节中有提到

requestInterceptor:
  - com.itmuch.contentcenter.feignclient.interceptor;

RestTemplate传递token

  • exchange()
@GetMapping("/tokenRelay/{userId}")
    public ResponseEntity<UserDTO> tokenRelay(@PathVariable Integer userId, HttpServletRequest request) {
        String token = request.getHeader("X-Token");
        HttpHeaders headers = new HttpHeaders();
        headers.add("X-Token", token);

        return this.restTemplate
            .exchange(
                "http://user-center/users/{userId}",
                HttpMethod.GET,
                new HttpEntity<>(headers),
                UserDTO.class,
                userId
            );
    }
  • 实现ClientHttpRequestInterceptor
    这个类是RestTemplate的拦截器,和Feign的差不多
public class TestRestTemplateTokenRelayInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest httpRequest = attributes.getRequest();
        String token = httpRequest.getHeader("X-Token");

        HttpHeaders headers = request.getHeaders();
        headers.add("X-Token", token);

        // 保证请求继续执行
        return execution.execute(request, body);
    }
}

还需要创建RestTemplate的时候进行拦截器的设置

 @Bean
    @LoadBalanced
    @SentinelRestTemplate
    public RestTemplate restTemplate() {
        RestTemplate template = new RestTemplate();
        template.setInterceptors(
            Collections.singletonList(
                new TestRestTemplateTokenRelayInterceptor()
            )
        );
        return template;
    }

AOP实现权限校验

使用自定义注解以及AOP的方式实现,同上文的检查token差不多

//这里表示在运行期注入注解
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckAuthorization {
    String value();
}

@PutMapping("/audit/{id}")
    @CheckAuthorization("admin")
    public Share auditById(@PathVariable Integer id, @RequestBody ShareAuditDTO auditDTO) {
        return this.shareService.auditById(id, auditDTO);
    }
 @Around("@annotation(com.itmuch.contentcenter.auth.CheckAuthorization)")
    public Object checkAuthorization(ProceedingJoinPoint point) throws Throwable {
        try {
            // 1. 验证token是否合法;
            this.checkToken();
            // 2. 验证用户角色是否匹配
            HttpServletRequest request = getHttpServletRequest();
            String role = (String) request.getAttribute("role");

            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            CheckAuthorization annotation = method.getAnnotation(CheckAuthorization.class);

            String value = annotation.value();

            if (!Objects.equals(role, value)) {
                throw new SecurityException("用户无权访问!");
            }
        } catch (Throwable throwable) {
            throw new SecurityException("用户无权访问!", throwable);
        }
        return point.proceed();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Spring Cloud是一个基于Spring Boot的开发工具,用于快速构建分布式系统的微服务框架。它提供了一系列的组件,包括服务注册与发现、配置中心、负载均衡、断路器、网关等,使得开发者可以更加方便地构建和管理微服务。 Spring Security是Spring框架中的一个安全框架,用于提供身份认证和授权功能。它可以与Spring Cloud集成,为微服务提供安全保障。 JWT(JSON Web Token)是一种轻量级的身份认证和授权机制,它使用JSON格式来传递信息。在Spring Cloud中,可以使用JWT来实现微服务之间的安全通信,保证数据的安全性和完整性。 ### 回答2: Spring Cloud是一个开源的分布式系统开发框架,它基于Spring Boot,能够帮助开发者快速构建云原生应用程序。Spring Cloud提供了一系列的组件,例如服务注册与发现(Eureka)、服务网关(Zuul)、配置中心(Config)等,可以协助开发者实现微服务架构。 Spring Security是Spring框架提供的一种安全框架,它能够为应用程序提供认证和授权的功能。Spring Security基于过滤器链的机制,可以对请求进行安全验证。开发者可以通过配置来定义访问控制规则,保护应用程序的资源。 JWT(JSON Web Token)是一种用于身份验证和访问控制的标准方法,它通过在身份验证完成后生成一个令牌,并将该令牌发送给客户端,客户端在后续的请求中通过该令牌进行身份验证。JWT由三部分组成,分别是头部、载荷和签名。头部和载荷使用Base64进行编码,然后使用一个密钥进行签名,确保JWT的安全性。 在使用Spring CloudSpring Security构建分布式系统时,可以使用JWT作为认证和授权的方式。具体做法是,当用户进行身份验证成功后,生成一个JWT令牌,并将该令牌返回给客户端。客户端在后续的请求中,将令牌作为Authorization头部的内容发送给服务端。服务端接收到请求后,解析JWT令牌,验证其合法性,并根据令牌中的信息来判断用户的身份和权限。通过这种方式,可以实现无状态的分布式身份验证和访问控制。 总结来说,Spring Cloud可以帮助开发者构建分布式系统,Spring Security可以提供身份验证和授权的功能,而JWT可以作为一种安全的认证和授权方式在分布式系统中使用。这三者相互结合,可以帮助开发者构建安全、可靠的分布式应用程序。 ### 回答3: Spring Cloud是一个基于Spring Boot的开发工具集,它提供了一系列的分布式系统开发工具,其中包括了分布式配置中心、服务注册与发现、消息总线、负载均衡、熔断器、数据流处理等。Spring Cloud的目标是帮助开发者快速构建适应于云环境的分布式系统。 Spring Security是Spring官方提供的安全框架,它可以用于保护Spring应用程序免受各种攻击,例如身份验证、授权、防止跨站点请求伪造等。Spring Security使用一种基于过滤器链的方式来处理HTTP请求,通过配置一系列的过滤器,可以实现对请求的鉴权和授权处理。 JWT(JSON Web Token)是一种用于跨域身份验证的开放标准。它可以在用户和服务器之间传输信息,并且能够对信息进行校验和解析。JWT一般由三部分组成:头部、载荷和签名。头部包含了令牌的类型和加密算法,载荷包含了需要传输的信息,签名用于验证令牌的合法性。 在使用Spring Cloud时,可以结合Spring Security和JWT来进行身份验证和授权。我们可以通过配置Spring Security的过滤器链来验证JWT的有效性,并在每个请求中进行用户身份的鉴权。通过使用JWT,我们可以避免传统的基于Session的身份验证方式,实现无状态的分布式身份验证。 总结起来,Spring Cloud是一个分布式系统开发工具集,Spring Security是一个安全框架,JWT是一种用于跨域身份验证的开放标准。在使用Spring Cloud进行分布式系统开发时,可以结合Spring Security和JWT来实现身份验证和授权的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值