新增springsecurity短信支持
This commit is contained in:
parent
9e515b1d62
commit
b5010197d3
|
@ -2,43 +2,74 @@ package net.maku.framework.security.config;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import net.maku.framework.security.exception.SecurityAuthenticationEntryPoint;
|
import net.maku.framework.security.exception.SecurityAuthenticationEntryPoint;
|
||||||
|
import net.maku.framework.security.mobile.MobileAuthenticationProvider;
|
||||||
|
import net.maku.framework.security.mobile.MobileUserDetailsService;
|
||||||
|
import net.maku.framework.security.mobile.MobileVerifyCodeService;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SpringSecurity 配置文件
|
||||||
|
*
|
||||||
|
* @author 阿沐 babamu@126.com
|
||||||
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||||
public class SecurityConfig {
|
public class SecurityConfig {
|
||||||
private final UserDetailsService userDetailsService;
|
|
||||||
private final OncePerRequestFilter authenticationTokenFilter;
|
private final OncePerRequestFilter authenticationTokenFilter;
|
||||||
private final PermitResource permitResource;
|
private final PermitResource permitResource;
|
||||||
|
private final UserDetailsService userDetailsService;
|
||||||
|
private final MobileUserDetailsService mobileUserDetailsService;
|
||||||
|
private final MobileVerifyCodeService mobileVerifyCodeService;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
|
DaoAuthenticationProvider daoAuthenticationProvider() {
|
||||||
return authenticationConfiguration.getAuthenticationManager();
|
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
|
||||||
|
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
|
||||||
|
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
|
||||||
|
|
||||||
|
return daoAuthenticationProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public AuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
MobileAuthenticationProvider mobileAuthenticationProvider() {
|
||||||
return new DefaultAuthenticationEventPublisher(applicationEventPublisher);
|
return new MobileAuthenticationProvider(mobileUserDetailsService, mobileVerifyCodeService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuthenticationManager authenticationManager() {
|
||||||
|
List<AuthenticationProvider> providerList = new ArrayList<>();
|
||||||
|
providerList.add(daoAuthenticationProvider());
|
||||||
|
providerList.add(mobileAuthenticationProvider());
|
||||||
|
|
||||||
|
ProviderManager providerManager = new ProviderManager(providerList);
|
||||||
|
providerManager.setAuthenticationEventPublisher(new DefaultAuthenticationEventPublisher(applicationEventPublisher));
|
||||||
|
|
||||||
|
return providerManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -53,8 +84,7 @@ public class SecurityConfig {
|
||||||
.and().authorizeRequests()
|
.and().authorizeRequests()
|
||||||
.antMatchers(permits).permitAll()
|
.antMatchers(permits).permitAll()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
.and().userDetailsService(userDetailsService)
|
.and().exceptionHandling().authenticationEntryPoint(new SecurityAuthenticationEntryPoint())
|
||||||
.exceptionHandling().authenticationEntryPoint(new SecurityAuthenticationEntryPoint())
|
|
||||||
.and().headers().frameOptions().disable()
|
.and().headers().frameOptions().disable()
|
||||||
.and().csrf().disable()
|
.and().csrf().disable()
|
||||||
;
|
;
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
package net.maku.framework.security.mobile;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.context.MessageSource;
|
||||||
|
import org.springframework.context.MessageSourceAware;
|
||||||
|
import org.springframework.context.support.MessageSourceAccessor;
|
||||||
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||||
|
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||||
|
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机短信登录 AuthenticationProvider
|
||||||
|
*
|
||||||
|
* @author 阿沐 babamu@126.com
|
||||||
|
*/
|
||||||
|
public class MobileAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
|
||||||
|
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||||
|
private final GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
|
||||||
|
private final MobileUserDetailsService mobileUserDetailsService;
|
||||||
|
private final MobileVerifyCodeService mobileVerifyCodeService;
|
||||||
|
|
||||||
|
public MobileAuthenticationProvider(MobileUserDetailsService mobileUserDetailsService, MobileVerifyCodeService mobileVerifyCodeService) {
|
||||||
|
this.mobileUserDetailsService = mobileUserDetailsService;
|
||||||
|
this.mobileVerifyCodeService = mobileVerifyCodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
|
Assert.isInstanceOf(MobileAuthenticationToken.class, authentication,
|
||||||
|
() -> messages.getMessage(
|
||||||
|
"MobileAuthenticationProvider.onlySupports",
|
||||||
|
"Only MobileAuthenticationProvider is supported"));
|
||||||
|
|
||||||
|
MobileAuthenticationToken authenticationToken = (MobileAuthenticationToken) authentication;
|
||||||
|
String mobile = authenticationToken.getName();
|
||||||
|
String code = (String) authenticationToken.getCredentials();
|
||||||
|
|
||||||
|
try {
|
||||||
|
UserDetails userDetails = mobileUserDetailsService.loadUserByMobile(mobile);
|
||||||
|
if (userDetails == null) {
|
||||||
|
throw new BadCredentialsException("Bad credentials");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 短信验证码效验
|
||||||
|
if (mobileVerifyCodeService.verifyCode(mobile, code)) {
|
||||||
|
return createSuccessAuthentication(authentication, userDetails);
|
||||||
|
} else {
|
||||||
|
throw new BadCredentialsException("mobile code is not matched");
|
||||||
|
}
|
||||||
|
} catch (UsernameNotFoundException ex) {
|
||||||
|
throw new BadCredentialsException(this.messages
|
||||||
|
.getMessage("MobileAuthenticationProvider.badCredentials", "Bad credentials"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Authentication createSuccessAuthentication(Authentication authentication, UserDetails user) {
|
||||||
|
MobileAuthenticationToken result = new MobileAuthenticationToken(user, null,
|
||||||
|
authoritiesMapper.mapAuthorities(user.getAuthorities()));
|
||||||
|
result.setDetails(authentication.getDetails());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<?> authentication) {
|
||||||
|
return MobileAuthenticationToken.class.isAssignableFrom(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
Assert.notNull(mobileUserDetailsService, "mobileUserDetailsService must not be null");
|
||||||
|
Assert.notNull(mobileVerifyCodeService, "mobileVerifyCodeService must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMessageSource(MessageSource messageSource) {
|
||||||
|
this.messages = new MessageSourceAccessor(messageSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package net.maku.framework.security.mobile;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机短信登录 AuthenticationToken
|
||||||
|
*
|
||||||
|
* @author 阿沐 babamu@126.com
|
||||||
|
*/
|
||||||
|
public class MobileAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
|
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||||
|
private final Object principal;
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
public MobileAuthenticationToken(Object principal, String code) {
|
||||||
|
super(null);
|
||||||
|
this.principal = principal;
|
||||||
|
this.code = code;
|
||||||
|
setAuthenticated(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MobileAuthenticationToken(Object principal, String code, Collection<? extends GrantedAuthority> authorities) {
|
||||||
|
super(authorities);
|
||||||
|
this.principal = principal;
|
||||||
|
this.code = code;
|
||||||
|
super.setAuthenticated(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
|
||||||
|
Assert.isTrue(!isAuthenticated,
|
||||||
|
"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
|
||||||
|
super.setAuthenticated(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getCredentials() {
|
||||||
|
return this.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return this.principal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eraseCredentials() {
|
||||||
|
super.eraseCredentials();
|
||||||
|
this.code = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package net.maku.framework.security.mobile;
|
||||||
|
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机短信登录,UserDetailsService
|
||||||
|
*
|
||||||
|
* @author 阿沐 babamu@126.com
|
||||||
|
*/
|
||||||
|
public interface MobileUserDetailsService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过手机号加载用户信息
|
||||||
|
*
|
||||||
|
* @param mobile 手机号
|
||||||
|
* @return 用户信息
|
||||||
|
* @throws UsernameNotFoundException 不存在异常
|
||||||
|
*/
|
||||||
|
UserDetails loadUserByMobile(String mobile) throws UsernameNotFoundException;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package net.maku.framework.security.mobile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机短信登录,验证码效验
|
||||||
|
*
|
||||||
|
* @author 阿沐 babamu@126.com
|
||||||
|
*/
|
||||||
|
public interface MobileVerifyCodeService {
|
||||||
|
|
||||||
|
boolean verifyCode(String mobile, String code);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user