7. Spring Boot + Spring Security 短信功能(验证)

1.SmsAuthenticationFilter用于验证短信登陆信息,并且把信息封装到SmsAuthenticationToken!
2.将生成的SmsAuthenticationToken发送到AuthenticationManager中,AutenticationManager会从所有的Token中 选取一个进行验证比对
3.SmsAuthenticationProvider调用UserDetailsService进行具体的Token逻辑验证比对
在这里插入图片描述
在这里插入图片描述

  • SmsCodeAuthenticationFilter继承AbstractAuthenticationProcessingFilter,并且改成自己自己的Filter
    package com.imooc.security.core.authentication.moblie;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

public static final String IMOOC_FROM_mobile_KEY = "mobile";

private String mobileParmeter = IMOOC_FROM_mobile_KEY;
private boolean postOnly = true;

// ~ Constructors
// ===================================================================================================

public SmsCodeAuthenticationFilter() {
	super(new AntPathRequestMatcher("/authentication/mobile", "POST"));
}

// ~ Methods
// ========================================================================================================

public Authentication attemptAuthentication(HttpServletRequest request,
		HttpServletResponse response) throws AuthenticationException {
	if (postOnly && !request.getMethod().equals("POST")) {
		throw new AuthenticationServiceException(
				"Authentication method not supported: " + request.getMethod());
	}

	String mobile = obtainmobile(request);
	

	if (mobile == null) {
		mobile = "";
	}

	mobile = mobile.trim();

	SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile);

	// Allow subclasses to set the "details" property
	setDetails(request, authRequest);

	return this.getAuthenticationManager().authenticate(authRequest);
}


/**
 * 获取前端传入的手机号
 */
protected String obtainmobile(HttpServletRequest request) {
	return request.getParameter(mobileParmeter);
}

/**
 * 将请求的ip sessionID 等设置到验证请求里面去 
 *
 * @param request that an authentication request is being created for
 * @param authRequest the authentication request object that should have its details
 * set
 */
protected void setDetails(HttpServletRequest request,
		SmsCodeAuthenticationToken authRequest) {
	authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}



/**
 * Defines whether only HTTP POST requests will be allowed by this filter. If set to
 * true, and an authentication request is received which is not a POST request, an
 * exception will be raised immediately and authentication will not be attempted. The
 * <tt>unsuccessfulAuthentication()</tt> method will be called as if handling a failed
 * authentication.
 * <p>
 * Defaults to <tt>true</tt> but may be overridden by subclasses.
 */
public void setPostOnly(boolean postOnly) {
	this.postOnly = postOnly;
}

}

  • SmsCodeAuthenticationProvider继承AuthenticationProvider

package com.imooc.security.core.authentication.moblie;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * @author cjj
 * @date 2019年1月29日
 * @email 729165621@qq.com
 * @blog blog.csdn.net/qq_29451823
 */
public class SmsCodeAuthenticationProvider implements AuthenticationProvider{
	
	private UserDetailsService userDetailsService;
	
	/**
	 * 进行身份认证的逻辑
	 */
	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		
		SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken)authentication;
		
		UserDetails user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());
		
		if(user == null) {
			throw new InternalAuthenticationServiceException("无法获取用户信息");
		}
		//token 认证 
		SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(user,user.getAuthorities());
		authenticationResult.setDetails(authenticationToken.getDetails());
		return authenticationResult;
	}
	/**
	 * 在AuthenticationManageer里面挑选一个Provider 来处理传进来的token
	 */
	@Override
	public boolean supports(Class<?> authentication) {
		// 判断传入的authentication是不是SmsCodeAuthenticationToken这种类型的
		return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
	}
	public UserDetailsService getUserDetailsService() {
		return userDetailsService;
	}
	public void setUserDetailsService(UserDetailsService userDetailsService) {
		this.userDetailsService = userDetailsService;
	}
	
	

}

  • SmsCodeAuthenticationToken
package com.imooc.security.core.authentication.moblie;

import java.util.Collection;

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

/**
 * 封装用户信息(登陆前或者登陆后)
 * @author cjj
 * @date 2019年1月29日
 * @email 729165621@qq.com
 * @blog blog.csdn.net/qq_29451823
 */
