Spring Security自定义认证页面(动态网页解决方案+静态网页解决方案)--练气中期圆满

写在前面

上一回我们简单分析了spring security拦截器链的加载流程,我们还有一些简单的问题没有解决。如何自定义登录页面?如何通过数据库获取用户权限信息?
今天主要解决如何配置自定义认证页面的问题。因为现在前后端分离,无状态、restful接口设计比较火,因此在思考静态网页如何获取spring security的CRSF Token.这个问题我在文末提出了我的见解,但似乎也不是很好的解决方案,很期待大家的宝贵建议!

Spring Security配置自定义认证页面步骤

第一步:在spring security的配置文件中指定自定义登录页面的信息


    

    
        
        

        
        
        
        
    

关于配置文件的几点说明:

  1. login-page:配置自定义的认证页面;
  2. login-processing-url:配置认证处理的url;
  3. default-target-url:配置认证成功之后跳转的页面;
  4. authentication-failure-url:配置认证失败之后跳转的页面;
  5. logout-url:配置注销处理路径;
  6. logout-success-url:配置成功注销后跳转的页面;
  7. username-parameter:配置前端表单向后台提交用户账户的参数名,默认值为username,可以不配置;
  8. password-parameter:配置前端表单向后台提交用户凭证的参数名,默认值为password。
  9. security="none"表示该路径下的资源访问不拦截(这个和匿名访问的配置是有区别的)

第二步:编写一个前端登录页面login.html




    
    登录





欢迎登录

登录

第三步,启动tomcat,访问http://127.0.0.1:8081/

我们可以发现,我们被重定向到了登录页面。接下来我们填写username和password点击登录(在前面的配置文件中定义了)

我们发现结果并不符合我们的预期。我们得到了403(没有权限)错误信息。

why?

我们对比一下我们写的登录页面和spring security给出的页面有啥不一样



    
    
    
    
    Please sign in
    
    
  
  
     

对比发现系统给出的和我们写的认证页面在表单中多出了下面这段

也就是说我们少了一个参数信息,这参数信息就是我们前篇文章讲到的spring security预防csrf攻击的内容。显然它是通过校验token去预防的。

解释一下如何通过检验token的方式预防csrf攻击:

​ 简单来说就是赵六你去账房领银两办事(获取系统服务)前先向王员外(可以是系统专门发放令牌的一个接口)索要一个令牌(token),你领银两的时候带上王员外给你的令牌,这账房管事的李老先生(一个拦截器)查看了你的令牌后才能给你钱,不然就不给你钱。你拿钱了之后呢令牌就被收走了(token过期策略),下次再想拿钱就得找王员外再要一个新的令牌。

接下来就让我们找李老先生拿银两去,哦,不对,是找王员外拿鸡毛令箭去。。。

第四步:配置csrf攻击防护机制

从Spring Security 4.0开始,默认情况下使用XML配置启用CSRF保护。如果要禁用CSRF保护,可以在下面看到相应的XML配置。


    
    

由于spring security的csrf令牌是存储再HttpSession中的,因此在动态网页中,可以很方便的获取到csrf token信息。


    

    

    
    
    
    
    

    

如果使用的是静态网页,例如前后端分离、restful接口设计和无状态session的情况下,或许可以考虑如下设计:

​ 将csef token暴露出去,前端通过ajax请求获取token,并在请求服务时带上token。当然,这里暴露出去的token应该是只能在内部暴露,使得静态页面得到token后,再将网页响应给用户。

获取token

登录

静态网页获取csrf token的部分代码

/**
 * @author 赖柄沣 [email protected]
 * @version 1.0
 * @date 2020/8/21 12:29
 */
@RestController
@RequestMapping("/csrf")
public class CsrfTokenCtrl {

    @GetMapping(value = "/getToken")
    public HashMap getToken(HttpServletRequest request ){
        /**
         * 在这里可以先过滤掉一些非法的请求,只允许内部静态网页服务器请求
         */
        
        CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
        HashMap map = new HashMap<>();
        map.put("csrf_header",token.getHeaderName());
        map.put("csrf",token.getToken());
        return map;
    }

}

End
为了保证系统安全,牺牲一些设计上的完美,在我看来是很有必要的。相信会有更好的方案!以上只是我个人的一些见解。欢迎大家提出不一样的想法。

你可能感兴趣的:(java,spring-security)