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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM