Angular get string from POST response - java

I am trying to get string "Error. Does this link come from email? Or maybe you have used your token already?" as a response if requesty is not correct (excactly such response I get in Postman) or "You have successfully changed your password." if request is ok, but instead of that on my website when I get directly from param of subscribe I get Object object, but when I use function JSON.stringify then I get something like that.
Here is my code:
submitFunc() {
this.data = '';
if (this.uploadForm.invalid) {
console.log('Password validation invalid')
return;
}
console.log('Password validation correct')
const response = this.restapiService.postResetPassword(this.tokenFromUrl, this.uploadForm.controls['password'].value);
response.subscribe(data => { console.log('a '+JSON.stringify(data)); },
error => { console.log('b '+JSON.stringify(error)); });
}
and
public postResetPassword(token: string, password: string): Observable<any> {
const body = {
'token': token,
'password': password
};
const headers = new HttpHeaders().set('Content-Type', 'application/json; charset=utf-8');
return this.http.post<any>('https://jakuwegiel-backend.herokuapp.com/reset_password', body,{headers: headers});
}
and my part of controller in backend
#PostMapping(value = "/reset_password", consumes="application/json")
public String processResetPassword(#RequestBody TokenAndPassword tokenAndPassword) {
try {
User user = userService.getByResetPasswordToken(tokenAndPassword.getToken());
if (user == null) {
return "message";
} else {
userService.updatePassword(user, tokenAndPassword.getPassword());
System.out.println("You have successfully changed your password.");
}
}
catch (Exception ex) {
System.out.println("aaaaaaaaaaaaa " +ex.getMessage());
return "Error. Does this link come from email? Or maybe you have used your token already?";
}
return "You have successfully changed your password.";
}
Is there anything you need more?

You need to console.log(error.error.text). And then you will be able to make this value in your text message.

Related

Refresh JWT expired token with Angular 11 interceptor from Spring Boot back end

I am working on a spring boot + angular project in which a user logs in from Angular front end to the authentication api on Spring Boot, which returns a JWT token. I also set up an interceptor on Angular that appends the Authorization header with the JWT token for all requests.
I am looking for a way to intercept angualar requests so that when spring boot throws a 401 error once the JWT token is expired, the Angular front end will try to contact the new refreshtoken endpoint with the expired JWT and a new "isRefreshToken" header set to true to receive a new JWT.
This is my current AuthService
#Injectable({
providedIn: 'root',
})
export class AuthService {
constructor(private http: HttpClient) {}
login(username: string, password: string) {
return this.http
.post<iUser>('http://localhost:8080/authenticate', { username, password }).pipe(
tap(res => this.setSession(res)),
shareReplay()
)
}
refreshToken(){
return this.http.post<iUser>('http://localhost:8080/refreshtoken', {responseType: 'text' as 'json'}).pipe(
tap(res => this.setSession(res)),
shareReplay()
)
}
private setSession(authResult) {
let tokenInfo = this.getDecodedAccessToken(authResult.token);
const expiresAt = moment(tokenInfo.exp);
localStorage.setItem('id_token', authResult.token);
localStorage.setItem('expires_at', JSON.stringify(expiresAt.valueOf()));
localStorage.setItem('userId', tokenInfo.userId);
}
logout() {
localStorage.removeItem('id_token');
localStorage.removeItem('expires_at');
localStorage.removeItem('userId');
}
public isLoggedIn() {
return moment().isBefore(this.getExpiration());
}
isLoggedOut() {
return !this.isLoggedIn();
}
getExpiration() {
const expiration = localStorage.getItem('expires_at');
const expiresAt = JSON.parse(expiration);
return moment.unix(expiresAt);
}
getDecodedAccessToken(token: string): any {
try{
return jwt_decode(token);
}
catch(Error){
return null;
}
}
}
While this is the interceptor I am using:
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private router: Router, private authService: AuthService){}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
let url = req.url.includes('localhost');
const idToken = localStorage.getItem('id_token');
if (idToken && url) {
const cloned = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + idToken),
});
console.log(cloned);
return next.handle(cloned);
} else {
return next.handle(req);
}
}
}
I can suggest to you another way of doing this which I used recently to log out a user when the token expires. Let me share my approach first:
loginUser(email: string, password: string) {
const authData: AuthData = { email: email, password: password };
this.http.post<{ token: string, expiresIn: number }>('http://localhost:3000/api/users/login', authData).subscribe( response => {
const token = response.token;
this.token = token;
if(token) {
const expiresInDuration = response.expiresIn;
this.tokenTimer = setTimeout(() => {
this.logout();
}, expiresInDuration*1000);
this.isAuthenticated = true;
this.authStatusListener.next(true);
const now = new Date();
const expirationDate = new Date(now.getTime() + (expiresInDuration * 1000));
this.saveAuthData(token, expirationDate);
this.router.navigate(['']);
}
});
}
logout() {
this.token = null;
this.isAuthenticated = false;
this.authStatusListener.next(false);
clearTimeout(this.tokenTimer);
this.clearAuthData();
this.router.navigate(['']);
}
private saveAuthData(token: string, expirationDate: Date) {
localStorage.setItem('token', token);
localStorage.setItem('expirationDate', expirationDate.toISOString());
}
So what I have done here is I have received a expireIn value which is in seconds when the token will expire. Then I have set a timeout callback method which will be called when that time is reached. Here I've logged out in your case you can call the API for the refresh token & make desired changes as per your requirement. So coming back to the point, I have set the expiration date & time with respect to the current date-time of login with expiresIn duration. Also added a authStatusListener Subject which will listen to the state of the authentication till it expires.
Nothing extra to do in Interceptor/Guard for token expiration
For controlling the logout button in header just do like this:
userIsAuthenticated = false;
private authListenerSubs: Subscription;
constructor(private authService: AuthService) { }
onLogout() {
this.authService.logout();
}
ngOnInit() {
this.authListenerSubs = this.authService.getAuthStatusListener().subscribe(isAuthenticated => {
this.userIsAuthenticated = isAuthenticated;
});
}
ngOnDestroy() {
this.authListenerSubs.unsubscribe();
}
Use userIsAuthenticated in ngIf in the HTML.
For a real scenario you can take help of this github repo.

