SpringCloud微服务如何进行权限校验?

这篇具有很好参考价值的文章主要介绍了SpringCloud微服务如何进行权限校验?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、概述:

1、什么是Spring Cloud?

SpringCloud, 基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于NetFlix的开源组件做高度抽象封装之外,还有一些选型中立的开源组件。

SpringCloud利用SpringBoot的开发便利性,巧妙地简化了分布式系统基础设施的开发,SpringCloud为开发人员提供了快速构建分布式系统的一些工具,包括配置管理,服务发现,断路器,路由,微代理,事件总线,全局锁,决策竞选,分布式会话等等,他们都可以用SpringBoot的开发风格做到一键启动和部署。

SpringBoot并没有重复造轮子,它只是将目前各家公司开发的比较成熟,经得起实际考研的服务框架组合起来,通过SpringBoot风格进行再封装,屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂,易部署和易维护的分布式系统开发工具包

2、什么是Spring Cloud 与 SpringBoot的关系

  • SpringBoot专注于快速方便的开发单个个体微服务。
  • SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供:配置管理,服务发现,断路器,路由,微代理,事件总线,全局锁,决策竞选,分布式会话等等集成服务。
  • SpringBoot可以离开SpringCloud独立使用,开发项目,但是SpringCloud离不开SpringBoot,属于依赖关系

二、以前的鉴权方案

1、单机tomcat应用登录检验(方案一 tomcat开启session 共享)

  • sesssion保存在浏览器和应用服务器会话之间
  • 用户登录成功,服务端会保证一个session,会给客户端一个sessionId
  • 客户端访问的时候会把sessionId保存在cookie中,每次请求都会携带这个sessionId

这种方案存在的问题:
1)存信息到内存,会话保持(session会存储在内存里,如果用户量比较大呢?内存就会被沾满)
2)JessionId存到浏览器cookie里面,如果cookie被拦截就有可能发生CSRF攻击(跨站攻击)

2、分布式应用中session共享(方案二redis集群存储登录token)

真实的应用不可能单节点部署,所以就有个多节点登录session共享的问题需要解决

1)tomcat支持session共享,但是有广播风暴;用户量大的时候,占用资源就严重,不推荐
2)使用redis存储token:

服务端使用UUID生成随机64位或者128位token,放入redis中,然后返回给客户端并存储在cookie中,用户每次访问都携带此token,服务端去redis中校验是否有此用户即可,这种方式目前也有很多公司都在使用。但是这种方式不是最优的方案,这种方式需要每次都去redis里拿数据检验一下,在访问量大的时候,每次访问redis也是一种资源(比如网络资源和IO)的消耗,所以现在很多应用已经开始使用我们今天要讲的JWT

这种架构的缺点:
JessionId和用户信息是绑定的,拿到JessionId就能拿到用户信息,一旦JessionId泄露了,别人就有可能CSRF跨域攻击你服务器

三、使用Cloud Gateway+Oauth2+JWT实现统一认证和鉴权

1、什么是JWT:

JWT(八股文):一个开放标准,它定义了一种用于简洁,自包含的用于通信双方之间以「JSON」对象的形式安全传递信息的方法.JWT可以使用「HMAC」算法或者是「RSA」 的公钥密钥对进行签名

简单来说,就是通过一定规范来生成token,然后可以通过解密算法逆向解密token,这样就可以获取用户信息

优点:
1)生产的token可以包含基本信息,比如id、用户昵称、头像等信息,避免再次查库
2)存储在客户端,不占用服务端的内存资源

缺点:
token是经过base64编码,所以可以解码,因此token加密前的对象不应该包含敏感信息,如用户权限,密码等

2、JWT格式组成 头部、负载、签名

header+payload+signature

  • 头部:主要是描述签名算法
  • 负载:主要描述是加密对象的信息,如用户的id等,也可以加些规范里面的东西,如iss签发者,exp 过期时间,sub 面向的用户
  • 签名:主要是把前面两部分进行加密,防止别人拿到token进行base解密后篡改token

