zoukankan      html  css  js  c++  java
  • spring security认证

    1.spring security 主要是为了做认证和授权,通过一系列的filter链;

    认证流程如下:

    security默认做认证处理的过滤器为UsernamePasswordAuthenticationFilter,该类继承AbstractAuthenticationProcessingFilter,首先执行AbstractAuthenticationProcessingFilter类的

    dofilter方法,该类dofiter源码如下:

     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest)req;
            HttpServletResponse response = (HttpServletResponse)res;
            //1.判断当前的filter是否可以处理当前请求,不可以的话则交给下一个filter处理
            if (!this.requiresAuthentication(request, response)) {
                chain.doFilter(request, response);
            } else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Request is to process authentication");
                }

                Authentication authResult;
                try {
                    /**抽象方法由子类UsernamePasswordAuthenticationFilter实
                    现attemptAuthentication,主要是获取认证信息,可根据自己实际需求继承UsernamePasswordAuthenticationFilter类,重写attemptAuthentication方法
                    **/
                    authResult = this.attemptAuthentication(request, response);
                    if (authResult == null) {
                        return;
                    }
                    //认证成功后,处理一些与session相关的方法
                    this.sessionStrategy.onAuthentication(authResult, request, response);
                } catch (InternalAuthenticationServiceException var8) {
                    this.logger.error("An internal error occurred while trying to authenticate the user.", var8);
                    //认证失败后的一些操作
                    this.unsuccessfulAuthentication(request, response, var8);
                    return;
                } catch (AuthenticationException var9) {
                    this.unsuccessfulAuthentication(request, response, var9);
                    return;
                }

                if (this.continueChainBeforeSuccessfulAuthentication) {
                    chain.doFilter(request, response);
                }
                //认证成功后的相关回调方法,主要将当前的认证放到SecurityContextHolder中
                this.successfulAuthentication(request, response, chain, authResult);
            }
        }

    AbstractAuthenticationProcessingFilter类的dofilter主要执行UsernamePasswordAuthenticationFilter类中的attemptAuthentication方法,该方法源码为:

    public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
        public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
        public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
        private String usernameParameter = "username";
        private String passwordParameter = "password";
        private boolean postOnly = true;

        public UsernamePasswordAuthenticationFilter() {
            super(new AntPathRequestMatcher("/login", "POST"));
        }

        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            if (this.postOnly && !request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            } else {
                //从request请求中获取username的值
                String username = this.obtainUsername(request);
                //从request请求中获取password的值
                String password = this.obtainPassword(request);
                if (username == null) {
                    username = "";
                }

                if (password == null) {
                    password = "";
                }

                username = username.trim();
                //通过用户名和密码构建一个UsernamePasswordAuthenticationToken的对象,作用是将用户请求的信息(用户名、密码、session等)封装到该对象中
                UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
                this.setDetails(request, authRequest);
                return this.getAuthenticationManager().authenticate(authRequest);
            }
        }

     需要说明一点的是,super((Collection)null); collection 代表权限列表,在这传了一个 null 进去是因为刚开始并没有进行认证,因此用户此时没有任何权限,并且设置没有认证的信息 setAuthenticated(false)

    再回到 UsernamePassworkAuthenticationFilter attemptAuthentication() 方法,可以看到方法最后调用了 getAuthenticationManager() 方法,然后就进入了 AuthenticationManager 接口的实现类 ProviderManager 中。

     补充:AuthenticationManager 不包含验证用户名以及密码的功能,只是用来管理 AuthenticationProvider,所有的校验规则都是写在 AuthenticationProvider 中的;

     然后执行ProciderManager中authenticate方法,该方法中主要执行AuthenticationProvider类中authenticate方法,用户的信息权限的验证就在该类中校验,可根据实际需要实现AuthenticationProvider接口,重写authenticate方法

    进入 ProviderManager 类后会调用 authenticate(Authentication authentication) 方法,它通过 AuthenticationProvider 实现类获取用户的登录的方式,然后会有一个 while 迭代器模式的循环遍历,检查它是否支持这种登录方式,具体的登录方式有表单登录,qq登录,微信登录等。如果最终都不支持会抛出相应的异常信息,如果支持则会进入AuthenticationProvider 接口的抽象实现类 AbstractUserDetailsAuthenticationProvider 中。

    AbstractUserDetailsAuthenticationProvider 类后会调用 authenticate(Authentication authentication) 方法源码如下:

    进入 AbstractUserDetailsAuthenticationProvider 类后会调用 authenticate(Authentication authentication) 方法对用户的身份进行校验,首先是判断用户是否为空,这个 user 是 UserDetail 的对象,如果为空,表示还没有认证,就需要调用 retrieveUser 方法去获取用户的信息,这个方法是抽象类 AbstractUserDetailsAuthenticationProvider 的扩展类DaoAuthenticationProvider 的一个方法。

    DaoAuthenticationProvider中retrieveUser源码如下:

    在该扩展类中,retrieveUser调用UserDetailsService接口实现类中的loadUserByUsername方法去获取用户信息,所以本地可以实现UserDetailsService接口,在这个实现类中,编写自己的逻辑

  • 相关阅读:
    Linux下安装配置jdk
    Linux基础实验(二)
    Linux基础命令(一)
    Linux基础实验(一)
    QT 参考资料
    C++ const_cast用法(转)
    05 内嵌汇编的编程
    构造函数和析构函数可以调用虚函数吗(转)
    C++之迭代器(Iterator)篇 (转)
    链接脚本
  • 原文地址:https://www.cnblogs.com/zpp1234/p/12170579.html
Copyright © 2011-2022 走看看