To avoid a flood of fake users let's implement the email registration confirmation.
And, of course, new entity class:
And repository:
Update
Now it's time to create a method for confirmation email sending - update our
NOTE:
That's all for this part. Let's look at our frontend.
{
#3 Update
#4 IMPORTANT: Unfortunately, we have no ability to provide a fixed link to some specific component which could validate the token. All the links from external sources (e.g. email) will forward us to the default application page. But we are able to tell our application that we want to confirm our registration and provide a token by using GET-parameters. So we need to create a special handler in the
#5 And finally we can finish the creating of
The Algorithm
- Create the new account setting
isEnabled
field value tofalse
. - Generate a random string token which will be a key for registration confirmation.
- Send this token to a newly registered user providing a convenient link already containing it.
- Set
isEnabled
account field totrue
, after user followed the link sent in specified period of time.
Backend
Database
At first, we need a new table for registration tokens storing:
CREATE TABLE public.verification_token
(
id serial NOT NULL,
token character varying,
expiry_date timestamp without time zone,
user_id integer,
PRIMARY KEY (id)
);
ALTER TABLE public.verification_token
ADD CONSTRAINT verification_token_users_fk FOREIGN KEY (user_id)
REFERENCES public.users (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE CASCADE;
And, of course, new entity class:
And repository:
Services
Then we need to implement features for token management - create, validate and send by email.Update
UserDetailsServiceImpl
adding methods for token creation and validation:
override fun createVerificationTokenForUser(token: String, user: User) {
tokenRepository.save(VerificationToken(token, user))
}
override fun validateVerificationToken(token: String): String {
val verificationToken: Optional<VerificationToken> = tokenRepository.findByToken(token)
if (verificationToken.isPresent) {
val user: User = verificationToken.get().user
val cal: Calendar = Calendar.getInstance()
if ((verificationToken.get().expiryDate.time - cal.time.time) <= 0) {
tokenRepository.delete(verificationToken.get())
return TOKEN_EXPIRED
}
user.enabled = true
tokenRepository.delete(verificationToken.get())
userRepository.save(user)
return TOKEN_VALID
} else {
return TOKEN_INVALID
}
}
Now it's time to create a method for confirmation email sending - update our
EmailServiceImpl
:
@Value("\${host.url}")
lateinit var hostUrl: String
@Autowired
lateinit var userDetailsService: UserDetailsServiceImpl
...
override fun sendRegistrationConfirmationEmail(user: User) {
val token = UUID.randomUUID().toString()
userDetailsService.createVerificationTokenForUser(token, user)
val link = "$hostUrl/?token=$token&confirmRegistration=true"
val msg = "<p>Please, follow the link to complete your registration:</p><p><a href=\"$link\">$link</a></p>"
user.email?.let{sendHtmlMessage(user.email!!, "KSVG APP: Registration Confirmation", msg)}
}
NOTE:
- I recommend take host URL as application.properties parameter
- In our link we send two GET parameters (
token
andconfirmRegistration
) to the default page. I will explain why a bit later
Controllers
Modify our
AuthController:
- Set
isEnabled
field value tofalse
for the new users - Send confirmation email after creating a new account
- Create controller for token validation
- IMPORTANT: check whether account is confirmed while user is logging in
Frontend
At first, we need to create a new component for registration confirm, so
#1 Create a new component
RegistrationConfirmPage.vue
#2 Add a new route to
router.js
with parameter :token
:{
path: '/registration-confirm/:token',
name: 'RegistrationConfirmPage',
component: RegistrationConfirmPage
}
#3 Update
SignUp.vue
- say new users that they have to follow the link in the email.
#4 IMPORTANT: Unfortunately, we have no ability to provide a fixed link to some specific component which could validate the token. All the links from external sources (e.g. email) will forward us to the default application page. But we are able to tell our application that we want to confirm our registration and provide a token by using GET-parameters. So we need to create a special handler in the
App.vue
which redirects us to RegistrationConfirmPage.vue
with :token
parameter after home page is loaded:
methods: {
confirmRegistration() {
if (this.$route.query.confirmRegistration === 'true' && this.$route.query.token != null) {
this.$router.push({name: 'RegistrationConfirmPage', params: { token: this.$route.query.token}});
}
},
...
mounted() {
this.confirmRegistration();
}
#5 And finally we can finish the creating of
RegistrationConfirmPage.vue
which sends the token to backend controller and show the message depending on request success:Ways to Improve
- Use events and listeners
- Create a beautiful confirmation email
Comments
Post a Comment