3、关于jwt客户端存储

可以存储在cookie,localstorage和sessionStorage里面

4、实战案例

应用架构

我们理想的解决方案应该是这样的,认证服务负责认证,网关负责校验认证和鉴权,其他API服务负责处理自己的业务逻辑。安全相关的逻辑只存在于认证服务和网关服务中,其他服务只是单纯地提供服务而没有任何安全相关逻辑。

服务划分
  • oauth2-gateway:网关服务,负责请求转发和鉴权功能,整合Spring Security+Oauth2;
  • oauth2-auth:Oauth2认证服务,负责对登录用户进行认证,整合Spring Security+Oauth2;
  • oauth2-api:受保护的API服务,用户鉴权通过后可以访问该服务,不整合Spring Security+Oauth2。

如图:
SpringCloud微服务如何进行权限校验?

方案实现

下面介绍下这套解决方案的具体实现,依次搭建认证服务、网关服务和API服务。

oauth2-auth建认证服务
  • 结构图
    SpringCloud微服务如何进行权限校验?

  • 在pom.xml中添加相关依赖,主要是Spring Security、Oauth2、JWT、Redis相关依赖;

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>koo-oauth2-parent</artifactId>
        <groupId>com.koo</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>oauth2-auth</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.koo</groupId>
            <artifactId>oauth2-common</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
            <version>2.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.nimbusds</groupId>
            <artifactId>nimbus-jose-jwt</artifactId>
            <version>8.16</version>
        </dependency>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>
</project>
  • 在application.yml中添加相关配置,主要是Nacos和Redis相关配置;
server:
  port: 2111
spring:
  profiles:
    active: dev
  application:
    name: oauth2-auth
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
  redis:
    database: 1
    port: 6379
    host: localhost
    password:
management:
  endpoints:
    web:
      exposure:
        include: "*"
  • 使用keytool生成RSA证书jwt.jks,复制到resource目录下,在JDK的bin目录下使用如下命令即可;
keytool -genkey -alias jwt -keyalg RSA -keystore jwt.jks
  • 创建UserServiceImpl类实现Spring Security的UserDetailsService接口,用于加载用户信息;
@Service
public class UserServiceImpl implements UserDetailsService {
 
    private List<UserDTO> userList;
    @Autowired
    private PasswordEncoder passwordEncoder;
 
    @PostConstruct
    public void initData() {
        String password = passwordEncoder.encode("123456");
        userList = new ArrayList<>();
        userList.add(new UserDTO(1L,"macro", password, 1, CollUtil.toList("ADMIN")));
        userList.add(new UserDTO(2L,"andy", password, 1, CollUtil.toList("TEST")));
    }
 
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        List<UserDTO> findUserList = userList.stream().filter(item -> item.getUsername().equals(username)).collect(Collectors.toList());
        if (CollUtil.isEmpty(findUserList)) {
            throw new UsernameNotFoundException(MessageConstant.USERNAME_PASSWORD_ERROR);
        }
        SysUser sysUser = new SysUser(findUserList.get(0));
        if (!sysUser.isEnabled()) {
            throw new DisabledException(MessageConstant.ACCOUNT_DISABLED);
        } else if (!sysUser.isAccountNonLocked()) {
            throw new LockedException(MessageConstant.ACCOUNT_LOCKED);
        } else if (!sysUser.isAccountNonExpired()) {
            throw new AccountExpiredException(MessageConstant.ACCOUNT_EXPIRED);
        } else if (!sysUser.isCredentialsNonExpired()) {
            throw new CredentialsExpiredException(MessageConstant.CREDENTIALS_EXPIRED);
        }
        return sysUser;
    }
 
}
  • 如果你想往JWT中添加自定义信息的话,比如说登录用户的ID,可以自己实现TokenEnhancer接口;

