SpringSecurity开发基于表单的认证(六)

SpringSecurity之记住我功能

  • 记住我功能基本原理
  • 记住我功能具体实现
  • 记住我功能SpringSecurity源码分析

记住我功能基本原理

image.png
image.png

这篇文章有停留两周的时间没有完成了,工作忙是一方面,另一方面是由于对spring security的理解混乱,导致出现问题解决时没有头绪,为此,阅读了《spring 实战》一书中的spring security章节后才逐渐思路清晰。下面接着对这篇文章进行补充。

首先从头对spring security的配置进行注释和整理,帮助阅读代码:

@Configuration
@EnableWebSecurity
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired 
    SecurityProperties securityProperties;
    
    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    
    @Autowired
    private MyAuthenticationFailHandler myAuthenticationFailHandler;
    
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    
    @Autowired
    private DataSource dataSource;
    
    @Autowired
    private UserDetailsService userDetailsService;
    
    @Bean
    public PersistentTokenRepository persistenceTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        //tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }
    
    /*
     * 对每个请求进行细粒度安全性控制的关键在于重载configure(HttpSecurity)方法
     * 
     * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception{
        ValidateCodeFilter validateCodeFilter =new ValidateCodeFilter();

        validateCodeFilter.setAuthenticationFailureHandler(myAuthenticationFailHandler);
        
        http
        
            /*
             * 在UsernamePasswordAuthenticationFilter过滤器之前添加短信验证码过滤器
             */
            .addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
            
            /*
             * 表单登录适用于浏览器向restful api发起请求;如果是后台程序直接发起请求访问restful api,则设为HTTP BASIC模式
             */
            .formLogin()
            .loginPage("/login.html") //跳转的登录页/authentication/require
            .loginProcessingUrl("/authentication/form") //登录时的请求
            .successHandler(myAuthenticationSuccessHandler) //表单登录成功时使用我们自己写的处理类
            .failureHandler(myAuthenticationFailHandler) //表单登录失败时使用我们自己写的处理类
            .and()
            
            /*
             * 调用rememberMe()方法启用记住我功能,通过在cookie中存储一个token完成
             */
            .rememberMe()
            //指定保存token的仓库,此处实现为保存到指定的数据库中
            .tokenRepository(persistenceTokenRepository())
            //tokenValiditySeconds()指定token的有效时间
            .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
            //指定登录用户、密码和权限
            .userDetailsService(userDetailsService) 
            .and()
            
            /*
             * 调用HttpSecurity类的authorizeRequests()方法所返回的对象的方法来配置请求级别的安全性细节
             */
            .authorizeRequests()
            //antMatchers()对指定路径的请求需要进行认证,这个方法以ant开头表示路径支持Ant风格的通配符,permitAll()方法运行请求没有任何的安全限制
            .antMatchers("login.html","/code/image").permitAll()
            //anyRequest()指定了匹配之外的所有请求,authenticated()要求在执行该请求时,必须已经登录了应用
            .anyRequest().authenticated()
            .and()
            
            /*
             * 禁用CSRF(跨站请求伪造)防护功能
             */
            .csrf().disable();
    }

web安全配置类中的configure方法是配置入口点,每一项配置都应该按照上面的写法进行分类,每种配置之间都通过and方法进行连接,如以".formLogin()"开头的是表单登录相关的配置,以".rememberMe()"开头的是记住我功能的相关配置,以".authorizeRequests()"开头的是请求的安全配置。我们先回顾一下第三项以authorizeRequests()开头的请求配置。
请求配置主要分两个方面:
1.要配置的请求的路径是什么?为此可以使用antMatchers()方法来指定路径;而往往指定了特定的路径后,在最后使用anyRequest()表示的是除以上以外的所有请求。
2.指定路径之后,这个路径所代表的请求该如何保护。如permitAll()方法表明对应的路径没有任何的安全限制,可以直接方法;authenticated()方法则表示只有认证成功以后才可以访问指定路径。
根据以上两点,上述代码中的这段请求安全配置可以理解为:请求路径为"login.html"和"/code/image"可以直接访问,没有安全限制,而除此之外的其他请求必须在身份认证通过以后才能访问。

在理解了请求的安全配置后,我们再来看记住我功能是怎么实现的。记住我的原理是在第一次登陆成功后,生成一份保存用户信息的token,一方面将这个token保存到指定的数据库中,另一方面将这个token保存到浏览器的cookie中。这样即使以后session丢失(如服务器重启)而浏览器的cookie还在,再次访问时仍可以通过cookie中的token来直接访问具体的restful api,而不需要重新进行表单登录。这就实现了记住我的功能。

下面我们来演示一下,首先我们已经写好一个具体的restful api:

    @GetMapping("/user")
    public void helloWorld(HttpServletRequest request,HttpServletResponse response) throws Exception{
        System.out.println("hello world");
    }

然后我们访问表单登录页面,http://localhost:8080/login.html,截图如下:

login.png

填写完正确的用户名和密码和验证码之后,点击登录,登录成功后,重新访问http://localhost:8080/user
这时就可以成功输出hello world了。但这只能说明登录成功后,usernamepassworldauthentication filter将登录信息保存到session中了,如果我们重启服务后再直接访问http://localhost:8080/user时,就不能直接访问到restful api了,而是重定向到登录页面,因为重启了以后session就不见了,但是我们加了记住我的配置后,即使重启应用后直接访问http://localhost:8080/user也能成功,这就是因为用户信息是保存到浏览器cookie中,只要cookie中存在用户信息就可以直接访问成功,而不需要先表单登录来进行身份认证。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容