SpringCloud gateway+Spring Security + JWT实现登录和用户权限校验

这篇具有很好参考价值的文章主要介绍了SpringCloud gateway+Spring Security + JWT实现登录和用户权限校验。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言

原本打算将Security模块与gateway模块分开写的,但想到gateway本来就有过滤的作用 ,于是就把gateway和Security结合在一起了,然后结合JWT令牌对用户身份和权限进行校验。

Spring Cloud的网关与传统的SpringMVC不同,gateway是基于Netty容器,采用的webflux技术,所以gateway模块不能引入spring web包。虽然是不同,但是在SpringMVC模式下的Security实现步骤和流程都差不多。

依赖

Spring  cloud gateway模块依赖

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!--JWT的依赖-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>

代码基本结构

springcloudgateway权限验证,spring,spring cloud,gateway,后端,java-ee

认证执行流程

一、Token工具类

public class JWTUtils {
    private final static String SING="XIAOYUAN";
    public static String creatToken(Map<String,String> payload,int expireTime){
        JWTCreator.Builder builder= JWT.create();
        Calendar instance=Calendar.getInstance();//获取日历对象
        if(expireTime <=0)
        instance.add(Calendar.SECOND,3600);//默认一小时
        else
            instance.add(Calendar.SECOND,expireTime);
        //为了方便只放入了一种类型
        payload.forEach(builder::withClaim);
        return builder.withExpiresAt(instance.getTime()).sign(Algorithm.HMAC256(SING));
    }
    public static Map<String, Object> getTokenInfo(String token){
        DecodedJWT verify = JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
        Map<String, Claim> claims = verify.getClaims();
        SimpleDateFormat dateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String expired= dateTime.format(verify.getExpiresAt());
        Map<String,Object> m=new HashMap<>();
        claims.forEach((k,v)-> m.put(k,v.asString()));
        m.put("exp",expired);
        return m;

    }
}

二、自定义User并且实现Spring Security的User接口,以及实现UserDetail接口

 
public class SecurityUserDetails extends User implements Serializable {

    private Long userId;

    public SecurityUserDetails(String username, String password, Collection<? extends GrantedAuthority> authorities, Long userId) {
        super(username, password, authorities);
        this.userId = userId;
    }

    public SecurityUserDetails(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities, Long userId) {
        super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
        this.userId = userId;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }
}

@Component("securityUserDetailsService")
@Slf4j
public class SecurityUserDetailsService implements ReactiveUserDetailsService {
    private final PasswordEncoder passwordEncoder= new BCryptPasswordEncoder();;
    @Override
    public Mono<UserDetails> findByUsername(String username) {
        //调用数据库根据用户名获取用户
        log.info(username);
        if(!username.equals("admin")&&!username.equals("user"))
                throw new UsernameNotFoundException("username error");
        else {
            Collection<GrantedAuthority> authorities = new ArrayList<>();
            if (username.equals("admin"))
            authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));//ROLE_ADMIN
            if (username.equals("user"))
                authorities.add(new SimpleGrantedAuthority("ROLE_USER"));//ROLE_ADMIN
            SecurityUserDetails securityUserDetails = new SecurityUserDetails(username,"{bcrypt}"+passwordEncoder.encode("123"),authorities,1L);
            return Mono.just(securityUserDetails);
        }

    }
}

这里我为了方便测试,只设置了两个用户,admin和晢user,用户角色也只有一种。

二、AuthenticationSuccessHandler,定义认证成功类

@Component
@Slf4j
public class AuthenticationSuccessHandler extends WebFilterChainServerAuthenticationSuccessHandler {
    @Value("${login.timeout}")
    private int timeout=3600;//默认一小时
    private final int rememberMe=180;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @SneakyThrows
    @Override
    public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {
        ServerWebExchange exchange = webFilterExchange.getExchange();
        ServerHttpResponse response = exchange.getResponse();
        //设置headers
        HttpHeaders httpHeaders = response.getHeaders();
        httpHeaders.add("Content-Type", "application/json; charset=UTF-8");
        httpHeaders.add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
        //设置body
        HashMap<String, String> map = new HashMap<>();
        String remember_me=exchange.getRequest().getHeaders().getFirst("Remember-me");

        ObjectMapper mapper = new ObjectMapper();
        List<? extends GrantedAuthority> list=authentication.getAuthorities().stream().toList();
          try {
            Map<String, String> load = new HashMap<>();
            load.put("username",authentication.getName());
            load.put("role",list.get(0).getAuthority());//这里只添加了一种角色 实际上用户可以有不同的角色类型
            String token;
            log.info(authentication.toString());
            if (remember_me==null) {
                token=JWTUtils.creatToken(load,3600*24);
                response.addCookie(ResponseCookie.from("token", token).path("/").build());
                //maxAge默认-1 浏览器关闭cookie失效
                redisTemplate.opsForValue().set(authentication.getName(), token, 1, TimeUnit.DAYS);
            }else {
                token=JWTUtils.creatToken(load,3600*24*180);
                response.addCookie(ResponseCookie.from("token", token).maxAge(Duration.ofDays(rememberMe)).path("/").build());
                redisTemplate.opsForValue().set(authentication.getName(), token, rememberMe, TimeUnit.SECONDS);//保存180天
            }

            map.put("code", "000220");
            map.put("message", "登录成功");
            map.put("token",token);
        } catch (Exception ex) {
            ex.printStackTrace();
              map.put("code", "000440");
            map.put("message","登录失败");
        }
        DataBuffer bodyDataBuffer = response.bufferFactory().wrap(mapper.writeValueAsBytes(map));
        return response.writeWith(Mono.just(bodyDataBuffer));
    }
    
}

