hello 各位小伙伴,国庆节终于过完啦,松哥也回来啦,今天开始咱们继续发干货!

关于 Spring Security,松哥之前发过多篇文章和大家聊聊这个安全框架的使用:

  1. 手把手带你入门 Spring Security!
  2. Spring Security 登录添加验证码
  3. SpringSecurity 登录使用 JSON 格式数据
  4. Spring Security 中的角色继承问题
  5. Spring Security 中使用 JWT!
  6. Spring Security 结合 OAuth2

不过,今天要和小伙伴们聊一聊 Spring Security 中的另外一个问题,那就是在 Spring Security 中未获认证的请求默认会重定向到登录页,但是在前后端分离的登录中,这个默认行为则显得非常不合适,今天我们主要来看看如何实现未获认证的请求直接返回 JSON ,而不是重定向到登录页面。

前置知识

这里关于 Spring Security 的基本用法我就不再赘述了,如果小伙伴们不了解,可以参考上面的 6 篇文章。

大家知道,在自定义 Spring Security 配置的时候,有这样几个属性:

@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.formLogin()
.loginProcessingUrl("/doLogin")
.loginPage("/login")
//其他配置
.permitAll()
.and()
.csrf().disable();
}

这里有两个比较重要的属性:

  • loginProcessingUrl:这个表示配置处理登录请求的接口地址,例如你是表单登录,那么 form 表单中 action 的值就是这里填的值。
  • loginPage:这个表示登录页的地址,例如当你访问一个需要登录后才能访问的资源时,系统就会自动给你通过重定向跳转到这个页面上来。

这种配置在前后端不分的登录中是没有问题的,在前后端分离的登录中,这种配置就有问题了。我举个简单的例子,例如我想访问 /hello 接口,但是这个接口需要登录之后才能访问,我现在没有登录就直接去访问这个接口了,那么系统会给我返回 302,让我去登录页面,在前后端分离中,我的后端一般是没有登录页面的,就是一个提示 JSON,例如下面这样:

@GetMapping("/login")
public RespBean login() {
return RespBean.error("尚未登录,请登录!");
}

完整代码大家可以参考我的微人事项目。

也就是说,当我没有登录直接去访问 /hello 这个接口的时候,我会看到上面这段 JSON 字符串。在前后端分离开发中,这个看起来没问题(后端不再做页面跳转,无论发生什么都是返回 JSON)。但是问题就出在这里,系统默认的跳转是一个重定向,就是说当你访问 /hello 的时候,服务端会给浏览器返回 302,同时响应头中有一个 Location 字段,它的值为 http://localhost:8081/login ,也就是告诉浏览器你去访问 http://localhost:8081/login 地址吧。浏览器收到指令之后,就会直接去访问 http://localhost:8081/login 地址,如果此时是开发环境并且请求还是 Ajax 请求,就会发生跨域。因为前后端分离开发中,前端我们一般在 NodeJS 上启动,然后前端的所有请求通过 NodeJS 做请求转发,现在服务端直接把请求地址告诉浏览器了,浏览器就会直接去访问 http://localhost:8081/login 了,而不会做请求转发了,因此就发生了跨域问题。

解决方案

很明显,上面的问题我们不能用跨域的思路来解决,虽然这种方式看起来也能解决问题,但不是最佳方案。

如果我们的 Spring Security 在用户未获认证的时候去请求一个需要认证后才能请求的数据,此时不给用户重定向,而是直接就返回一个 JSON,告诉用户这个请求需要认证之后才能发起,就不会有上面的事情了。

这里就涉及到 Spring Security 中的一个接口 AuthenticationEntryPoint ,该接口有一个实现类:LoginUrlAuthenticationEntryPoint ,该类中有一个方法 commence,如下:

/**
* Performs the redirect (or forward) to the login form URL.
*/
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) {
String redirectUrl = null;
if (useForward) {
if (forceHttps && "http".equals(request.getScheme())) {
redirectUrl = buildHttpsRedirectUrlForRequest(request);
}
if (redirectUrl == null) {
String loginForm = determineUrlToUseForThisRequest(request, response,
authException);
if (logger.isDebugEnabled()) {
logger.debug("Server side forward to: " + loginForm);
}
RequestDispatcher dispatcher = request.getRequestDispatcher(loginForm);
dispatcher.forward(request, response);
return;
}
}
else {
redirectUrl = buildRedirectUrlToLoginPage(request, response, authException);
}
redirectStrategy.sendRedirect(request, response, redirectUrl);
}

首先我们从这个方法的注释中就可以看出,这个方法是用来决定到底是要重定向还是要 forward,通过 Debug 追踪,我们发现默认情况下 useForward 的值为 false,所以请求走进了重定向。

那么我们解决问题的思路很简单,直接重写这个方法,在方法中返回 JSON 即可,不再做重定向操作,具体配置如下:

@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.formLogin()
.loginProcessingUrl("/doLogin")
.loginPage("/login")
//其他配置
.permitAll()
.and()
.csrf().disable().exceptionHandling()
.authenticationEntryPoint(new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException authException) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
RespBean respBean = RespBean.error("访问失败!");
if (authException instanceof InsufficientAuthenticationException) {
respBean.setMsg("请求失败,请联系管理员!");
}
out.write(new ObjectMapper().writeValueAsString(respBean));
out.flush();
out.close();
}
});
}

在 Spring Security 的配置中加上自定义的 AuthenticationEntryPoint 处理方法,该方法中直接返回相应的 JSON 提示即可。这样,如果用户再去直接访问一个需要认证之后才可以访问的请求,就不会发生重定向操作了,服务端会直接给浏览器一个 JSON 提示,浏览器收到 JSON 之后,该干嘛干嘛。

结语

