ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

springSecurity实现登录验证

2021-12-28 16:03:23  阅读:121  来源: 互联网

标签:return 登录 验证 request 认证 public Authentication springSecurity response


文章目录

实现AbstractAuthenticationToken自定义验证对象

在SpringSecurity认证过程中,最核心的对象为Authentication,这个对象用于在认证过程中存储主体的各种基本信息(例如:用户名,密码,所属部门等等)和主体的认证信息(例如,接口权限)。

我们可以通过继承AbstractAuthenticationToken来自定义的Authentication对象

public class MyUserNamePassToken extends AbstractAuthenticationToken {


    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

		//一般用于存储主体信息,
    private Object principal;
		//一般用于储存验证主体信息的凭据
    private Object credentials;

		
    public MyUserNamePassToken(Object principal, Object credentials) {
        super(null);
        this.principal = principal;
        this.credentials = credentials;
        setAuthenticated(false);
    }

    public MyUserNamePassToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        setAuthenticated(true);
    }


    @Override
    public Object getCredentials() {
        return credentials;
    }

    @Override
    public Object getPrincipal() {
        return principal;
    }
}

我们可能还是比较懵逼,定义这个对象有啥用,别急。对于当前这个对象的各个属性存储啥其实都不重要,你想要怎么存就怎么存,我们重点关注第二个构造方法中的入参authorities,这个参数是在AbstractAuthenticationToken中定义的,代表该用户所拥有的所有权限的集合。

定义登录filter

自定义filter的方法有很多种,通过阅读springSecurity自带的UsernamePasswordAuthenticationFilter的源码我们对其进行模仿,通过继承AbstractAuthenticationProcessingFilter来实现一个Filter,AbstractAuthenticationProcessingFilter是由springSecurity定义的一个过滤器抽象类,它基于认证流程做了一个非常好的扩充,下面是AbstractAuthenticationProcessingFilter的dofilter方法源码。

private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		if (!requiresAuthentication(request, response)) {
			chain.doFilter(request, response);
			return;
		}
		try {
      //先调用钩子方法尝试进行身份认证
			Authentication authenticationResult = attemptAuthentication(request, response);
      //如果没有认证成功,直接返回
			if (authenticationResult == null) {
				// return immediately as subclass has indicated that it hasn't completed
				return;
			}
      //session相关功能,现在都不用session,这里不管
			this.sessionStrategy.onAuthentication(authenticationResult, request, response);
			//认证成功时候继续执行过滤器链剩余的过滤器,默认时false不执行; 
			if (this.continueChainBeforeSuccessfulAuthentication) {
				chain.doFilter(request, response);
			}
      //执行认证成功处理器
			successfulAuthentication(request, response, chain, authenticationResult);
		}
    //认证发生异常则执行认证失败处理器
		catch (InternalAuthenticationServiceException failed) {
			this.logger.error("An internal error occurred while trying to authenticate the user.", failed);
			unsuccessfulAuthentication(request, response, failed);
		}
		catch (AuthenticationException ex) {
			unsuccessfulAuthentication(request, response, ex);
		}
	}

通过阅读源码发现,只要我们继承了AbstractAuthenticationProcessingFilter我们就只需要实现attemptAuthentication(request, response)方法来处理具体的认证流程,再定义一个AuthenticationSuccessHandler处理认证成功和定义一个AuthenticationFailureHandler来处理认证失败这三个就可以实现一个完整的登录filter。

实现AbstractAuthenticationProcessingFilter的attemptAuthentication方法

public class MyLoginFilter extends AbstractAuthenticationProcessingFilter {
		//定义过滤器拦截的请求映射
    private final static String matchUrl = "/login";

    public MyLoginFilter() {
        super(new AntPathRequestMatcher(matchUrl));
    }

	  //定义身份验证逻辑
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        //初始化一个我们自定义的未经认证的Authentication对象
        MyUserNamePassToken userNamePassToken = new MyUserNamePassToken(request.getParameter("userName"), request.getParameter("UserPass"));
        //调用所有的身份验证处理器循环进行验证,返回一个经过验证的Authentication对象,想看源码的同学可以看ProviderManager这个类
      	return this.getAuthenticationManager().authenticate(userNamePassToken);
    }
}