@Component
public class JwtTokenEnhancer implements TokenEnhancer {
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        SysUser securityUser = (SysUser) authentication.getPrincipal();
        Map<String, Object> info = new HashMap<>();
        //把用户ID设置到JWT中
        info.put("id", securityUser.getId());
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
        return accessToken;
    }
}
  • 添加认证服务相关配置Oauth2ServerConfig,需要配置加载用户信息的服务UserServiceImpl及RSA的钥匙对KeyPair;

@AllArgsConstructor
@Configuration
@EnableAuthorizationServer
public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {
 
    private final PasswordEncoder passwordEncoder;
    private final UserServiceImpl userDetailsService;
    private final AuthenticationManager authenticationManager;
    private final JwtTokenEnhancer jwtTokenEnhancer;
 
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("client-app")
                .secret(passwordEncoder.encode("123456"))
                .scopes("all")
                .authorizedGrantTypes("password", "refresh_token")
                .accessTokenValiditySeconds(3600)
                .refreshTokenValiditySeconds(86400);
    }
 
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> delegates = new ArrayList<>();
        delegates.add(jwtTokenEnhancer); 
        delegates.add(accessTokenConverter());
        enhancerChain.setTokenEnhancers(delegates); //配置JWT的内容增强器
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService) //配置加载用户信息的服务
                .accessTokenConverter(accessTokenConverter())
                .tokenEnhancer(enhancerChain);
    }
 
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();
    }
 
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setKeyPair(keyPair());
        return jwtAccessTokenConverter;
    }
 
    @Bean
    public KeyPair keyPair() {
        //从classpath下的证书中获取秘钥对
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "123456".toCharArray());
        return keyStoreKeyFactory.getKeyPair("jwt", "123456".toCharArray());
    }
 
}
  • 配置Spring Security,允许获取公钥接口的访问;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
                .antMatchers("/rsa/publicKey").permitAll()
                .anyRequest().authenticated();
    }
 
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
 
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
 
}
  • 实体类
@Data
@NoArgsConstructor
public class SysUser implements UserDetails {

    private Long id;

    private String username;

    private String password;

    private UserDTO user;

    public SysUser(UserDTO user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    public boolean isEnabled() {
        return false;
    }
}

SpringCloud微服务如何进行权限校验?

oauth2-gateway网关

接下来我们就可以搭建网关服务了,它将作为Oauth2的资源服务、客户端服务使用,对访问微服务的请求进行统一的校验认证和鉴权操作。

  • 结构图
    SpringCloud微服务如何进行权限校验?