public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken{
	private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

	// ~ Instance fields
	// ================================================================================================

	private final Object principal;
	// ~ Constructors
	// ===================================================================================================

	/**
	 * This constructor can be safely used by any code that wishes to create a
	 * <code>UsernamePasswordAuthenticationToken</code>, as the {@link #isAuthenticated()}
	 * will return <code>false</code>.
	 *
	 */
	public SmsCodeAuthenticationToken(String mobile) {
		super(null);
		this.principal = mobile;
		
		setAuthenticated(false);//是否认证
	}

	/**
	 * This constructor should only be used by <code>AuthenticationManager</code> or
	 * <code>AuthenticationProvider</code> implementations that are satisfied with
	 * producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
	 * authentication token.
	 *
	 * @param principal
	 * @param credentials
	 * @param authorities
	 */
	public SmsCodeAuthenticationToken(Object principal, 
			Collection<? extends GrantedAuthority> authorities) {
		super(authorities);
		this.principal = principal;
		super.setAuthenticated(true); // must use super, as we override
	}

	// ~ Methods
	// ========================================================================================================


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

		super.setAuthenticated(false);
	}
	
	public Object getPrincipal() {
		return this.principal;
	}
	
	@Override
	public Object getCredentials() {
	
		return null;
	}
	
	@Override
	public void eraseCredentials() {
		super.eraseCredentials();
	}
}

  • SmsCodeAuthenticationSecurityConfig进行文件配置
package com.imooc.security.core.authentication.moblie;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;

/**
 * 短信验证码的安全配置
 * @author cjj
 * @date 2019年1月29日
 * @email 729165621@qq.com
 * @blog blog.csdn.net/qq_29451823
 */
@Component("smsCodeAuthenticationSecurityConfig")
public class SmsCodeAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>{
	
	@Autowired
	private AuthenticationSuccessHandler imoocAuthenticationSuccessHandler;
	
	@Autowired
	private AuthenticationFailureHandler imoocAuthenticationFailureHandler;
	
	@Autowired
	private UserDetailsService userDetailsService;
	 
	@Override
	public void configure(HttpSecurity http) throws Exception {
		SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter();
		smsCodeAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
		smsCodeAuthenticationFilter.setAuthenticationSuccessHandler(imoocAuthenticationSuccessHandler);
		smsCodeAuthenticationFilter.setAuthenticationFailureHandler(imoocAuthenticationFailureHandler);
		
		SmsCodeAuthenticationProvider smsCodeAuthenticationProvider = new SmsCodeAuthenticationProvider();
		smsCodeAuthenticationProvider.setUserDetailsService(userDetailsService);
		
		http.authenticationProvider(smsCodeAuthenticationProvider)
			.addFilterAfter(smsCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
	}
}
 

  • 然后在BrowserSecurityConfig里面加入SmsCodeAuthenticationSecurityConfig配置文件
package com.imooc.security.browser;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import com.imooc.security.core.authentication.moblie.SmsCodeAuthenticationSecurityConfig;
import com.imooc.security.core.properties.SecurityProperties;
import com.imooc.security.core.validate.code.SmsCodeFilter;
import com.imooc.security.core.validate.code.ValidateCodeFilter;

/**
 * 
 * @author cjj
 * @date 2018年9月26日
 * @email 729165621@qq.com
 * @blog blog.csdn.net/qq_29451823
 */
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Autowired
	private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;
	
	@Autowired
	private SecurityProperties securityProperties;
	
	@Autowired
	private AuthenticationSuccessHandler imoccAuthenticationSuccessHandler;
	
	@Autowired
	private AuthenticationFailureHandler imoccAuthenticationFailUrlHandler;
	