好了,一个小小的重定向问题和小伙伴们分享下,不知道大家有没有看懂呢?这也是我最近在重构微人事的时候遇到的问题。预计 11 月份,微人事的 Spring Boot 版本会升级到目前最新版,请小伙伴们留意哦。

关注公众号【江南一点雨】,专注于 Spring Boot+微服务以及前后端分离等全栈技术,定期视频教程分享,关注后回复 Java ,领取松哥为你精心准备的 Java 干货!

Spring Security 前后端分离登录,非法请求直接返回 JSON的更多相关文章

  1. 七:Spring Security 前后端分离登录,非法请求直接返回 JSON

    Spring Security 前后端分离登录,非法请求直接返回 JSON 解决方案 在 Spring Security 中未获认证的请求默认会重定向到登录页,但是在前后端分离的登录中,这个默认行为则 ...

  2. vue + spring boot + spring security 前后端分离 携带 Cookie 登录实现 只写了个登录

    最近想弄一下vue 所以就自己给自己找坑入   结果弄的满身是伤 哈哈哈 首先我说下 前后端分离  跨域请求  我在网上找了一些  可是都是针对于 spring boot 的 我自己还有 securi ...

  3. spring boot + spring security +前后端分离【跨域】配置 + ajax的json传输数据

    1.前言 网上各个社区的博客参差不齐 ,给初学者很大的困扰 , 我琢磨了一天一夜,到各个社区找资料,然后不断测试,遇到各种坑,一言难尽啊,要么源码只有一部分,要么直接报错... 最后实在不行,直接去看 ...

  4. 八个开源的 Spring Boot 前后端分离项目,一定要收藏!

    八个开源的 Spring Boot 前后端分离项目 最近前后端分离已经在慢慢走进各公司的技术栈,不少公司都已经切换到这个技术栈上面了.即使贵司目前没有切换到这个技术栈上面,我们也非常建议大家学习一下前 ...

  5. Spring Cloud 前后端分离后引起的跨域访问解决方案

    背景 Spring Cloud 微服务试点改造,目前在尝试前后端分离. 前台A应用(本机8080端口),通过网管(本机8769端口)调用后台应用B(本机8082端口).应用C发布的http服务.. A ...

  6. beego 前后端分离登录验证

    conf>app.conf 文件添加一下参数 copyrequestbody=true sessionon =true routers>router.go 文件添加初始化路由 func i ...

  7. Django前后端分离跨域请求问题

    一.问题背景 之前使用django+vue进行前后端分离碰到跨域请求问题,跨域(域名或者端口不同)请求问题的本质是由于浏览器的同源策略导致的,当请求的响应不是处于同一个域名和端口下,浏览器不会接受响应 ...

  8. 谈谈渲染,玩玩nginx——前后端分离,转发请求到Tomcat的尝试

    一.谈谈"渲染" 相信好多人都挺听过"渲染"这个词,但不清楚它是什么意思?前端开发以为这是后端的活儿,后端开发以为是前端的事儿,推着推着就不了了之.其实渲染很简 ...

  9. 七个开源的 Spring Boot 前后端分离项目,一定要收藏!

    前后端分离已经在慢慢走进各公司的技术栈,根据松哥了解到的消息,不少公司都已经切换到这个技术栈上面了.即使贵司目前没有切换到这个技术栈上面,松哥也非常建议大家学习一下前后端分离开发,以免在公司干了两三年 ...

随机推荐

  1. D-Distance_2019牛客暑期多校训练营(第八场)

    题目链接 Distance 题意 1<=nmh,q<=1e5 q个操作 1 x y z往坐标里加入一个点 2 x y z查询距离该点最近的点的距离(曼哈顿距离) 题解 做法一 将要插入的点 ...

  2. CFdiv2 165E. Compatible Numbers 子集枚举

    传送门 题意: 给出一个序列,输出每个数x对应的一个ans,要求ans在数列中,并且ans & x  = 0:数列的每个数小于(4e6) 思路: 这道题的方向比较难想.想到了就比较轻松了,可以 ...

  3. POJ - 3660 Cow Contest 传递闭包floyed算法

    Cow Contest POJ - 3660 :http://poj.org/problem?id=3660   参考:https://www.cnblogs.com/kuangbin/p/31408 ...

  4. lightoj 1119 - Pimp My Ride(状压dp)

    题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1119 题解:状压dp存一下车有没有被搞过的状态就行. #include < ...

  5. 江苏 徐州邀请赛 icpc B Array dp 滚动数组模板

    题目 题目描述 JSZKC is the captain of the lala team. There are N girls in the lala team. And their height ...

  6. 不权威的国产CPU发展历程

    最近进行了一些国产化相关工作 趁着周末有时间,自己整理一下这段时间的学习内容. 毕竟不是处理器和芯片的业内人士,里面多有纰漏,请谅解. 希望可以作为入门学习的简单知识. 1.0 远古时代 unix 世 ...

  7. 不要小看小小的 emoji 表情

    前言 好久没更新了,最近事比较多,或许下个月就会恢复到正常的发文频次. 这篇文章得从一个 emoji 表情开始,我之前开源的一个 IM 项目中有朋友提到希望可以支持 emoji 表情传输. https ...

  8. 新建项目中的fail和missing之类的问题

    首先必须要明白:每一个项目需要都要安装在本地仓库中去--->pom,war,jar无一例外 如果不安装会出现下面的错误: 解决的办法就是: 先clean后install项目,把他们安装到本地仓库 ...

  9. 玩转 Springboot 2 之热部署(DevTools)

    Devtools 介绍 SpringBoot 提供了热部署的功能,那啥是热部署累?SpringBoot官方是这样说的:只要类路径上的文件发生更改,就会自动重新启动应用程序.在IDE中工作时,这可能是一 ...

  10. Day4 总结