当用户认证成功的时候就会调用这个类,这里我将token作为cookie返回客户端,当客服端请求接口的时候将带上Cookie,然后gateway在认证之前拦截,然后将Cookie写入Http请求头中,后面的授权在请求头中获取token。(这里我使用的cookie来保存token,当然也可以保存在localStorage里,每次请求的headers里面带上token)

这里还实现了一个记住用户登录的功能,原本是打算读取请求头中的表单数据的Remember-me字段来判断是否记住用户登录状态,但是这里有一个问题,在获取请求的表单数据的时候一直为空,因为Webflux中请求体中的数据只能被读取一次,如果读取了就需要重新封装,前面在进行用户认证的时候已经读取过了请求体导致后面就读取不了(只是猜测,因为刚学习gateway还不是很了解,在网上查了很多资料一直没有解决这个问题),于是我用了另一个方法,需要记住用户登录状态的时候(Remember-me),我就在前端请求的时候往Http请求头加一个Remember-me字段,然后后端判断有没有这个字段,没有的话就不记住。

三、AuthenticationFaillHandler  ,认证失败类

@Slf4j
@Component
public class AuthenticationFaillHandler  implements ServerAuthenticationFailureHandler {

    @SneakyThrows
    @Override
    public Mono<Void> onAuthenticationFailure(WebFilterExchange webFilterExchange, AuthenticationException e) {
        ServerHttpResponse response = webFilterExchange.getExchange().getResponse();
        response.setStatusCode(HttpStatus.FORBIDDEN);
        response.getHeaders().add("Content-Type", "application/json; charset=UTF-8");
        HashMap<String, String> map = new HashMap<>();
        map.put("code", "000400");
        map.put("message", e.getMessage());
        log.error("access forbidden path={}", webFilterExchange.getExchange().getRequest().getPath());
        ObjectMapper objectMapper = new ObjectMapper();
        DataBuffer dataBuffer = response.bufferFactory().wrap(objectMapper.writeValueAsBytes(map));
        return response.writeWith(Mono.just(dataBuffer));
    }
}

四、SecurityRepository ,用户信息上下文存储类

@Slf4j
@Component
public class SecurityRepository implements ServerSecurityContextRepository {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public Mono<Void> save(ServerWebExchange exchange, SecurityContext context) {
        return Mono.empty();
    }

    @Override
    public Mono<SecurityContext> load(ServerWebExchange exchange) {
        String token = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        log.info(token);
        if (token != null) {
            try {
                Map<String,Object> userMap= JWTUtils.getTokenInfo(token);
                String result=(String)redisTemplate.opsForValue().get(userMap.get("username"));
                if (result==null || !result.equals(token))
                    return Mono.empty();
                SecurityContext emptyContext = SecurityContextHolder.createEmptyContext();
                Collection<SimpleGrantedAuthority> authorities=new ArrayList<>();
                log.info((String) userMap.get("role"));
                authorities.add(new SimpleGrantedAuthority((String) userMap.get("role")));
                Authentication authentication=new UsernamePasswordAuthenticationToken(null, null,authorities);
                emptyContext.setAuthentication(authentication);
                return Mono.just(emptyContext);
            }catch (Exception e) {
                return Mono.empty();
            }
        }
        return Mono.empty();
    }
}

当客户端访问服务接口的时候,如果是有效token,那么就根据token来判断用户权限,实现ServerSecurityContextRepository 类的主要目的是实现load方法,这个方法实际上是传递一个Authentication对象供后面ReactiveAuthorizationManager<AuthorizationContext>来判断用户权限。我这里只传递了用户的role信息,所以就没有去实现ReactiveAuthorizationManager这个接口了。

