自定义【Spring Security】实现多种认证方式
概述
Spring Security是一个功能强大且高度可定制的Java安全框架,用于保护基于Spring的应用程序。它重点提供认证(Authentication)和授权(Authorization),并且通过使用Spring的依赖注入(DI)特性,使得安全配置变得灵活和集中。
Spring Security的灵活性和强大功能使其成为保护Spring应用程序的首选安全解决方案。正是由于其高度可配置性,我想引入一组自定义认证器到Rdtalk来适配企业框架多认证诉求。
引言
企业框架通常需要实现多种认证方式,比如用户名密码、手机验证码、邮箱、企业微信等等。Spring Security可以通过自定义认证器AuthenticationProvider 来实现不同的认证方式。接下来咱们就来探索一下Spring Security具体如何来实现多种认证方式。
实践
最近项目上有对接企业微信需求,所以我们以用户名密码、企业微信登录两种方式来进行实践,其他一些登录方式扩展即可loginType即可。
自定义认证器AuthenticationProvider
首先我们可以通用的AuthenticationProvider,以及对应的认证信息Authentication,实际场景中这两个一般是配套使用。认证器AuthenticationProvider有一个认证方法authenticate(),我们需要实现该认证方法,认证成功之后返回认证信息Authentication。
1.CustomerAuthenticationProvider
package com.rdtalk.framework.security.provider;
import java.util.ArrayList;
import java.util.Map;
import javax.annotation.PostConstruct;
import com.rdtalk.common.exception.ServiceException;
import com.rdtalk.common.utils.MessageUtils;
import com.rdtalk.framework.security.model.CustomOAuth2AuthenticationInfo;
import com.rdtalk.framework.web.exception.BusinessException;
import com.rdtalk.framework.web.service.OAuth2AuthenService;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import lombok.extern.slf4j.Slf4j;
/**
* 通用AuthenticationProvider
*
* @author rdtalk
*/
@Slf4j
public class CustomAuthenticationProvider implements AuthenticationProvider, ApplicationContextAware {
private ApplicationContext context;
private OAuth2AuthenService service;
@PostConstruct
public void initAuth2AuthenService() {
service = context.getBean(OAuth2AuthenService.class);
}
@Override
public Authentication authenticate(Authentication arg0) throws AuthenticationException {
try {
@SuppressWarnings("unchecked")
Map<String, String> map = (Map<String, String>) arg0.getDetails();
if (map == null) {
throw new ServiceException(MessageUtils.message("user.auth.error"));
}
CustomOAuth2AuthenticationInfo authInfo = new CustomOAuth2AuthenticationInfo();
authInfo.setAuthType(map.get("authType"));
authInfo.setEquipinfo(map.get("equipinfo"));
authInfo.setLoginName(map.get("username"));
authInfo.setPassword(arg0.getCredentials() ==