Angular Post request goes to pending status and does not hit the server

I am trying to get the user list for a email Id using a post request , Sometimes the post request goes to pending status and it stays in the same status forever.If I restart the tomcat then the request works but after some times the same issue occurs.
Below is the post method calling in angular
loadBOEDetailsListByEmail(emailId, password) {
const url = `${environment.url}backofficeemployee/detailsByBoeEmailId/`;
const params = {
resetEmail: emailId
};
const myHeader = new HttpHeaders();
myHeader.append('Content-Type', 'application/x-www-form-urlencoded');
return Observable.create(observer => {
this.http.post(url, params, { headers: myHeader }).subscribe(
(response: any) => {
if (response && response.data && response.data[0] !== undefined) {
this.accountList = response.data;
const boe = response.data[0];
this.checkAccountValidity(boe, password, observer);
} else {
observer.error('No account found');
}
},
() => observer.error('Employee service call failed')
);
});
}
In the java side this is how I am receiving
// Backoffice employee - Details by BoeUserId
#PostMapping(value = "/detailsByBoeEmailId/")
public #ResponseBody Map<String, Object> getBackofficeemployeeDetailsByBoeEmailId(#RequestBody ResetpasswordRequestDto requestDto) {
log.info(" boeEmailId in getBackofficeemployeeDetails {}", requestDto.getResetEmail());
try {
List<BackofficeemployeeResponseDto> backofficeemployeeResponseDto = backofficeemployeeService
.getByBoeEmailId(requestDto.getResetEmail());
return JsonUtils.mapOK(backofficeemployeeResponseDto);
} catch (Exception e) {
log.error("Exception in getBackofficeemployeeDetailsByBoeEmailId", e);
return JsonUtils.mapError(ERROR_MSG + e.getMessage());
}
}

Data is passed within ""(doublequotes) from angularJs to SpringMVC Controller