Security框架默认提供了两个ServerSecurityContextRepository实现类,WebSessionServerSecurityContextRepository和NoOpServerSecurityContextRepository,Security默认使用WebSessionServerSecurityContextRepository,这个是使用session来保存用户登录状态的,NoOpServerSecurityContextRepository是无状态的。

五、AuthenticationEntryPoint ,接口认证入口类

如果客户端没有认证授权就直接访问服务接口,然后就会调用这个类,返回的状态码是401


@Slf4j
@Component
public class AuthenticationEntryPoint extends HttpBasicServerAuthenticationEntryPoint {
    @SneakyThrows
    @Override
    public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException e) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json; charset=UTF-8");
        HashMap<String, String> map = new HashMap<>();
        map.put("status", "00401");
        map.put("message", "未登录");
        ObjectMapper objectMapper = new ObjectMapper();
        DataBuffer bodyDataBuffer = response.bufferFactory().wrap(objectMapper.writeValueAsBytes(map));
        return response.writeWith(Mono.just(bodyDataBuffer));
    }
}

六、AccessDeniedHandler ,授权失败处理类

当访问服务接口的用户权限不够时会调用这个类,返回HTTP状态码是403

@Slf4j
@Component
public class AccessDeniedHandler implements ServerAccessDeniedHandler {
    @SneakyThrows
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, AccessDeniedException denied) {
        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", "000403");
        map.put("message", "未授权禁止访问");
        log.error("access forbidden path={}", exchange.getRequest().getPath());
        ObjectMapper objectMapper = new ObjectMapper();
        DataBuffer dataBuffer = response.bufferFactory().wrap(objectMapper.writeValueAsBytes(map));
        return response.writeWith(Mono.just(dataBuffer));
    }
}

七、AuthorizationManager ,鉴权管理类

@Slf4j
@Component
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, AuthorizationContext authorizationContext) {
        return authentication.map(auth -> {
            //SecurityUserDetails userSecurity = (SecurityUserDetails) auth.getPrincipal();
            String path=authorizationContext.getExchange().getRequest().getURI().getPath();
            for (GrantedAuthority authority : auth.getAuthorities()){
                if (authority.getAuthority().equals("ROLE_USER")&&path.contains("/user/normal"))
                    return new AuthorizationDecision(true);
                else if (authority.getAuthority().equals("ROLE_ADMIN")&&path.contains("/user/admin"))
                    return new AuthorizationDecision(true);
//对客户端访问路径与用户角色进行匹配
            }
            return new AuthorizationDecision(false);
        }).defaultIfEmpty(new AuthorizationDecision(false));
    }
}

返回new AuthorizationDecision(true)代表授予权限访问服务,为false则是拒绝。

八、LogoutHandler,LogoutSuccessHandler 登出处理类

@Component
@Slf4j
public class LogoutHandler implements ServerLogoutHandler {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Override
    public Mono<Void> logout(WebFilterExchange webFilterExchange, Authentication authentication) {
        HttpCookie cookie=webFilterExchange.getExchange().getRequest().getCookies().getFirst("token");
        try {
            if (cookie != null) {
                Map<String,Object> userMap= JWTUtils.getTokenInfo(cookie.getValue());
                redisTemplate.delete((String) userMap.get("username"));
            }
        }catch (JWTDecodeException e) {
           return Mono.error(e);
        }

        return Mono.empty();
    }
}
@Component
public class LogoutSuccessHandler implements ServerLogoutSuccessHandler {
    @SneakyThrows
    @Override
    public Mono<Void> onLogoutSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {
        ServerHttpResponse response = webFilterExchange.getExchange().getResponse();
        //设置headers
        HttpHeaders httpHeaders = response.getHeaders();
        httpHeaders.add("Content-Type", "application/json; charset=UTF-8");
        httpHeaders.add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
        //设置body
        HashMap<String, String> map = new HashMap<>();
        //删除token
        response.addCookie(ResponseCookie.from("token", "logout").maxAge(0).path("/").build());
        map.put("code", "000220");
        map.put("message", "退出登录成功");
        ObjectMapper mapper = new ObjectMapper();
        DataBuffer bodyDataBuffer = response.bufferFactory().wrap(mapper.writeValueAsBytes(map));
        return response.writeWith(Mono.just(bodyDataBuffer));
    }
}

九、CookieToHeadersFilter ,将Cookie写入Http请求头中

