SpringCloud+Nacos+Security+Vue单点登录记录

前言

最近把spring-cloud的注册中心改用了Nacos,顺便整合了一下spring-security,前端采用vue实现登录,废话不多说,开始了。

一、后端

1、nacos集成

a. 下载nacos。我是用的2.0版本以上

b. 解压,启动sh startup.sh -m standalone

c. http://localhost:8848/nacos/,账号nacos/nacos

d.pom依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

2、创建gateway集成security

SecurityConfig配置
SecurityWebFilterChain chain = http.formLogin()
        .loginPage("/login")
        // 登录成功handler
        .authenticationSuccessHandler(jsonServerAuthenticationSuccessHandler)
        // 登陆失败handler
        .authenticationFailureHandler(jsonServerAuthenticationFailureHandler)
        // 无访问权限handler
        .authenticationEntryPoint(serverAuthenticationEntryPoint)
        .and()
        .logout()
        // 登出成功handler
        .logoutSuccessHandler(jsonServerLogoutSuccessHandler)
        .and()
        .csrf().disable()
        .httpBasic().disable()
        .authorizeExchange()
        // 白名单放行
        .pathMatchers(AUTH_WHITELIST).permitAll()
        // 访问权限控制
        .anyExchange().access(authorizeConfigManager).and().build();
@Bean
ReactiveAuthenticationManager reactiveAuthenticationManager() {
    LinkedList<ReactiveAuthenticationManager> managers = new LinkedList<>();
    managers.add(authenticationManager);
    return new DelegatingReactiveAuthenticationManager(managers);
}

Api请求校验类

AuthorizeConfigManager
@Slf4j
@Component
public class AuthorizeConfigManager implements ReactiveAuthorizationManager<AuthorizationContext> {

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> authentication,
                                             AuthorizationContext authorizationContext) {
        boolean check = false;
        ServerWebExchange exchange = authorizationContext.getExchange();
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        Authentication authentication1=JwtTokenUtils.getAuthenticationeFromToken(request);
        if (null != authentication1) {
            for (GrantedAuthority authority : authentication1.getAuthorities()) {
                if (antPathMatcher.match(authority.getAuthority(), path)) {
                    log.info(String.format("用户请求API校验通过,GrantedAuthority:{%s}  Path:{%s} ", authority.getAuthority(), path));
                    check = true;
                }
            }
        }
        return Mono.just(new AuthorizationDecision(check));
    }

    @Override
    public Mono<Void> verify(Mono<Authentication> authentication, AuthorizationContext object) {
        return check(authentication, object)
                .filter(d -> d.isGranted())
                .switchIfEmpty(Mono.defer(() -> {

                    String body = ErrorCode.SYSTEM_ERROR.toString();
                    return Mono.error(new AccessDeniedException(body));
                }))
                .flatMap(d -> Mono.empty());
    }
}

登录成功类

JsonServerAuthenticationSuccessHandler
@Component
public class JsonServerAuthenticationSuccessHandler implements ServerAuthenticationSuccessHandler {

    @Override
    public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {
        // 登录成功后可以放入一些参数到session中
        ServerHttpResponse response = webFilterExchange.getExchange().getResponse();
        response.setStatusCode(HttpStatus.OK);
        // 系统登录认证
        String token = JwtTokenUtils.generateToken(authentication);
        response.getHeaders().set("token",token);



        response.getHeaders().set(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8");

        DataBuffer buffer = response.bufferFactory().wrap(
                ResultDataUtils.getResponse(ErrorCode.SUCCESS.getCode(),ErrorCode.SUCCESS.getMessage(),authentication.getAuthorities()).getBytes(CharsetUtil.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
}

获取用户信息类

public class UserInfoUtil {


    public static final String SECRET = "xxx";

        //用于子服务获取用户信息 
    public static String getUserName() throws GlobalException {

        return getUserName(((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("token"));
    }

//用于gateway获取用户信息
    public static String getUserName(String token) throws GlobalException {

        if (token != null) {
            if (isTokenExpired(token)) {
                throw new GlobalException(ErrorCode.EXPIRED);
            }
            Claims claims = getClaimsFromToken(token);
            if (claims == null) {
                return null;
            }
            String username = claims.getSubject();
            if (username == null) {
                return null;
            }
            return username;
        }
        return null;
    }

    public static Boolean isTokenExpired(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            Date expiration = claims.getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
            return true;
        }
    }

    public static Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }


}

二、前端

调用配置

export const login = data => axiosRequest.formdata('/login', data)

export function formdata(url, params = {}) {
    return new Promise((resolve, reject) => {
        httpService({
            url: url,
            method: 'post',
            data: params,
            transformRequest: [
                function (data) {
                    let ret = ''
                    for (let it in data) {
                        ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
                    }
                    ret = ret.substring(0, ret.lastIndexOf('&'));
                    return ret
                }
            ],
            headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
        }).then(response => {
            resolve(response)
        }).catch(error => {
            reject(error)
        })
    })
}

关键代码就是上面这些,还有其他的代码,下回有空再补吧。有需要的童鞋也可以一起讨论。~~其实是有点懒~~不想贴了.....

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud Nacos是一种基于Nacos的微服务架构中的服务发现和配置管理工具。它提供了服务注册与发现、服务健康监测、动态配置管理等功能,可以帮助我们更好地管理前端Vue项目的上线部署。 首先,我们需要在前端Vue项目中引入Spring Cloud Nacos的相关依赖。可以通过Maven或者Gradle方式引入,具体的依赖可以参考Spring Cloud Nacos的官方文档。 接下来,在前端Vue项目的配置文件中,我们需要指定Nacos服务的地址和端口号。这样前端项目就可以通过Nacos注册和发现相关的微服务。配置文件的具体内容如下所示: ``` nacos: server-addr: localhost:8848 ``` 然后,我们需要在前端Vue项目中编写相应的代码来获取Nacos中的配置信息。可以使用Nacos提供的Java SDK或者相关的RESTful接口来实现。通过动态配置管理的功能,我们可以在Nacos中配置前端Vue项目的一些运行参数,并实时获取这些配置信息。 最后,我们需要将前端Vue项目打包,并将打包后的文件部署到服务器上。可以使用Nginx等Web服务器来托管前端静态资源文件。部署过程中需要注意配置Nginx来正确地映射前端Vue项目的访问路径。 总结来说,通过引入Spring Cloud Nacos的依赖,配置Nacos的地址和端口号,编写相关代码来获取Nacos中的配置信息,并将前端Vue项目打包部署到服务器上,我们就可以实现前端Vue项目的上线部署。这样可以更好地管理和配置前端项目,提高项目的可维护性和灵活性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值