spring security 自定义多种方式登录授权

自定义token,继承 AbstractAuthenticationToken

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;

/**
 * 手机短信token验证
 *
 * @author ming
 * @version 1.0.0
 * @date 2021/3/1 15:17
 **/
public class SmsAuthenticationToken extends AbstractAuthenticationToken {

    private static final long serialVersionUID = 530L;
    private final Object principal;
    private Object credentials;

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

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

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

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

    @Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        } else {
            super.setAuthenticated(false);
        }
    }

    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
        this.credentials = null;
    }
}

自定义拦截类Filter,继承AbstractAuthenticationProcessingFilter

import com.base.web.config.security.authentication.SmsAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义手机号、短信验证码登录过滤器
 *
 * @author ming
 * @version 1.0.0
 * @date 2021/3/1 15:17
 **/
public class JwtSmsLoginFilter extends AbstractAuthenticationProcessingFilter {

    public JwtSmsLoginFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
        super(requiresAuthenticationRequestMatcher);
    }

    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String phoneNo = request.getParameter("phoneNo");
        String code = request.getParameter("code");

        if (phoneNo == null) {
            phoneNo = "";
        }
        if (code == null) {
            code = "";
        }

        SmsAuthenticationToken token = new SmsAuthenticationToken(phoneNo, code);
        //token.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));/
        token.setDetails(this.authenticationDetailsSource.buildDetails(request));
        SecurityContextHolder.getContext().setAuthentication(token);

        return super.getAuthenticationManager().authenticate(token);
    }

}

实现登录验证逻辑

import cn.hutool.core.util.ObjectUtil;
import com.base.common.constant.WebConstant;
import com.base.redis.utils.RedisCacheUtil;
import com.base.web.config.security.authentication.SmsAuthenticationToken;
import com.base.web.service.AccountService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;

/**
 * 用户自定义身份认证, 短信验证码模式
 *
 * @author ming
 * @date : 2019/7/2 17:17
 * @since : 1.0
 */
@Component
public class SmsAuthenticationProvider implements AuthenticationProvider {
    @Resource
    private AccountService accountService;
    @Resource
    private RedisCacheUtil redisCacheUtil;

    /**
     * 认证处理,返回一个Authentication的实现类则代表认证成功,返回null则代表认证失败
     *
     * @date 2019/7/5 15:19
     * @since 1.0
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String phoneNo = authentication.getName();
        String code = (String) authentication.getCredentials();
        if (StringUtils.isBlank(phoneNo)) {
            throw new UsernameNotFoundException("手机号不可以为空");
        }
        if (StringUtils.isBlank(code)) {
            throw new BadCredentialsException("验证码不可以为空");
        }
        //验证短信验证码
        String key = phoneNo + WebConstant.REDIS_KEY_SUFFIX_FOR_VERIFICATION_CODE;
        boolean hasCode = redisCacheUtil.hasKey(key);
        if (!hasCode) {
            throw new BadCredentialsException("短信验证码已失效请重新获取");
        }
        String smsCode = redisCacheUtil.getString(key);
        //比较前端传入的明文和数据库中加密的密文是否相等
        if (!smsCode.equalsIgnoreCase(code)) {
            throw new BadCredentialsException("验证码错误");
        }
        redisCacheUtil.delete(key);
        //获取用户信息
        UserDetails user = accountService.loadUserByUsername(phoneNo);
        if (ObjectUtil.isEmpty(user)) {
            throw new BadCredentialsException("用户信息加载失败");
        }

        //获取用户权限信息
        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
        return new UsernamePasswordAuthenticationToken(user, null, authorities);
    }
    
    /**
     * 如果该AuthenticationProvider支持传入的Authentication对象,则返回true
     *
     * @date 2019/7/5 15:19
     * @since 1.0
     */
    @Override
    public boolean supports(Class<?> aClass) {

        return SmsAuthenticationToken.class.isAssignableFrom(aClass);
    }
}

security配置

// 添加过滤器
http.addFilterBefore(smsLoginFilter(), AbstractPreAuthenticatedProcessingFilter.class);
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
	auth.userDetailsService(userService)
			.passwordEncoder(passwordEncoder())
			.and()
			.authenticationProvider(smsAuthenticationProvider)
			.authenticationProvider(passwordAuthenticationProvider);
}
/**
 * 登录认证器 --- 手机号、短信登录
 */
@Bean
public AbstractAuthenticationProcessingFilter smsLoginFilter() throws Exception {
	JwtSmsLoginFilter jwtSmsLoginFilter = new JwtSmsLoginFilter(new AntPathRequestMatcher("/account/login", "POST"));
	jwtSmsLoginFilter.setAuthenticationManager(this.authenticationManager());
	jwtSmsLoginFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
	jwtSmsLoginFilter.setAuthenticationFailureHandler(authenticationFailureHandler);
	return jwtSmsLoginFilter;
}
posted @ 2021-06-04 15:10  itwetouch  阅读(2765)  评论(3编辑  收藏  举报