若依登录自定义扩展Springboot+security支持密码、验证码多种登录方式
若依开源框架登录使用的配置大部分都是security自定义的,目前希望在此框架基础上支持自定义的登录,如手机号+密码登录认证、手机号+短信验证码认证。1、自定义登录实现思路主要是实现继承DaoAuthenticationProvider类,重写additionalAuthenticationChecks方法,将通过密码标识来判断是不是需要验证密码和免密验证。2、继承DaoAuthenticatio
·
若依开源框架登录使用的配置大部分都是security自定义的,目前希望在此框架基础上支持自定义的登录,如手机号+密码登录认证、手机号+短信验证码认证。
1、自定义登录实现思路
主要是实现继承DaoAuthenticationProvider类,重写additionalAuthenticationChecks方法,将通过密码标识来判断是不是需要验证密码和免密验证。
2、继承DaoAuthenticationProvider
package com.tuitui.framework.security.filter;
import com.tuitui.common.constant.Constants;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @description: 自定义登录扩展
* @author: lst
* @date: 2020-12-03 14:58
*/
public class CustomLoginAuthenticationProvider extends DaoAuthenticationProvider {
/**
* 免密常量
*/
public static final String CUSTOM_LOGIN_SMS = "CUSTOM_LOGIN_SMS";
public CustomLoginAuthenticationProvider(UserDetailsService userDetailsService) {
super();
setUserDetailsService(userDetailsService);
}
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
if (authentication.getCredentials() == null) {
this.logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
} else {
String presentedPassword = authentication.getCredentials().toString();
if(Constants.CUSTOM_LOGIN_SMS.equals(presentedPassword)){
//短信登录,不验证密码
}else{
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
this.logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
}
}
}
3、修改security配置
/**
* 身份认证接口
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
//添加自己的身份验证类,userDetailsService这个可以自己在重新定义根据那个字段验证用户存在与否
auth.authenticationProvider(new CustomLoginAuthenticationProvider(userDetailsService));
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
并添加你的登录接口匿名访问
4、实现登录接口
controller类
package com.tuitui.web.controller.app;
import com.tuitui.api.domain.model.AppUserCodeForm;
import com.tuitui.api.domain.model.AppUserForm;
import com.tuitui.api.service.IAppLoginService;
import com.tuitui.common.constant.Constants;
import com.tuitui.common.core.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
/**
* @Description APP端关于登录接口
* @author lst
* @date 2020-12-3 16:04
*/
@RestController
@RequestMapping("/app")
@Api(value = "AppLoginController", tags = "APP端关于登录接口")
public class AppLoginController {
@Autowired
private IAppLoginService appLoginService;
/**
* @Description app端手机号+密码登录
* @author lst
* @date 2020-12-3 16:37
* @param appUserForm app端用户密码登录表单
* @return com.tuitui.common.core.domain.AjaxResult
*/
@PostMapping(value = "/login-mobile", produces = "application/json; charset=utf-8")
@ApiOperation(value = "手机号+密码登录", notes = "手机号+密码登录", produces = "application/json")
public AjaxResult loginByMobile(@RequestBody @Valid AppUserForm appUserForm) {
AjaxResult ajax = AjaxResult.success();
String token = appLoginService.loginByMobile(appUserForm);
ajax.put(Constants.TOKEN, token);
return ajax;
}
/**
* @Description 手机号+短信验证码登录
* @author lst
* @date 2020-12-3 16:56
* @param appUserCodeForm app端用户验证码登录表单
* @return com.tuitui.common.core.domain.AjaxResult
*/
@PostMapping(value = "/login-code", produces = "application/json; charset=utf-8")
@ApiOperation(value = "手机号+短信验证码登录", notes = "手机号+短信验证码登录", produces = "application/json")
public AjaxResult loginByCode(@RequestBody @Valid AppUserCodeForm appUserCodeForm) {
AjaxResult ajax = AjaxResult.success();
String token = appLoginService.loginByCode(appUserCodeForm);
ajax.put(Constants.TOKEN, token);
return ajax;
}
}
请求表单AppUserForm、AppUserCodeForm类
package com.tuitui.api.domain.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* @Description app端用户密码登录表单
* @author lst
* @date 2020-12-3 16:04
*/
@Data
@NotNull
@ApiModel(description = "app端用户密码登录表单")
public class AppUserForm implements Serializable {
/**
* 手机号码-对应系统表的username
*/
@ApiModelProperty(name = "mobile", notes = "手机号码",required = true)
@NotEmpty(message = "手机号码不能为空")
private String mobile;
/**
* 用户密码
*/
@ApiModelProperty(name = "passWord", notes = "用户密码",required = true)
@NotEmpty(message = "用户密码不能为空")
private String passWord;
}
package com.tuitui.api.domain.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* @Description app端用户验证码登录表单
* @author lst
* @date 2020-12-3 16:04
*/
@Data
@NotNull
@ApiModel(description = "app端用户验证码登录表单")
public class AppUserCodeForm implements Serializable {
/**
* 手机号码-对应系统表的username
*/
@ApiModelProperty(name = "mobile", notes = "手机号码",required = true)
@NotEmpty(message = "手机号码不能为空")
private String mobile;
/**
* 短信验证码
*/
@ApiModelProperty(name = "smsCode", notes = "短信验证码",required = true)
@NotEmpty(message = "短信验证码不能为空")
private String smsCode;
}
IAppLoginService接口
package com.tuitui.api.service;
import com.tuitui.api.domain.model.AppUserCodeForm;
import com.tuitui.api.domain.model.AppUserForm;
/**
* @DESCRIPTION APP端关于登录接口
* @author lst
* @date 2020-12-3 16:04
*/
public interface IAppLoginService {
String loginByMobile(AppUserForm appUserForm);
String loginByCode(AppUserCodeForm appUserCodeForm);
}
AppLoginServiceImpl实现类
package com.tuitui.api.service.impl;
import com.tuitui.api.domain.model.AppUserCodeForm;
import com.tuitui.api.domain.model.AppUserForm;
import com.tuitui.api.service.IAppLoginService;
import com.tuitui.common.constant.Constants;
import com.tuitui.common.core.domain.model.LoginUser;
import com.tuitui.common.exception.CustomException;
import com.tuitui.common.exception.user.UserPasswordNotMatchException;
import com.tuitui.common.utils.MessageUtils;
import com.tuitui.framework.manager.AsyncManager;
import com.tuitui.framework.manager.factory.AsyncFactory;
import com.tuitui.framework.web.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @description: APP端关于登录接口实现类
* @author: lst
* @date: 2020-12-03 16:35
*/
@Service
public class AppLoginServiceImpl implements IAppLoginService {
@Autowired
private TokenService tokenService;
@Resource
private AuthenticationManager authenticationManager;
/**
* 免密常量
*/
public static final String CUSTOM_LOGIN_SMS = "CUSTOM_LOGIN_SMS";
/**
* @Description app端手机号+密码登录
* @author lst
* @date 2020-12-3 16:37
* @param appUserForm app端用户密码登录表单
* @return java.lang.String
*/
@Override
public String loginByMobile(AppUserForm appUserForm) {
return loginVerify(appUserForm.getMobile(),appUserForm.getPassWord());
}
/**
* @Description 手机号+短信验证码登录
* @author lst
* @date 2020-12-3 16:56
* @param appUserCodeForm app端用户验证码登录表单
* @return java.lang.String
*/
@Override
public String loginByCode(AppUserCodeForm appUserCodeForm) {
//TODO 1、验证验校验 等接入短信在完善
//TODO 2、用户验证
return loginVerify(appUserCodeForm.getMobile(),Constants.CUSTOM_LOGIN_SMS);
}
/**
* @Description 登录验证
* @author lst
* @date 2020-12-3 16:47
* @param userName 用户名
* @param passWord 密码
* @return java.lang.String
*/
private String loginVerify(String userName,String passWord) {
//TODO 1、用户验证
Authentication authentication = null;
try {
//TODO 1.1该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, passWord));
} catch (Exception e) {
if (e instanceof BadCredentialsException) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
} else {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGIN_FAIL, e.getMessage()));
throw new CustomException(e.getMessage());
}
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
//TODO 2、生成token
return tokenService.createToken(loginUser);
}
}
5、postman测试
http://localhost:8080/app/login-mobile、http://localhost:8080/app/login-code
请求任一登录接口,返回token令牌
将token放入任一个接口需要登录的接口访问
更多推荐
所有评论(0)