Spring Security——基于表单登录认证原理及实现

栏目: Java · 发布时间: 6年前

内容简介:Spring Security——基于表单登录认证原理及实现
spring security默认采用basic模式认证。浏览器发送http报文请求一个受保护的资源,浏览器会
弹出对话框让输入用户名和密码。并以用户名:密码的形式base64加密,加入Http报文头部的Authorization
(默认用户名为user,密码则是会在启动程序时后台console里输出,每次都不一样)。后台获取Http报文头
部相关认证信息,认证成功返回相应内容,失败则继续认证。下面会详细介绍具体认证流程。

二、基于表单的认证原理

基本认证流程:
                     SecurityContextPersistenceFilter
                                   ↓
                   AbstractAuthenticationProcessingFilter
                                   ↓
                    UsernamePasswordAuthenticationFilter
                                   ↓
                         AuthenticationManager
                                   ↓
                         AuthenticationProvider
                                   ↓
                          userDetailsService
                                   ↓
                              userDetails
                                   ↓
                                认证通过
                                   ↓
                            SecurityContext
                                   ↓
                          SecurityContextHolder
                                   ↓
                           RememberMeServices
                                   ↓
                      AuthenticationSuccessHandler
SecurityContextPersistenceFilter会校验请求中session是否有SecurityContext,有放SecurityContextHolder
中,返回时校验SecurityContextHolder中是否有securityContext,有放session,从而实现认证信息在多个请求中共
享。
AbstractAuthenticationProcessingFilter中会调自身attemptAuthentication抽象方法的某个实现
UsernamePasswordAuthenticationFilter便是一个,它从请求中获取账号密码后,构造了一个token,此时没有认证,
如下:
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
        super((Collection)null);
        this.principal = principal;
        this.credentials = credentials;
        this.setAuthenticated(false);
    }
随后会调用AuthenticationManager接口中authenticate方法,ProviderManager具体实现,它遍历
provider,调用其supports方法,去匹配之前申明的token,找到provider后调用authenticate方法,
这个方法才开始认证用户信息,表单登录的是DaoAuthenticationProvider其父类进行以下操作:
①调用userDetailsService接口的loadUserByUsername方法获取UserDetails用户信息
②检查UserDetails用户是否可用、是否账户没有过期、是否账户没有被锁定
③检查UserDetails密码是否正确
④检查UserDetails密码是否没有过期
⑤都通过会重新申明一个token,不过多了权限集合参数如下
public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
    Collection authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
    }
此时用户才被认证通过,上述步骤有一个错了会抛出AuthenticationException中的子异常,下面是其继承图:
Spring Security——基于表单登录认证原理及实现
认证结果返回给AbstractAuthenticationProcessingFilter,将结果放到SecurityContextHolder的
SecurityContext中,若添加了记住我功能又会调用rememberMeServices来实现,最后调用
AuthenticationSuccessHandler接口成功处理。

三、功能实现

在第二部分介绍具体原理,接下来实现自定义登录验证。首先编写一个config类继承WebSecurityConfigurerAdapter
类重写configure方法填写配置
protected void configure(HttpSecurity http) throws Exception {
        http
                /**
                 * 表单登录配置
                 */
                .formLogin() //表单登录
                .loginPage("authentication/login.html") //自定义登录页面
                .loginProcessingUrl("/authentication/form") //与自定义登录页面处理路径一致
//        http.httpBasic()   basic模式弹出框登录
                .successHandler(myAuthenticationSuccessHandler)  //自定义认证成功处理
                .failureHandler(myAuthenticationFailureHandler)  //自定义认证失败处理
                .and()
                /**
                 * 需要认证的请求配置,
                 * 注:最为具体的请求路径放在前面,而最不具体的路径(如anyRequest())放在最后面。
                 * 如果不这样做的话,那不具体的路径配置将会覆盖掉更为具体的路径配置
                 */
                .authorizeRequests()
                //允许这样请求通过,需要将登录所需路径配好,不然会一直重定向
                .antMatchers("/authentication/*").permitAll() 
                .anyRequest().authenticated()//任何请求都需要认证
                .and()
                .csrf().disable(); //关闭csrf防御机制
    }
自定义用户实现UserDetailsService接口重写loadUserByUsername方法
@Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return new User(username, "123456", true, true,
                true, true, new ArrayList());
    }
这里的User是security自己的,写死了密码为123456,正常应该根据用户名从数据库查出用户信息。当然密码也不可
能为明文,这里推荐使用BCryptPasswordEncoder加密,因为其每次加密都会生成随机盐加入字符串中。需要在之前申
明的config类添加即可
@Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
这四个boolean值分别表示是否可用、是否账户没有过期、是否密码没有过期、是否账户没有被锁定。构造函数
最后一个参数为该用户用哪些接口权限,同样也从数据库查,但是这个权限只会在登录时初始化一次,若我登录后修
改权限,则无法同步,后续介绍解决办法。
    接下来就是两个登录的自定义登录处理,成功的实现AuthenticationSuccessHandler接口,失败的则实现
AuthenticationFailureHandler接口
@Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException{
        response.setContentType("application/json;UTF-8");
        response.getWriter().println("{\"success\":true,\"result\":\"" + "登录成功" + "\"}");
    }
    
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        response.setContentType("application/json;UTF-8");
        response.getWriter().println("{\"error\":true,\"message\":\"登录名或者密码错误\"}");
    }
注意成功和失败最后的方法参数是不同的,一个是成功的认证信息,另一个失败抛出的认证异常json串的key可以
根据自身登录页面ajax处理结果的属性来定,必须保持一致。
    页面代码就不复制了,做一个简单html就行。

以上所述就是小编给大家介绍的《Spring Security——基于表单登录认证原理及实现》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算机网络(第4版)

计算机网络(第4版)

[美] James F. Kurose、[美] Keith W. Ross / 陈鸣 / 机械工业出版社 / 2009-11 / 66.00元

本书采用了独创的自顶向下方法,即从应用层开始沿协议栈向下讲解计算机网络的基本原理,强调应用层范例和应用编程接口,内容深入浅出,注重教学方法,理论与实践相结合。第3版的内容相应更新并反映了网络领域的最新进展,如增加了无线和移动网络一章,扩充了对等网络、BGP、MPLS、网络安全、广播选路和因特网编址及转发方面的材料;还增加了一套实用的实验,并修订了习题。本书适合作为计算机、电子、通信工程相关专业的本......一起来看看 《计算机网络(第4版)》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具