@Slf4j
@Component
public class CookieToHeadersFilter implements WebFilter{
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        try {

            HttpCookie cookie=exchange.getRequest().getCookies().getFirst("token");
            if (cookie != null) {
                String token = cookie.getValue();
                ServerHttpRequest request=exchange.getRequest().mutate().header(HttpHeaders.AUTHORIZATION,token).build();
                return chain.filter(exchange.mutate().request(request).build());
            }
        }catch (NoFoundToken e) {
            log.error(e.getMsg());
        }

        return chain.filter(exchange);

    }

}

这里需要注意的是,如果要想在认证前后过滤Http请求,用全局过滤器或者局部过滤器是不起作用的,因为它们总是在鉴权通过后执行,也就是它们的执行顺序始终再Security过滤器之后,无论order值多大多小。这时候必须实现的接口是WebFilter而不是GlobalFilter或者GatewayFilter,然后将接口实现类添加到WebSecurityConfig配置中心去。

十、WebSecurityConfig,配置类

@EnableWebFluxSecurity
@Configuration
@Slf4j
public class WebSecurityConfig {
    @Autowired
    SecurityUserDetailsService securityUserDetailsService;
    @Autowired
    AuthorizationManager authorizationManager;
    @Autowired
    AccessDeniedHandler accessDeniedHandler;
    @Autowired
    AuthenticationSuccessHandler authenticationSuccessHandler;
    @Autowired
    AuthenticationFaillHandler authenticationFaillHandler;
    @Autowired
    SecurityRepository securityRepository;
    @Autowired
    CookieToHeadersFilter cookieToHeadersFilter;
    @Autowired
    LogoutSuccessHandler logoutSuccessHandler;
    @Autowired
    LogoutHandler logoutHandler;

    @Autowired
    com.example.gateway.security.AuthenticationEntryPoint authenticationEntryPoint;
    private final String[] path={
            "/favicon.ico",
            "/book/**",
            "/user/login.html",
            "/user/__MACOSX/**",
            "/user/css/**",
            "/user/fonts/**",
            "/user/images/**"};
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http.addFilterBefore(cookieToHeadersFilter, SecurityWebFiltersOrder.HTTP_HEADERS_WRITER);
        //SecurityWebFiltersOrder枚举类定义了执行次序
        http.authorizeExchange(exchange -> exchange // 请求拦截处理
                                .pathMatchers(path).permitAll()
                                .pathMatchers(HttpMethod.OPTIONS).permitAll()
                                .anyExchange().access(authorizationManager)//权限
                        //.and().authorizeExchange().pathMatchers("/user/normal/**").hasRole("ROLE_USER")
                        //.and().authorizeExchange().pathMatchers("/user/admin/**").hasRole("ROLE_ADMIN")
                        //也可以这样写 将匹配路径和角色权限写在一起
                )
                .httpBasic()
                .and()
                .formLogin().loginPage("/user/login")//登录接口
                .authenticationSuccessHandler(authenticationSuccessHandler) //认证成功
                .authenticationFailureHandler(authenticationFaillHandler) //登陆验证失败
                .and().exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler)//基于http的接口请求鉴权失败
                .and().csrf().disable()//必须支持跨域
                .logout().logoutUrl("/user/logout")
                .logoutHandler(logoutHandler)
                .logoutSuccessHandler(logoutSuccessHandler);
        http.securityContextRepository(securityRepository);
        //http.securityContextRepository(NoOpServerSecurityContextRepository.getInstance());//无状态 默认情况下使用的WebSession
        return http.build();
    }

    @Bean
    public ReactiveAuthenticationManager reactiveAuthenticationManager() {
        LinkedList<ReactiveAuthenticationManager> managers = new LinkedList<>();
        managers.add(authentication -> {
            // 其他登陆方式
            return Mono.empty();
        });
        managers.add(new UserDetailsRepositoryReactiveAuthenticationManager(securityUserDetailsService));
        return new DelegatingReactiveAuthenticationManager(managers);
    }

}




十一、测试

首先没有登录访问服务

springcloudgateway权限验证,spring,spring cloud,gateway,后端,java-ee

然后登录 

springcloudgateway权限验证,spring,spring cloud,gateway,后端,java-ee

访问服务

springcloudgateway权限验证,spring,spring cloud,gateway,后端,java-ee

访问另一个接口

springcloudgateway权限验证,spring,spring cloud,gateway,后端,java-ee文章来源地址https://www.toymoban.com/news/detail-779929.html

