diff --git a/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register-result/register-result.component.html b/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register-result/register-result.component.html index 8666655b12ae93c2e07f0a3a929bf0319ed5eeab..d3675f5720ddf29e314ff7e06a962056e1c12f7b 100644 --- a/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register-result/register-result.component.html +++ b/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register-result/register-result.component.html @@ -4,9 +4,11 @@ {{ 'app.register-result.msg' | i18n: params }} + diff --git a/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register-result/register-result.component.ts b/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register-result/register-result.component.ts index d4b6e67d3c25225475051fb796a22b28fbed6272..23cc848653256a64345a63732a29fd043b51288d 100644 --- a/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register-result/register-result.component.ts +++ b/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register-result/register-result.component.ts @@ -10,6 +10,6 @@ export class UserRegisterResultComponent { params = { email: '' }; email = ''; constructor(route: ActivatedRoute, public msg: NzMessageService) { - this.params.email = this.email = route.snapshot.queryParams['email'] || 'ng-alain@example.com'; + this.params.email = this.email = route.snapshot.queryParams['email'] || 'maxkeysupport@maxkey.top'; } } diff --git a/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register/register.component.html b/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register/register.component.html index 500d5f19e63257fc849f3d2c77b1d86c0af8935d..f7ab78fa2c05e2b3e725e21f19c46ddd22864e69 100644 --- a/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register/register.component.html +++ b/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register/register.component.html @@ -1,6 +1,28 @@

{{ 'app.register.register' | i18n }}