  • 在pom.xml中添加相关依赖,主要是Gateway、Oauth2和JWT相关依赖;

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>koo-oauth2-parent</artifactId>
        <groupId>com.koo</groupId>
        <version>1.0.0</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <artifactId>oauth2-gateway</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.koo</groupId>
            <artifactId>oauth2-common</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <version>2.2.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-resource-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-client</artifactId>
            <version>5.3.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-jose</artifactId>
            <version>5.3.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.nimbusds</groupId>
            <artifactId>nimbus-jose-jwt</artifactId>
            <version>8.16</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
        </dependency>
    </dependencies>

</project>
  • 在application.yml中添加相关配置,主要是路由规则的配置、Oauth2中RSA公钥的配置及路由白名单的配置;
server:
  port: 2112
spring:
  profiles:
    active: dev
  application:
    name: oauth2-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      routes: #配置路由规则
        - id: oauth2-api-route
          uri: lb://oauth2-api
          predicates:
            - Path=/api/**
          filters:
            - StripPrefix=1
        - id: oauth2-auth-route
          uri: lb://oauth2-auth
          predicates:
            - Path=/auth/**
          filters:
            - StripPrefix=1
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能
          lower-case-service-id: true #使用小写服务名,默认是大写
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: 'http://localhost:9401/rsa/publicKey' #配置RSA的公钥访问地址
  redis:
    database: 0
    port: 6379
    host: localhost
    password:
secure:
  ignore:
    urls: #配置白名单路径
      - "/actuator/**"
      - "/auth/oauth/
  • 对网关服务进行配置安全配置,由于Gateway使用的是WebFlux,所以需要使用@EnableWebFluxSecurity注解开启;

  • 在WebFluxSecurity中自定义鉴权操作需要实现ReactiveAuthorizationManager接口;

@Component
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
 
    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
        //从Redis中获取当前路径可访问角色列表
        URI uri = authorizationContext.getExchange().getRequest().getURI();
        Object obj = redisTemplate.opsForHash().get(RedisConstant.RESOURCE_ROLES_MAP, uri.getPath());
        List<String> authorities = Convert.toList(String.class,obj);
        authorities = authorities.stream().map(i -> i = AuthConstant.AUTHORITY_PREFIX + i).collect(Collectors.toList());
        //认证通过且角色匹配的用户可访问当前路径
        return mono
                .filter(Authentication::isAuthenticated)
                .flatMapIterable(Authentication::getAuthorities)
                .map(GrantedAuthority::getAuthority)
                .any(authorities::contains)
                .map(AuthorizationDecision::new)
                .defaultIfEmpty(new AuthorizationDecision(false));
    }
 
}
  • 这里我们还需要实现一个全局过滤器AuthGlobalFilter,当鉴权通过后将JWT令牌中的用户信息解析出来,然后存入请求的Header中,这样后续服务就不需要解析JWT令牌了,可以直接从请求的Header中获取到用户信息。
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
 
    private static Logger LOGGER = LoggerFactory.getLogger(AuthGlobalFilter.class);
 
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (StringUtils.isEmpty(token)) {
            return chain.filter(exchange);
        }
        try {
            //从token中解析用户信息并设置到Header中去
            String realToken = token.replace("Bearer ", "");
            JWSObject jwsObject = JWSObject.parse(realToken);
            String userStr = jwsObject.getPayload().toString();
            LOGGER.info("AuthGlobalFilter.filter() user:{}",userStr);
            ServerHttpRequest request = exchange.getRequest().mutate().header("user", userStr).build();
            exchange = exchange.mutate().request(request).build();
        } catch (java.text.ParseException e) {
            e.printStackTrace();
        }
        return chain.filter(exchange);
    }
 
    @Override
    public int getOrder() {
        return 0;
    }
}
  • 配置忽略路径
@Getter
@Setter
@ConfigurationProperties(prefix = "secure.ignored")
public class IgnoreUrlsConfig {
    private List<String> urls = new ArrayList<>();
}
  • 对拒绝访问时展现的信息进行处理
@Component
@Slf4j
public class JwtAccessDeniedHandler implements ServerAccessDeniedHandler {

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, AccessDeniedException e) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.FORBIDDEN);
        response.getHeaders().add("Content-Type", "application/json; charset=UTF-8");

        HashMap<String, String> map = new HashMap<>();
        map.put("code", "000000");
        map.put("message", "未授权禁止访问");

        log.error("access forbidden path={}", exchange.getRequest().getPath());

        DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONBytes(map));
        return response.writeWith(Mono.just(dataBuffer));
    }
}
  • 当为登录或者token无效时访问接口,自定义返回结果
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {

    @Override
    public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException e) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.FORBIDDEN);
        response.getHeaders().add("Content-Type", "application/json; charset=UTF-8");

        HashMap<String, String> map = new HashMap<>();
        map.put("code", "000000");
        map.put("message", "未授权禁止访问");

        log.error("access forbidden path={}", exchange.getRequest().getPath());

        DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONBytes(map));
        return response.writeWith(Mono.just(dataBuffer));
    }
}
oauth2-api 模块

最后我们搭建一个API服务,它不会集成和实现任何安全相关逻辑,全靠网关来保护它。

  • 结构图
    SpringCloud微服务如何进行权限校验?

  • 在pom.xml中添加相关依赖;

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>koo-oauth2-parent</artifactId>
        <groupId>com.koo</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>oauth2-api</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.koo</groupId>
            <artifactId>oauth2-common</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>
  • 在application.yml添加相关配置,很常规的配置;
server:
  port: 2113
spring:
  profiles:
    active: dev
  application:
    name: oauth2-api
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
management:
  endpoints:
    web:
      exposure:
        include: "*"
  • 创建一个测试接口,网关验证通过即可访问;
@RestController
public class HelloController {
 
    @GetMapping("/hello")
    public String hello() {
        return "Hello World.";
    }
 
}
  • 创建一个LoginUserHolder组件,用于从请求的Header中直接获取登录用户信息;
@Component
public class LoginUserHolder {
 
    public UserDTO getCurrentUser(){
        //从Header中获取用户信息
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String userStr = request.getHeader("user");
        JSONObject userJsonObject = new JSONObject(userStr);
        UserDTO userDTO = new UserDTO();
        userDTO.setUsername(userJsonObject.getStr("user_name"));
        userDTO.setId(Convert.toLong(userJsonObject.get("id")));
        userDTO.setRoles(Convert.toList(String.class,userJsonObject.get("authorities")));
        return userDTO;
    }
}
  • 创建一个获取当前用户信息的接口。
@RestController
@RequestMapping("/user")
public class UserController{
 
    @Autowired
    private LoginUserHolder loginUserHolder;
 
    @GetMapping("/currentUser")
    public UserDTO currentUser() {
        return loginUserHolder.getCurrentUser();
    }
 
}
oauth2-common公共模块
  • 结构图:
    SpringCloud微服务如何进行权限校验?

  • pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>koo-oauth2-parent</artifactId>
        <groupId>com.koo</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>oauth2-common</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.8</version>
        </dependency>
    </dependencies>
</project>
  • 常量
/**
 * @author charlin
 * @date 2023/5/3 13:00
 * @description
 */

public class MessageConstant {
    public static final String USERNAME_PASSWORD_ERROR = "用户密码错误";
    public static final String ACCOUNT_DISABLED = "账户禁用";
    public static final String ACCOUNT_LOCKED = "账户锁定";
    public static final String ACCOUNT_EXPIRED = "账户过期了";
    public static final String CREDENTIALS_EXPIRED = "认证过期";
}
public class RedisConstant {
    public static final String RESOURCE_ROLES_MAP = "resource_roles_map";
}
功能演示
  • 使用密码模式获取JWT令牌,访问地址:http://localhost:2111/auth/oauth/token
    SpringCloud微服务如何进行权限校验?

