spring security 手机验证码登录
时间: 2023-08-24 07:06:59 浏览: 63
对于Spring Security的手机验证码登录,你可以按照以下步骤进行设置:
1. 首先,你需要添加Spring Security的依赖到你的项目中。在pom.xml文件中,添加以下依赖项:
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
```
2. 接下来,创建一个实现了`UserDetailsService`接口的自定义用户服务类。这个类将负责加载用户信息,包括手机号码和验证码等。你可以在该类中重写`loadUserByUsername`方法,在方法中查询和验证用户信息。
3. 创建一个实现了`AuthenticationProvider`接口的自定义身份验证提供者类。在该类中,你可以根据手机号码和验证码进行用户身份验证。你可以借助第三方库来验证短信验证码的有效性。
4. 现在,配置Spring Security以启用手机验证码登录。在你的应用程序的配置类中,添加以下代码:
```java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
相关问题
springsecurity实现手机验证码登录
Spring Security可以很方便地实现手机验证码登录,步骤如下:
1. 添加spring-security-web和spring-security-config依赖。
```xml
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring-security.version}</version>
</dependency>
```
2. 创建一个实现UserDetailsService接口的类,该类用于根据不同的用户名加载用户信息。
```java
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.selectByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户名不存在");
}
return new UserPrincipal(user);
}
}
```
3. 创建一个实现AuthenticationProvider接口的类,该类用于验证用户的手机号和验证码是否正确。
```java
@Service
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;
String mobile = authenticationToken.getPrincipal().toString();
String code = authenticationToken.getCredentials().toString();
String redisCode = redisTemplate.opsForValue().get(SmsCodeAuthenticationFilter.REDIS_SMS_CODE_KEY_PREFIX + mobile);
if (StringUtils.isBlank(redisCode)) {
throw new BadCredentialsException("验证码不存在或已过期");
}
if (!StringUtils.equals(code, redisCode)) {
throw new BadCredentialsException("验证码不正确");
}
UserDetails userDetails = new UserPrincipal(new User(mobile, "", Collections.emptyList()));
return new SmsCodeAuthenticationToken(userDetails, userDetails.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
}
}
```
4. 创建一个实现AuthenticationFilter接口的类,该类用于处理短信验证码登录请求。
```java
public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public static final String SPRING_SECURITY_FORM_MOBILE_KEY = "mobile";
public static final String SPRING_SECURITY_FORM_CODE_KEY = "code";
public static final String REDIS_SMS_CODE_KEY_PREFIX = "SMS_CODE_";
private String mobileParameter = SPRING_SECURITY_FORM_MOBILE_KEY;
private String codeParameter = SPRING_SECURITY_FORM_CODE_KEY;
private boolean postOnly = true;
public SmsCodeAuthenticationFilter() {
super(new AntPathRequestMatcher("/login/mobile", "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("不支持的请求方式: " + request.getMethod());
}
String mobile = obtainMobile(request);
String code = obtainCode(request);
if (StringUtils.isBlank(mobile)) {
throw new UsernameNotFoundException("手机号不能为空");
}
if (StringUtils.isBlank(code)) {
throw new BadCredentialsException("验证码不能为空");
}
SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile, code);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
protected String obtainMobile(HttpServletRequest request) {
return request.getParameter(mobileParameter);
}
protected String obtainCode(HttpServletRequest request) {
return request.getParameter(codeParameter);
}
protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
public void setMobileParameter(String mobileParameter) {
this.mobileParameter = mobileParameter;
}
public void setCodeParameter(String codeParameter) {
this.codeParameter = codeParameter;
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
public final String getMobileParameter() {
return mobileParameter;
}
public final String getCodeParameter() {
return codeParameter;
}
}
```
5. 在WebSecurityConfigurerAdapter的子类中进行配置。
```java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private SmsCodeAuthenticationProvider smsCodeAuthenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login/mobile").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").defaultSuccessURL("/home").permitAll()
.and()
.logout().logoutUrl("/logout").permitAll()
.and()
.addFilterBefore(smsCodeAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(smsCodeAuthenticationProvider)
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SmsCodeAuthenticationFilter smsCodeAuthenticationFilter() {
SmsCodeAuthenticationFilter filter = new SmsCodeAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler((request, response, authentication) -> {
response.setContentType("application/json;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\": 0, \"message\": \"登录成功\"}");
out.flush();
out.close();
});
filter.setAuthenticationFailureHandler((request, response, exception) -> {
response.setContentType("application/json;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("{\"code\": 1, \"message\": \"" + exception.getMessage() + "\"}");
out.flush();
out.close();
});
return filter;
}
}
```
6. 在前端页面中添加短信验证码登录的表单。
```html
<form action="/login/mobile" method="post">
<div>
<label>手机号:</label>
<input type="text" name="mobile" />
</div>
<div>
<label>验证码:</label>
<input type="text" name="code" />
<button type="button" onclick="sendSmsCode()">发送验证码</button>
</div>
<div>
<button type="submit">登录</button>
</div>
</form>
```
7. 在后端控制器中添加发送短信验证码的接口。
```java
@RestController
public class SmsCodeController {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@GetMapping("/sms/code")
public void sendSmsCode(String mobile) {
String code = RandomStringUtils.randomNumeric(6);
redisTemplate.opsForValue().set(SmsCodeAuthenticationFilter.REDIS_SMS_CODE_KEY_PREFIX + mobile, code, 5, TimeUnit.MINUTES);
// 发送短信验证码
}
}
```
以上就是使用Spring Security实现手机验证码登录的全部步骤。
springsecurity 实现验证码登录
Spring Security可以通过自定义过滤器来实现验证码登录,主要步骤如下:
1. 添加依赖
在pom.xml文件中添加以下依赖:
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.kaptcha</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
```
2. 配置验证码生成器
在Spring Security的配置类中定义验证码生成器:
```java
@Bean
public DefaultKaptcha kaptcha() {
Properties properties = new Properties();
properties.setProperty("kaptcha.border", "no");
properties.setProperty("kaptcha.textproducer.font.color", "black");
properties.setProperty("kaptcha.image.width", "150");
properties.setProperty("kaptcha.image.height", "50");
properties.setProperty("kaptcha.textproducer.char.length", "4");
Config config = new Config(properties);
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
```
3. 定义验证码过滤器
创建一个验证码过滤器类,继承`OncePerRequestFilter`,重写`doFilterInternal`方法,在其中判断是否需要验证验证码,如果是则验证并抛出异常。
```java
public class CaptchaFilter extends OncePerRequestFilter {
private final static String CAPTCHA_SESSION_KEY = "captcha_key";
private final static String LOGIN_URL = "/login";
@Autowired
private DefaultKaptcha kaptcha;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (LOGIN_URL.equals(request.getRequestURI()) && request.getMethod().equalsIgnoreCase("post")) {
try {
validate(request);
} catch (CaptchaException e) {
request.setAttribute("errorMessage", e.getMessage());
request.getRequestDispatcher("/login").forward(request, response);
return;
}
}
filterChain.doFilter(request, response);
}
private void validate(HttpServletRequest request) throws CaptchaException {
String captchaCode = request.getParameter("captchaCode");
String captchaSession = (String) request.getSession().getAttribute(CAPTCHA_SESSION_KEY);
if (StringUtils.isEmpty(captchaCode) || StringUtils.isEmpty(captchaSession)
|| !captchaCode.equalsIgnoreCase(captchaSession)) {
throw new CaptchaException("验证码错误");
}
}
}
```
其中`CaptchaException`为自定义异常类,用于抛出验证码校验失败的异常信息。
4. 注册验证码过滤器
将验证码过滤器注册到Spring Security的配置中:
```java
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new CaptchaFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/login", "/captcha").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").defaultSuccessUrl("/index")
.and()
.logout().logoutSuccessUrl("/login").permitAll()
.and()
.csrf().disable();
}
```
其中,`addFilterBefore`方法用于将验证码过滤器添加到Spring Security的过滤器链中。
5. 添加验证码生成接口
在控制器中添加一个生成验证码的接口,用于获取验证码图片和将验证码存储到session中:
```java
@GetMapping("/captcha")
public void captcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setHeader("Cache-Control", "no-store, no-cache");
response.setContentType("image/jpeg");
String captchaText = kaptcha.createText();
BufferedImage captchaImage = kaptcha.createImage(captchaText);
request.getSession().setAttribute(CAPTCHA_SESSION_KEY, captchaText);
ServletOutputStream outputStream = response.getOutputStream();
ImageIO.write(captchaImage, "jpg", outputStream);
IOUtils.closeQuietly(outputStream);
}
```
6. 修改登录页面
在登录页面中添加一个输入框和验证码图片:
```html
<form method="post" action="/login">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" class="form-control" id="username" name="username" placeholder="请输入用户名">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" id="password" name="password" placeholder="请输入密码">
</div>
<div class="form-group">
<label for="captchaCode">验证码</label>
<div class="input-group">
<input type="text" class="form-control" id="captchaCode" name="captchaCode" placeholder="请输入验证码">
<div class="input-group-append">
<img src="/captcha" onclick="this.src='/captcha?'+Math.random()" style="cursor:pointer;">
</div>
</div>
</div>
<button type="submit" class="btn btn-primary">登录</button>
</form>
```
以上就是Spring Security实现验证码登录的步骤。