+ + + + + + + {{ 'validation.email.required' | i18n }} + {{ 'validation.email.wrong-format' | i18n }} + + + + + + + + + + {{ 'validation.email.required' | i18n }} + {{ 'validation.email.wrong-format' | i18n }} + + + diff --git a/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register/register.component.ts b/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register/register.component.ts index bafffb80d1f12ee8c7e464e26ec55725f89452d3..b9a583749f13f39bae3cba9e5f08b04bf6347c37 100644 --- a/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register/register.component.ts +++ b/maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/register/register.component.ts @@ -4,8 +4,11 @@ import { Router } from '@angular/router'; import { _HttpClient } from '@delon/theme'; import { MatchControl } from '@delon/util/form'; import { NzSafeAny } from 'ng-zorro-antd/core/types'; +import { NzMessageService } from 'ng-zorro-antd/message'; import { finalize } from 'rxjs/operators'; +import { SignUpService } from '../../../service/signup.service'; + @Component({ selector: 'passport-register', templateUrl: './register.component.html', @@ -13,10 +16,19 @@ import { finalize } from 'rxjs/operators'; changeDetection: ChangeDetectionStrategy.OnPush }) export class UserRegisterComponent implements OnDestroy { - constructor(fb: FormBuilder, private router: Router, private http: _HttpClient, private cdr: ChangeDetectorRef) { + constructor( + fb: FormBuilder, + private signUpService: SignUpService, + private msg: NzMessageService, + private router: Router, + private http: _HttpClient, + private cdr: ChangeDetectorRef + ) { this.form = fb.group( { - mail: [null, [Validators.required, Validators.email]], + username: [null, [Validators.required]], + displayName: [null, [Validators.required]], + email: [null, [Validators.required, Validators.email]], password: [null, [Validators.required, Validators.minLength(6), UserRegisterComponent.checkPassword.bind(this)]], confirm: [null, [Validators.required, Validators.minLength(6)]], mobilePrefix: ['+86'], @@ -31,8 +43,15 @@ export class UserRegisterComponent implements OnDestroy { // #region fields - get mail(): AbstractControl { - return this.form.get('mail')!; + get username(): AbstractControl { + return this.form.get('username')!; + } + + get displayName(): AbstractControl { + return this.form.get('displayName')!; + } + get email(): AbstractControl { + return this.form.get('email')!; } get password(): AbstractControl { return this.form.get('password')!; @@ -92,6 +111,13 @@ export class UserRegisterComponent implements OnDestroy { this.mobile.updateValueAndValidity({ onlySelf: true }); return; } + this.signUpService.produceOtp({ mobile: this.mobile.value }).subscribe(res => { + if (res.code !== 0) { + this.msg.success(`短信发送失败`); + this.cdr.detectChanges(); + } + this.msg.success(`短信发送成功`); + }); this.count = 59; this.cdr.detectChanges(); this.interval$ = setInterval(() => { @@ -104,7 +130,6 @@ export class UserRegisterComponent implements OnDestroy { } // #endregion - submit(): void { this.error = ''; Object.keys(this.form.controls).forEach(key => { @@ -118,15 +143,21 @@ export class UserRegisterComponent implements OnDestroy { const data = this.form.value; this.loading = true; this.cdr.detectChanges(); - this.http - .post('/register?_allow_anonymous=true', data) + this.signUpService + .register(data) .pipe( finalize(() => { this.loading = false; this.cdr.detectChanges(); }) ) - .subscribe(() => { + .subscribe(res => { + if (res.code !== 0) { + this.msg.success(`注册失败`); + this.cdr.detectChanges(); + return; + } + this.msg.success(`注册成功`); this.router.navigate(['passport', 'register-result'], { queryParams: { email: data.mail } }); }); } diff --git a/maxkey-web-frontend/maxkey-web-app/src/app/service/signup.service.ts b/maxkey-web-frontend/maxkey-web-app/src/app/service/signup.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..318b76e983ad219c56c9c84414e686952da1fb44 --- /dev/null +++ b/maxkey-web-frontend/maxkey-web-app/src/app/service/signup.service.ts @@ -0,0 +1,16 @@ +import { Injectable, Inject } from '@angular/core'; +import { _HttpClient, User } from '@delon/theme'; +@Injectable({ + providedIn: 'root' +}) +export class SignUpService { + constructor(private http: _HttpClient) { } + + produceOtp(param: any) { + return this.http.get('/signup/produceOtp?_allow_anonymous=true', param); + } + + register(param: any) { + return this.http.get('/signup/register?_allow_anonymous=true', param); + } +} diff --git a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/ForgotPasswordContorller.java b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/ForgotPasswordContorller.java index b9fa795ff982ceba2fa9a642bcebd2c235cc0ab3..fecc56a0ef6bf13dce4fb7c1a1abd7a77c285111 100644 --- a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/ForgotPasswordContorller.java +++ b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/ForgotPasswordContorller.java @@ -115,10 +115,9 @@ public class ForgotPasswordContorller { @RequestParam String email, @RequestParam String state, @RequestParam String captcha) { - _logger.debug("forgotpassword /forgotpassword/produceEmailOtp."); - _logger.debug("Email {} : " , email); + _logger.debug("/forgotpassword/produceEmailOtp Email {} : " , email); if (!authJwtService.validateCaptcha(state,captcha)) { - _logger.debug("login captcha valid error."); + _logger.debug("captcha valid error."); return new Message(Message.FAIL).buildResponse(); } diff --git a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/RegisterController.java b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/RegisterController.java index 12c5cff5b2253beed7dde248e9d2fd86785a07d2..82b845cacb36118a8a74709e8093c1848f477d22 100644 --- a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/RegisterController.java +++ b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/RegisterController.java @@ -18,39 +18,33 @@ package org.maxkey.web.contorller; import java.io.IOException; -import java.util.Date; +import java.util.regex.Pattern; + import javax.servlet.ServletException; -import org.apache.commons.mail.DefaultAuthenticator; -import org.apache.commons.mail.EmailException; -import org.apache.commons.mail.HtmlEmail; -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; + +import org.maxkey.authn.jwt.AuthJwtService; import org.maxkey.configuration.ApplicationConfig; import org.maxkey.constants.ConstsStatus; import org.maxkey.crypto.password.PasswordReciprocal; -import org.maxkey.entity.Register; +import org.maxkey.entity.Message; import org.maxkey.entity.UserInfo; -import org.maxkey.persistence.service.RegisterService; +import org.maxkey.password.onetimepwd.AbstractOtpAuthn; +import org.maxkey.password.onetimepwd.OtpAuthnService; import org.maxkey.persistence.service.UserInfoService; -import org.maxkey.util.DateUtils; import org.maxkey.util.StringUtils; import org.maxkey.web.WebContext; -import org.maxkey.web.message.Message; -import org.mybatis.spring.SqlSessionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.servlet.ModelAndView; @Controller @@ -58,183 +52,81 @@ import org.springframework.web.servlet.ModelAndView; public class RegisterController { private static Logger _logger = LoggerFactory.getLogger(RegisterController.class); + Pattern mobileRegex = Pattern.compile("^[1][3,4,5,7,8][0-9]{9}$"); + @Autowired - RegisterService registerService; + AuthJwtService authJwtService; @Autowired - @Qualifier("applicationConfig") protected ApplicationConfig applicationConfig; @Autowired - @Qualifier("userInfoService") private UserInfoService userInfoService; @Autowired - private PasswordEncoder passwordEncoder; - - - @RequestMapping(value={"/forward"}) - public ModelAndView forward() { - _logger.debug("register /register/register."); - return new ModelAndView("register/register"); - } + @Qualifier("otpAuthnService") + OtpAuthnService otpAuthnService; - @RequestMapping(value={"/forward/email"}) - public ModelAndView forwardEmail() { - _logger.debug("register /register/register."); - return new ModelAndView("register/registerInst"); - } - - //邮件验证注册 - @RequestMapping(value={"/register"}) - public ModelAndView reg(@ModelAttribute("register") Register register) { - _logger.debug("register /register/register."); - _logger.debug(""+register); - ModelAndView modelAndView= new ModelAndView("register/registered"); - - UserInfo userInfo = registerService.findByEmail(register.getWorkEmail()); - - if(userInfo!=null){ - modelAndView.addObject("registered", 1); - return modelAndView; - } - - register.setId(register.generateId()); - registerService.insert(register); - HtmlEmail email = new HtmlEmail(); - - try { - email.setHostName(applicationConfig.getEmailConfig().getSmtpHost()); - email.setSmtpPort(applicationConfig.getEmailConfig().getPort()); - email.setAuthenticator(new DefaultAuthenticator( - applicationConfig.getEmailConfig().getUsername(), - applicationConfig.getEmailConfig().getPassword() - )); - - email.addTo(register.getWorkEmail(), register.getDisplayName()); - email.setFrom(applicationConfig.getEmailConfig().getSender(), "MaxKey"); - email.setSubject("MaxKey Identity & Access Registration activate Email ."); - - String activateUrl=WebContext.getHttpContextPath()+"/register/forward/activate/"+register.getId(); - - - // set the html message - String emailText=""; - emailText+="activate
"; - emailText+=" or copy "+activateUrl+" to brower."; - emailText+=""; - email.setHtmlMsg(emailText); - - // set the alternative message - email.setTextMsg("Your email client does not support HTML messages"); - - // send the email - email.send(); - } catch (EmailException e) { - e.printStackTrace(); - } - modelAndView.addObject("registered", 0); - return modelAndView; - } - - @GetMapping(value={"/forward/activate/{id}"}) - public ModelAndView confirm(@PathVariable("id") String id) { - _logger.debug("register /register/forward/activate."); - Register register=registerService.get(id); - ModelAndView mav=new ModelAndView("register/activate"); - if(register!=null){ - mav.addObject("model", register); - } - - return mav; - } - - @PostMapping(value={"/activate/{id}"}) - public ModelAndView setPassWord(@PathVariable("id") String id, - @RequestParam String password, - @RequestParam String confirmpassword) { - _logger.debug("register /register/setpassword."); - ModelAndView modelAndView=new ModelAndView("register/activated"); - if(password.equals(confirmpassword)){ - Register register=registerService.get(id); - if(register!=null){ - SqlSession sqlSession = SqlSessionUtils.getSqlSession( - WebContext.getBean("sqlSessionFactory",SqlSessionFactory.class)); - sqlSession.commit(false); - - UserInfo userInfo=new UserInfo(); - userInfo.setUsername(register.getWorkEmail()); - userInfo.setDisplayName(register.getDisplayName()); - - userInfo.setWorkPhoneNumber(register.getWorkPhone()); - userInfo.setEmail(register.getWorkEmail()); - userInfo.setStatus(ConstsStatus.ACTIVE); - userInfo.setDecipherable(PasswordReciprocal.getInstance().encode(password)); - - password = passwordEncoder.encode(password ); - userInfo.setPassword(password); - //default InstId - if(StringUtils.isEmpty(userInfo.getInstId())) { - userInfo.setInstId("1"); - } - userInfo.setPasswordLastSetTime(DateUtils.format(new Date(), DateUtils.FORMAT_DATE_YYYY_MM_DD_HH_MM_SS)); - userInfoService.insert(userInfo); - - registerService.remove(id); - sqlSession.commit(true); - modelAndView.addObject("activate", 1); - }else{ - modelAndView.addObject("activate", 2); - } - }else{ - modelAndView.addObject("activate", 0); - } - return modelAndView; - } + @Autowired + private PasswordEncoder passwordEncoder; + @ResponseBody + @RequestMapping(value = { "/produceOtp" }, produces = {MediaType.APPLICATION_JSON_VALUE}) + public ResponseEntity produceOtp( + @RequestParam String mobile) { + _logger.debug("/signup/produceOtp Mobile {}: " ,mobile); + + _logger.debug("Mobile Regex matches {}",mobileRegex.matcher(mobile).matches()); + if(StringUtils.isNotBlank(mobile) && mobileRegex.matcher(mobile).matches()) { + UserInfo userInfo = new UserInfo(); + userInfo.setUsername(mobile); + userInfo.setMobile(mobile); + AbstractOtpAuthn smsOtpAuthn = otpAuthnService.getByInstId(WebContext.getInst().getId()); + smsOtpAuthn.produce(userInfo); + return new Message(userInfo).buildResponse(); + } + + return new Message(Message.FAIL).buildResponse(); + } + //直接注册 - @RequestMapping(value={"/registeron"}) + @RequestMapping(value={"/register"}) @ResponseBody - public Message registeron(UserInfo userInfo,@RequestParam String emailMobile) throws ServletException, IOException { - - if(StringUtils.isEmpty(emailMobile)) { - return new Message(WebContext.getI18nValue("register.emailMobile.error"),"1"); - } - - if(StringUtils.isValidEmail(emailMobile)) { - userInfo.setEmail(emailMobile); - } - - if(StringUtils.isValidMobileNo(emailMobile)) { - userInfo.setMobile(emailMobile); - } - - if(!(StringUtils.isValidEmail(emailMobile)||StringUtils.isValidMobileNo(emailMobile))) { - return new Message(WebContext.getI18nValue("register.emailMobile.error"),"1"); - } - - UserInfo temp = userInfoService.findByEmailMobile(emailMobile); - - if(temp!=null) { - return new Message(WebContext.getI18nValue("register.emailMobile.exist"),"1"); - } - - temp = userInfoService.findByUsername(userInfo.getUsername()); - if(temp!=null) { - return new Message(WebContext.getI18nValue("register.user.error"),"1"); - } - //default InstId - if(StringUtils.isEmpty(userInfo.getInstId())) { - userInfo.setInstId("1"); - } - - userInfo.setStatus(ConstsStatus.ACTIVE); - - if(userInfoService.insert(userInfo)) { - return new Message(WebContext.getI18nValue("login.text.register.success"),"0"); + public ResponseEntity register( + @ModelAttribute UserInfo userInfo, + @RequestParam String captcha) throws ServletException, IOException { + UserInfo validateUserInfo = new UserInfo(); + validateUserInfo.setUsername(userInfo.getMobile()); + validateUserInfo.setMobile(userInfo.getMobile()); + AbstractOtpAuthn smsOtpAuthn = otpAuthnService.getByInstId(WebContext.getInst().getId()); + if (smsOtpAuthn !=null + && smsOtpAuthn.validate(validateUserInfo, captcha)){ + UserInfo temp = userInfoService.findByEmailMobile(userInfo.getEmail()); + + if(temp != null) { + return new Message(Message.FAIL).buildResponse(); + } + + temp = userInfoService.findByUsername(userInfo.getUsername()); + if(temp != null) { + return new Message(Message.FAIL).buildResponse(); + } + + //default InstId + if(StringUtils.isEmpty(userInfo.getInstId())) { + userInfo.setInstId("1"); + } + String password = userInfo.getPassword(); + userInfo.setDecipherable(PasswordReciprocal.getInstance().encode(password)); + password = passwordEncoder.encode(password ); + userInfo.setPassword(password); + userInfo.setStatus(ConstsStatus.INACTIVE); + + if(userInfoService.insert(userInfo)) { + return new Message().buildResponse(); + } } - return new Message(WebContext.getI18nValue("login.text.register.error"),"1"); - + return new Message(Message.FAIL).buildResponse(); } }