SpringSecurity-five(实现免登陆)

使用SpringSecurity提供的接口完成免登陆逻辑

1. 免登陆实现逻辑

image.png![image.png]g)

  • 用户通过浏览器发起第一次请求,然后经过UsernamePasswordAuthenticationFilter过滤器进行认证,认证成功就进入到RememberMeService中基于用户名和密码生成一个token,这个服务再将token存放到数据库中。并且在这个service中还要将token返回给客户端并设置到cookie中。
  • 当用户第二次发起请求的时候,直接进入到一个RememberMeAuthenticationFilter过滤器中进行验证,这个过滤器同样调用service查询数据库中的token。
  • 加入记住我单选框,这里的name值必须为"remember-me"
	<tr>
            <td colspan="2"><input name="remember-me" type="checkbox" value="true"/>记住我</td>
        </tr>

  • token的过期时间可能需要用户自己配置,所以字我们前边写的BrowserSecurity中添加token属性
package com.zcf.security.core.properties;

public class BrowserProperties {
    /**
     * 赋予loginPage默认值,也就是如果用户不指定自己的登录页面,
     * 则使用我们提供的默认登录页面
     */
    private String loginPage = "/zcf-signIn.html";

    /**
     * 配置登录之后是跳转还是返回json
     * @return
     */
    private LoginType loginType = LoginType.JSON;
    /**
     * 配置token过期时间
     */
    private int rememberMeSeconds = 3600;

    public String getLoginPage() {
        return loginPage;
    }

    public void setLoginPage(String loginPage) {
        this.loginPage = loginPage;
    }

    public LoginType getLoginType() {
        return loginType;
    }

    public void setLoginType(LoginType loginType) {
        this.loginType = loginType;
    }

    public int getRememberMeSeconds() {
        return rememberMeSeconds;
    }

    public void setRememberMeSeconds(int rememberMeSeconds) {
        this.rememberMeSeconds = rememberMeSeconds;
    }
}
  • 配置操作数据类,也就是上边说到的TokenRepository
   @Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private DataSource dataSource;

    /**
     * 导入自己写的AuthenticationSuccessHandler的实现类
     */
    @Autowired
    private AuthenticationSuccessHandler zcfAuthenticationSuccessHandler;

    /**
     * 导入自己写的AuthenticationFailureHandler的实现类
     */
    @Autowired
    private AuthenticationFailureHandler zcfAuthenticationFailureHandler;

    /**
     *
     *
     */
    @Autowired
    private UserDetailsService myUserDetailService;

    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        /**
         * 配置数据源
         */
        tokenRepository.setDataSource(dataSource);
        /**
         * 在JdbcTokenRepositoryImpl中有数据库脚本
         * 我们使用脚本来创建表
         * 但是在第二次重启服务的时候需要注释掉
         */
        //tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }
    @Bean
    public PasswordEncoder passwordEncoder(){
        /**
         * 这里返回的是spring默认的PasswordEncoder的实现类,用的也是默认的加密方法
         * 通过查看PasswordEncoder接口的源码可以看到有两个方法,一个是对传进来的数据进行加密的方法
         * 一个是调用这个方法,spring会自己判断传进来的数据是否符合加密规则
         * 如果需要使用自己的加密方法,那么这个方法要实现PasswordEncoder这个接口,然后返回
         */
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        ValidateCodeFilter filter = new ValidateCodeFilter();
        filter.setSecurityProperties(securityProperties);
        filter.afterPropertiesSet();

        filter.setAuthenticationFailureHandler(zcfAuthenticationFailureHandler);
        http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class)
                .formLogin()                                      //基于form表单的登录验证
                .loginPage("/authentication/require")                //指定登录页面
                .loginProcessingUrl("/authentication/form")   //表单的action路径
                .successHandler(zcfAuthenticationSuccessHandler)//配置自己写的登录成功处理器
                .failureHandler(zcfAuthenticationFailureHandler)
                .and()
                .rememberMe()//配置记住我
                .tokenRepository(persistentTokenRepository())//设置tokenRepository
                .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())//设置过期时间
                .userDetailsService(myUserDetailService)//设置登录的服务
                .and()
                .authorizeRequests()        //关于请求的一些配置
                /**
                 * 这里需要注意一个错误,如果不适用antMatchers().permitAll()将登录的url设置为不需要身份验证的话
                 * 那么就会导致,请求重定向次数过多错误
                 */
                .antMatchers("/authentication/require",securityProperties.getBrowser().getLoginPage(),
                        "/code/image").permitAll() //访问这个路径不需要身份验证
                .anyRequest()               //所有的请求
                .authenticated()            //身份验证
                .and()
                .csrf().disable();          //关闭跨站防护
    }
}
  • 访问浏览器进行登录,会发现数据库中多了一个表,并且存在登录用户的数据 image.png

这样就实现了免登陆逻辑了,可以看到由于SpringSecurity提供的接口,整个逻辑实现的特别简单。但是需要了解的是业务逻辑的实现。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×