在这饭代码的最后一行我们调用this.getAuthenticationManager().authenticate(userNamePassToken),这行代码的意思是调用所有的身份验证处理器对当前的认证信息进行处理,认证成功则返回Authentication,我们通过实现AuthenticationProvider自定义一个处理器来单独处理我们的MyUserNamePassToken。

自定义身份验证处理器

public class MyUserNamePassProvider implements AuthenticationProvider {

	  
    private final UserDetailsService userDetailsService;

    public MyUserNamePassProvider(UserDetailsService MyUserDetailsService) {
        this.userDetailsService = MyUserDetailsService;
    }

		//认证方法,这里只是简单实现验证,具体实现根据具体业务而定
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        MyUserNamePassToken myUserNamePassToken = (MyUserNamePassToken) authentication;
        User user = null;
        try {
            user = (User) userDetailsService.loadUserByUsername(myUserNamePassToken.getName());
            if (user == null) {
                throw new Exception("用户不存在");
            }
            if (!myUserNamePassToken.getCredentials().equals(user.getPassword())) {
                throw new Exception("用户密码不正确");
            }
            String s = UUID.randomUUID().toString();
            LoginToken.tokens.put(s, user);
            myUserNamePassToken.setDetails(s);
            return myUserNamePassToken;
        } catch (Exception e) {
            throw new InternalAuthenticationServiceException(e.getMessage());
        }
    }
	  //这里定义支持处理那种类型的authentication
    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.isAssignableFrom(MyUserNamePassToken.class);
    }
}

这个类只实现了两个方法,第一个方法authenticate用于进行权限验证,如果验证成功则返回一个

定义认证成功处理器

我们直接返回登录成功

public class LoginSuccessHandler implements AuthenticationSuccessHandler {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().write(objectMapper.writeValueAsString(R.ok(authentication.getDetails(), "登录成功")));
    }
}

定义认证失败处理器

认证失败直接返回认证失败

public class LoginFailHandler implements AuthenticationFailureHandler {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().write(objectMapper.writeValueAsString(R.failed(exception.getMessage(), "登录失败")));
    }
}

配置登录过滤器到springSecurity

构建一个springSecurity配置类

@Configuration
public class LoginAuthenticationConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

    @Autowired
    @Qualifier("MyUserDetailsService")
    UserDetailsService userDetailsService;

    @Bean
    public LoginSuccessHandler loginSuccessHandler() {
        return new LoginSuccessHandler();
    }

    @Bean
    public LoginFailHandler loginFailHandler() {
        return new LoginFailHandler();
    }

    @Override
    public void configure(HttpSecurity builder) throws Exception {
        builder.authenticationProvider(new MyUserNamePassProvider(userDetailsService));
        MyLoginFilter loginFilter = new MyLoginFilter();
        loginFilter.setAuthenticationManager(builder.getSharedObject(AuthenticationManager.class));
        loginFilter.setAuthenticationSuccessHandler(loginSuccessHandler());
        loginFilter.setAuthenticationFailureHandler(loginFailHandler());
        builder.addFilterAfter(loginFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

新建一个SpringSecurity总配置类,将上面的登录认证配置添加。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    final LoginAuthenticationConfig loginAuthenticationConfig;

    public SecurityConfig(LoginAuthenticationConfig loginAuthenticationConfig) {
        this.loginAuthenticationConfig = loginAuthenticationConfig;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //禁用 CSRF
                .csrf().disable()
                //去除session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .logout().disable()
                .apply(loginAuthenticationConfig).and()
                .authorizeRequests().anyRequest().authenticated();
    }
}

至此我们就完成一个登录验证的配置

标签:return,登录,验证,request,认证,public,Authentication,springSecurity,response
来源: https://blog.csdn.net/qq_40231937/article/details/122195452

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有