	@Autowired
	private DataSource dataSource;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
		JdbcTokenRepositoryImpl tokenRepositoryImpl = new JdbcTokenRepositoryImpl();
		tokenRepositoryImpl.setDataSource(dataSource);
		//tokenRepositoryImpl.setCreateTableOnStartup(true);//自动创建用户信息表
		return tokenRepositoryImpl;
		
	}
	/**
	 * 处理密码加密解密
	 * @return
	 */
	@Bean
	public PasswordEncoder passwordEncode() {
		//PasswordEncoder的一个实现类
		return new BCryptPasswordEncoder();
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		
		ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
		validateCodeFilter.setAuthenticationFailureHandler(imoccAuthenticationFailUrlHandler);
		validateCodeFilter.setSecurityProperties(securityProperties);
		validateCodeFilter.afterPropertiesSet();
		
		SmsCodeFilter smsCodeFilter = new SmsCodeFilter();
		smsCodeFilter.setAuthenticationFailureHandler(imoccAuthenticationFailUrlHandler);
		smsCodeFilter.setSecurityProperties(securityProperties);
		smsCodeFilter.afterPropertiesSet();
		
		http.addFilterBefore(smsCodeFilter,UsernamePasswordAuthenticationFilter.class)//smsCodeFilter过滤器加载到用户名密码过滤器校验的前面
			.addFilterBefore(validateCodeFilter,UsernamePasswordAuthenticationFilter.class)//validatecodeFilter过滤器加载到用户名密码过滤器校验的前面
		    .formLogin()//表单认证
			.loginPage("/authentication/require")//添加自定义登陆界面
			.loginProcessingUrl("/authentication/from")//这个URL用UsernamePasswordAuthenticationFilter来处理
			.successHandler(imoccAuthenticationSuccessHandler)
			.failureHandler(imoccAuthenticationFailUrlHandler)
			.and()
		//配置记住我
			.rememberMe()
			.tokenRepository(persistentTokenRepository())
			.tokenValiditySeconds(securityProperties.getBrowser().getRemeberMeSeconds())
			.userDetailsService(userDetailsService)
		//http.httpBasic()//弹出框认证
			.and()
			.authorizeRequests()//对请求做一个授权
			.antMatchers("/authentication/require"
					,securityProperties.getBrowser().getLoginPage()
					,"/code/*").permitAll()//访问这个页面的时候不需要授权
			.anyRequest()//任何请求
			.authenticated()//身份认证
			.and()
			.csrf().disable()//关闭跨站请求伪造
			.apply(smsCodeAuthenticationSecurityConfig);
	}
}

  • 效果展示

在这里插入图片描述
不输入短信验证码直接登陆
在这里插入图片描述
输入错误的短信验证码
在这里插入图片描述
发送短信验证码后,后台会受到一个6位数字的短信验证码(这儿是手动随机模拟生成),然后输入正确的短信验证码,这儿是设置将Token信息发送到前台页面
在这里插入图片描述
如果重复页面验证,就是返回登陆页面,再登陆一次
在这里插入图片描述
注解:整体代码有一个重复的地方,需要重构。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 是一个用于构建微服务的开源框架,它能够快速搭建项目并且提供了许多便捷的功能和特性。Spring Security 是一个用于处理认证和授权的框架,可以保护我们的应用程序免受恶意攻击。JWT(JSON Web Token)是一种用于身份验证的开放标准,可以被用于安全地传输息。Spring MVC 是一个用于构建 Web 应用程序的框架,它能够处理 HTTP 请求和响应。MyBatis 是一个用于操作数据库的框架,可以简化数据库操作和提高效率。Redis 是一种高性能的键值存储系统,可以用于缓存与数据存储。 基于这些技术,可以搭建一个商城项目。Spring Boot 可以用于构建商城项目的后端服务,Spring Security 可以确保用户息的安全性,JWT 可以用于用户的身份验证Spring MVC 可以处理前端请求,MyBatis 可以操作数据库,Redis 可以用于缓存用户息和商品息。 商城项目的后端可以使用 Spring BootSpring Security 来搭建,通过 JWT 来处理用户的身份验证和授权。数据库操作可以使用 MyBatis 来简化与提高效率,同时可以利用 Redis 来缓存一些常用的数据和息,提升系统的性能。前端请求则可以通过 Spring MVC 来处理,实现商城项目的整体功能。 综上所述,借助于 Spring BootSpring Security、JWT、Spring MVC、MyBatis 和 Redis 这些技术,可以构建出一个高性能、安全可靠的商城项目,为用户提供良好的购物体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值