  • 使用获取到的JWT令牌访问需要权限的接口,访问地址:http://localhost:2113/api/hello
    SpringCloud微服务如何进行权限校验?

  • 使用获取到的JWT令牌访问获取当前登录用户信息的接口,访问地址:http://localhost:2113/api/user/currentUser
    SpringCloud微服务如何进行权限校验?

  • 当JWT令牌过期时,使用refresh_token获取新的JWT令牌,访问地址:http://localhost:2111/auth/oauth/token
    SpringCloud微服务如何进行权限校验?

  • 使用没有访问权限的andy账号登录,访问接口时会返回如下信息,访问地址:http://localhost:2113/api/hello
    SpringCloud微服务如何进行权限校验?

四、源码下载:

https://gitee.com/charlinchenlin/koo-erp文章来源地址https://www.toymoban.com/news/detail-500314.html

到了这里,关于SpringCloud微服务如何进行权限校验?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【SpringCloud Gateway】SpringCloud各微服务之间用户登录信息共享的实现思路——gateway网关token校验以及向微服务发送请求携带token

            最近在学习SpringCloud项目时,想到了一些问题,各个微服务分别部署在不同的服务上,由naocs作为注册中心实现负载均衡,彼此之间通过Feign相互调用通信,信息同步并不像单体项目那样方便,传统单体项目的登录验证方式似乎在SpringCloud中不能满足项目的需求。那么

    2024年02月05日
    浏览(19)
  • 【SpringCloud】一、微服务概述、注册中心与Ribbon负载均衡技术简介

    微服务治理 异步通信技术 — mq 缓存技术 — Redis 搜索技术 — ES集群 Devops — Jenkins… 微服务是一种将各个模块拆分开独立运行以提高系统整体效率的技术,其主要特征为: 单一职责:每个服务对应唯一的业务能力、做到单一职责。 面向服务:对外要暴露微服务的业务接口