I am passing data from controller.js to service.js to SpringController.java
but weird thing is happening when i pass $scope.credentials.uname data to Java Controller .
The data passed is coming in doublequotes . When i print the value in Java
its getting printed as "USER" instead of USER.
Also due to this i am not able to save the username in database.
$scope.submitUsername = function()
{
$log.info("username "+$scope.credentials.uname);
Here log is getting printed properly chrome console
username SYS_USER --> without double quotes
loginService.fetchUserType(angular.copy($scope.credentials.uname)).then(function(data)
{
if (data.loginType == 'NotValidUsername')
{
$log.info("Failure")
toaster.pop('information', "Warning", 'Enter Valid UserName');
}
else
{
$log.info("Success")
if (data.loginType == 'database')
{
$scope.isExternalUser = true;
$scope.showSubmitButton = false;
}
else
{
$scope.isExternalUser = false;
$scope.showSubmitButton = false;
}
}
})
};
service.js
fetchUserType : function(userName)
{
var promise = $http({
url : "checkUserType.do",
method : "POST",
data : JSON.stringify(userName)
}).success(function(data, status, header, config, statusText)
{
}).error(function(data, status, header, config, statusText)
{
if(!status === 901)
toaster.pop('error', status, statusText);
}).then(function(response)
{
return response.data;
})
return promise;
}
Java Controller method
#RequestMapping(value = "/checkUserType.do", method = { RequestMethod.GET, RequestMethod.POST })
#ResponseBody
public Object checkUserType(#RequestBody String username,HttpServletRequest request)
{
log.info(" Inside checkUserType "+username);
User user = new User();
user.setUserName(username);
String userType = loginService.checkUserType(user.getUserName());
user.setLoginType(userType);
return user;
}
Output on console is
Inside checkUserType "SYS_USER".
How should i pass data so that i can avoid these ""(doublequotes) being passed to Java Controller
Remove JSON.stringify(userName) from your service.js This is whats adding the double quotes around your request.
Instead your data should just be data: userName. When it gets send to your controller it will be correctly converted to json for your controller to digest.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

Java 8: Functional interface to check permissions and return a response

I am trying to create a function withCheckPermissions which checks if the user has permissions,
If the user is not permission'd return a "Bad Response"
otherwise Return a "success" if it was a POST
otherwise return the contents of a GET request
Here's what I have so far:
public <A extends Response> Response withCheckPermissions(Supplier<A> code) {
User user = getCurrentUser();
if (isAllowed(user)) {
try {
return code.get();
} catch (Exception e) {
return handleError(ERROR_MESSAGE, e);
}
} else {
log.warn("User not allowed...");
return sendBadRequest(NO_ACCESS_MESSAGE);
}
}
I am calling it as:
#POST
#Path("myJob")
public Response sendMail() {
return withCheckPermissions(() -> {
try {
manager.generateEmail();
} catch (Exception e) {
return handleError("Problem sending email", e);
}
return sendSuccess();
});
}
I get errors such as:
Could not find MessageBodyWriter for response object of type: java.util.HashMap of media type: application/octet-stream
Is there a proper way to do it?
I am trying to avoid a construct such as:
if isAllowed(User) {
doSomething()
} else {
return errorResponse
}
As you didnt define the Media Type that your endpoint produces, the type will be "application/octet-stream", unless you inform it on the request header (Accept = "text/plain").
Put #Produces(MediaType.TEXT_PLAIN) to your method and try, should work.

JSP: Error in forwarding page

This question is related to the previous one, when I click over an anchor
send email
it calls servlet using json
$("#Email").click(function() {
var option={
"action":"sendEmail"
};
$.getJSON('StudentManagementServlet',option, function(hasEmail) {
if(hasEmail == false){
// //view form to let user enter his email
$("#CommViaEmail").fadeIn("normal");
}
});
});
in servlet I handle the request
if (action != null && action.equals("sendEmail")) {
//open connection to db
con.setAutoCommit(false);
String email = ParentManagement.getParentEmail(con, stdNo);
if (email != null) {
String commResult = createAccountAndSendEmail(con, parentNo, email);
request.setAttribute("result", commResult);
request.setAttribute("incp", "ResultPage");
RequestDispatcher dispatcher = request.getRequestDispatcher("/index.jsp");
dispatcher.forward(request, response); //doesn't make forward!!!!!
System.out.println(">>send email DONE!!");
con.commit();
return;
} else {
boolean hasEmail = false;
String json = new Gson().toJson(hasEmail);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
}
}
The problem here is if user has an email, then I send an email but request dosn't forward to result page, even the print statement is printed " System.out.println(">>send email DONE!!");" ??
You need to let JS/jQuery do that job. Let the servlet write true as JSON result and in JS do
if (hasEmail) {
window.location = 'index.jsp';
} else {
$("#CommViaEmail").fadeIn("normal"); //view form to let user enter his email
}
Or when you want to control the URL yourself, add the new location to the JSON
Map<String, Object> data = new HashMap<String, Object>();
data.put("hasEmail", true);
data.put("location", "index.jsp");
// ...
with
..., function(data) {
if (data.hasEmail) {
window.location = data.location;
} else {
$("#CommViaEmail").fadeIn("normal"); //view form to let user enter his email
}
}
You are making an AJAX request from the client and are trying to 'forward' that request in the server side.
AJAX requests DONT refresh the page. The hasEmail variable in javascript function will be a string containing the HTML of the index.jsp.

Categories