素材巴巴 > 程序开发 >

若依登录自定义扩展Springboot security支持密码、验证码多种登录方式

程序开发 2023-09-12 12:22:50

若依开源框架登录使用的配置大部分都是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);}@Overrideprotected 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配置

/*** 身份认证接口*/@Overrideprotected 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 {@Autowiredprivate 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 {@Autowiredprivate TokenService tokenService;@Resourceprivate 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*/@Overridepublic 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*/@Overridepublic 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.loadUserByUsernameauthentication = 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、生成tokenreturn tokenService.createToken(loginUser);}}
 

5、postman测试

http://localhost:8080/app/login-mobile、http://localhost:8080/app/login-code

请求任一登录接口,返回token令牌

将token放入任一个接口需要登录的接口访问

 

 

 


标签:

上一篇: 深度学习电脑配置有什么要求? 下一篇:
素材巴巴 Copyright © 2013-2021 http://www.sucaibaba.com/. Some Rights Reserved. 备案号:备案中。