    2024年02月09日
    浏览(26)
  • 引入短信服务发送手机验证码进行安全校验

    其他方案=引入QQ邮箱发送验证码进行安全校验 相对短信验证码,操作更简单而且免费 最近想给自己的项目在注册时加点安全校验,准备使用免费的邮箱验证来着,在上一篇引入QQ邮箱进行安全校验时,看有朋友说阿里云会送一些短信服务免费额度,于是去官网一看,果然送了

    2024年02月04日
    浏览(22)
  • SpringBoot 如何使用 @RequestBody 进行数据校验

    在 Web 开发中,前台向后台发送数据是非常常见的场景。而在 SpringBoot 框架中,我们通常使用 @RequestBody 注解来接收前台发送的 JSON 数据,并将其转化为 Java 对象。但是,接收到的数据并不一定是符合要求的,因此我们需要对其进行数据校验。本文将介绍如何在 SpringBoot 中使用

    2024年02月10日
    浏览(17)
  • 代码模版-element plus如何进行前端校验输入框

    使用 vue3 + element plus 先 npm 安装 在 src/main.js 中引入 可以拷贝官网:https://element-plus.org/zh-CN/component/form.html 这个 rules 是组件中 js 赋过来的,prop 表示用在了 rules 中,比如这个 account,表示规则对应的是哪个 prop 比如点击登录按钮触发 login 函数执行 最后我们什么都不输入点击

    2024年02月12日
    浏览(14)
  • 如何在Spring Boot中优雅地进行参数校验

    在平时的开发工作中,我们通常需要对接口进行参数格式验证。当参数个数较少(个数小于3)时,可以使用 if ... else ... 手动进行参数验证。当参数个数大于3个时,使用 if ... else ... 进行参数验证就会让代码显得臃肿,这个时候推荐使用注解来进行参数验证。 在Java中,注解

    2024年01月17日
    浏览(18)
  • SpringCloud微服务整合Spring Security进行统一鉴权

    网关gateway 普通资源微服务member 鉴权微服务auth 为了做到更灵活的方法级别的鉴权操作,决定将权限控制下放到具体的普通微服务,其实并不需要多配置很多东西。网关只负责转发请求,鉴权则是由auth认证微服务来完成的。 网上很多都是在网关层面进行鉴权,但是这么做不灵

    2024年02月04日
    浏览(17)
  • Java之SpringCloud Alibaba【五】【微服务 Sentinel整合openfeign进行降级】

    Java之SpringCloud Alibaba【一】【Nacos一篇文章精通系列】 跳转 Java之SpringCloud Alibaba【二】【微服务调用组件Feign】 跳转 Java之SpringCloud Alibaba【三】【微服务Nacos-config配置中心】 跳转 Java之SpringCloud Alibaba【四】【微服务 Sentinel服务熔断】 跳转 Java之SpringCloud Alibaba【五】【微服务

    2024年02月11日
    浏览(17)
  • 面对根据角色和单子状态如何有效的进行按钮权限的控制

    当阁下看到这个按钮权限控制时,该如何应对 问题1: 举个🌰,对于【待分配】这个工单状态的申请撤回按钮进行解析 问题2:举2个🌰对于【科室待接受】这个节点的申请撤回按钮进行解析 问题3:有些按钮 在多个节点要显示,比如【申请撤回、追加信息、催办】,像这种

    2024年01月19日
    浏览(15)
  • nginx在安装时使用root权限进行安装并启用,如何更改为普通用户权限运行nginx(亲测)

    目录 前言: 步骤一:先查询nginx相关信息 1、查询操作系统版本:cat /etc/redhat-release 2、查询nginx安装路径:如果不知道nginx安装目录,使用:find / -name nginx(全局查找nginx应用) 3、切换到nginx父目录下查看nginx目前所属主:所属组权限属于root还是普通用户 ?4、查看nginx当前启动

    2024年02月07日
    浏览(16)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包