到了这里,关于SpringCloud gateway+Spring Security + JWT实现登录和用户权限校验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Java开发 - 单点登录初体验(Spring Security + JWT)

    目录 ​​​​​​​ 前言 为什么要登录 登录的种类 Cookie-Session Cookie-Session-local storage JWT令牌 几种登陆总结  用户身份认证与授权 创建工程 添加依赖 启动项目 Bcrypt算法的工具 创建VO模型类 创建接口文件 创建XML文件 补充配置 添加依赖 添加配置 创建配置类 测试上面的配置

    2024年02月02日
    浏览(32)
  • spring boot中常用的安全框架 Security框架 利用Security框架实现用户登录验证token和用户授权(接口权限控制)

    spring boot中常用的安全框架 Security 和 Shiro 框架 Security 两大核心功能 认证 和 授权 重量级 Shiro 轻量级框架 不限于web 开发 在不使用安全框架的时候 一般我们利用过滤器和 aop自己实现 权限验证 用户登录 Security 实现逻辑 输入用户名和密码 提交 把提交用户名和密码封装对象

    2024年02月06日
    浏览(35)
  • SpringCloud搭建微服务之Gateway+Jwt实现统一鉴权

    在微服务项目中,需要对整个微服务系统进行权限校验,通常有两种方案,其一是每个微服务各自鉴权,其二是在网关统一鉴权,第二种方案只需要一次鉴权就行,避免了每个微服务重复鉴权的麻烦,本文以网关统一鉴权为例介绍如何搭建微服务鉴权项目。 本文案例中共有四

    2024年02月13日
    浏览(29)
  • Spring Security登录用户数据获取(4)

    登录成功之后,在后续的业务逻辑中,开发者可能还需要获取登录成功的用户对象,如果不使用任何安全管理框架,那么可以将用户信息保存在HttpSession中,以后需要的时候直接从HttpSession中获取数据。在Spring Security中,用户登录信息本质上还是保存在 HttpSession中,但是为了方

    2024年02月03日
    浏览(35)
  • Spring Gateway使用JWT实现统一身份认证

    在开发集群式或分布式服务时,鉴权是最重要的一步,为了方便对请求统一鉴权,一般都是会放在网关中进行处理。目前非常流行的一种方案是使用JWT,详细的使用说明,可以找相关的资料查阅,这里先不进行深入的引用了。主要使用它下面的特性: 它的数据使用JSON格式封

    2024年02月12日
    浏览(23)
  • 【深入浅出 Spring Security(四)】登录用户数据的获取,超详细的源码分析

    在【深入浅出Spring Security(一)】Spring Security的整体架构 中叙述过一个SecurityContextHolder 这个类。说在处理请求时,Spring Security 会先从 Session 中取出用户登录数据,保存到 SecurityContextHolder 中,然后在请求处理完毕后,又会拿 SecurityContextHolder 中的数据保存到 Session 中,然后再

    2024年02月07日
    浏览(26)
  • 基于SpringCloud + Oauth2.0 + ShiroRedis + JWT + Gateway + Nacos + Nginx + Vue实现的SaaS数字商城系统

    SaaS的英文全称是Software as a Service,意思是软件即服务 ,是云计算的其中一种服务模式 SaaS是一种通过Internet提供集中托管应用程序的方式,企业用户一般通过客户端或网页来使用,无需购买、安装或维护任何软件及硬件,因此 SaaS应用程序又被称为\\\"基于Web的软件\\\" 或 \\\"托管软件

    2024年01月20日
    浏览(35)
  • Spring Gateway+Security+OAuth2+RBAC 实现SSO统一认证平台

    背景:新项目准备用SSO来整合之前多个项目的登录和权限,同时引入网关来做后续的服务限流之类的操作,所以搭建了下面这个系统雏形。 : Spring Gateway, Spring Security, JWT, OAuth2, Nacos, Redis, Danymic datasource, Javax, thymeleaf 如果对上面这些技术感兴趣,可以继续往下阅读 如

    2024年02月13日
    浏览(34)
  • SpringCloud整合spring security+ oauth2+Redis实现认证授权

    在微服务构建中,我们一般用一个父工程来通知管理依赖的各种版本号信息。父工程pom文件如下: 在SpringCloud微服务体系中服务注册中心是一个必要的存在,通过注册中心提供服务的注册和发现。具体细节可以查看我之前的博客,这里不再赘述。我们开始构建一个eureka注册中

    2024年02月06日
    浏览(41)
  • Spring-Security实现登录接口

    Security 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架 Shiro ,它提供了更丰富的功能,社区资源也比Shiro丰富。 具体介绍和入门看springSecurity入门 在实现之前幺要了解一下登录校验的流程以及 SpringSecurity 的原理以及认证流程 1、登录校验流程 2、 SpringSecurity完

    2024年01月18日
    浏览(34)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包