ValidationPipe in provider - validation

NestJs:
How can I use validation like this:
#UsePipes(ValidationPipe)
in provider?
in file task.serive.ts tried to use #UsePipes(ValidationPipe) before method, but it doesn't appear

you can use like this,
export class LoginDto {
// validation decorator to check for an email field!
#IsEmail()
readonly email: string;
// validation decorators for password field!
#IsNotEmpty()
#IsString()
readonly password: string;
constructor(credentials: CredentialsInterface) {
if (credentials) {
this.email = credentials.email;
this.password = credentials.password;
}
}
}
in your service,
import { validate } from 'class-validator';
const credentials = new LoginDto(req.body);
const errors = await validate(credentials);
if (errors.length) {
throw new BadRequestException({
statusCode: HttpStatus.BAD_REQUEST,
error: HttpErrors.BAD_REQUEST,
message: errors,
});
}

You can't use Nest Enhancers from providers. They only bind to Controller,s Resovlers, and Gateways, as that is where the request enters and exists the server from. To get around this, at least class-validator, you can instantiate your own Validator class and run the validations.

Related

How to inject CacheManager inside Websocket Adapter in Nest JS?

I want to ask for an advice.
In my Nest application, I store all sessions in Redis Database. And I have CacheModule that works with redis so I am able to manually check sessions in DB.
I need to inject CacheModule in WebsocketAdapter class, cause I need to validate sessiondId inside cookie with existing session in my Redis cache.
Here is current version of the WebsocetAdapter class. For now I just decided to tag socket with sessionId and validate it later, but it is not what I want.
export class WebsocketAdapter extends IoAdapter {
createIOServer(port: number, options?: any) {
const server = super.createIOServer(port, options);
server.use(async (socket: AuthenticatedSocket, next) => {
const { cookie: clientCookie } = socket.handshake.headers;
if (!clientCookie) return next(new Error('Не аутентифицирован. Запрос без cookie'));
const { ['connect.sid']: sessionId } = cookie.parse(clientCookie);
if (!sessionId) return next(new Error('Запрос без sessionId'));
socket.user = sessionId;
next();
});
return server;
}
}
I cannot inject CacheModule with constructor, since I extended IoAdapter class and applying WebsocketAdapter like this:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({ credentials: true, origin: true });
const adapter = new WebsocketAdapter(app);
app.useWebSocketAdapter(adapter);
await app.listen(9001);
}
Maybe, I shall apply this adapter as a Middleware to websocket route, but I don't know how to do this.
Can you help me out with this?

ThrottlerGuard not working on Websocket in Nestjs

I'm creating an application that is using Nestjs with websockets, but now I need to add rate limit on the sockets, but analyzing the documentation documentation link and implementing what it says in it, when I use #UseGuards(MyGuard) an error occurs in the application.
My Guard:
#Injectable()
export class NewThrottlerGuard extends ThrottlerGuard {
protected async handleRequest(
context: ExecutionContext,
limit: number,
ttl: number,
): Promise<boolean> {
console.log('Request');
const client = context.switchToWs().getClient();
const ip = client.conn.remoteAddress;
const key = this.generateKey(context, ip);
const ttls = await this.storageService.getRecord(key);
if (ttls.length >= limit) {
throw new ThrottlerException();
}
await this.storageService.addRecord(key, ttl);
return true;
}
}
Websocket:
#UseGuards(NewThrottlerGuard)
#SubscribeMessage('sendMessage')
sendMessage(
#ConnectedSocket() client: Socket,
#MessageBody() message: string,
) {
client.rooms.forEach((room) => {
if (room !== client.id) {
client.broadcast.to(room).emit('message', message);
}
});
}
Error in console:
/node_modules/#nestjs/common/utils/validate-each.util.js:22
throw new InvalidDecoratorItemException(decorator, item, context.name);
^
Error: Invalid guard passed to #UseGuards() decorator (ChatGateway).
at validateEach
The file in: #nestjs/common/utils/validate-each.util.js:22
function validateEach(context, arr, predicate, decorator, item) {
if (!context || !context.name) {
return true;
}
console.log(context, arr)
const errors = arr.some(str => !predicate(str));
if (errors) {
throw new InvalidDecoratorItemException(decorator, item, context.name);
}
return true;
}
i put some console.log then in the terminal it show:
[Function: ChatGateway] [ undefined ]
In Github Throttler documentation they say: You cannot bind the guard with APP_GUARD or app.useGlobalGuards() due to how Nest binds global guards.
So, im using #UseGuards()
The guard itself was written correctly, but it was put in a location that importing it made a circular reference between files, so when #UseGuards() was used it became #UseGuards(undefined) which caused the cryptic error message. Moving the guard to a dedicated file will fix the error
I follow your github reference settings and it doesn't work,The following is my code, where is my setting wrong, and the request to ws is not intercepted(In the handleRequest method)

Axios Post in react js is giving error No 'Access-Control-Allow-Origin' header is present on the requested resource

I am trying to do create Login page using react in my web application with spring boot in backend. I am using spring security JDBC Authentication for login. I am trying to convert my JSP pages to React. Login is working fine with JSP and spring boot. Now i am trying to create same page with react. but when i post using axios post i am getiing error
Access to XMLHttpRequest at 'http://localhost:8080/onlineshopping/login' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
this is axios Post
export const Login = (username, password) => async dispatch => {
console.log(password)
let params = {
username: username,
password: password
}
const res = await axios.post("http://localhost:8080/onlineshopping/login", {params});
dispatch({
type: Login,
payload: res.data
});
};
SecurityConfig.java
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.usersByUsernameQuery("select email, password, enabled from user_detail where email = ?")
.authoritiesByUsernameQuery("select email, role from user_detail where email = ?")
.dataSource(dataSource)
.passwordEncoder(bCryptPasswordEncoder);
}
Pagecontroller.java
#RestController
#CrossOrigin
public class PageController {
#RequestMapping("/login")
public Map<String, Object> login(
#RequestParam(name = "error", required = false) String error,
#RequestParam(name = "logout", required = false) String logout) {
Map<String, Object> map = new HashMap<String, Object>();
System.out.println("Login");
map.put("title", "Login");
if (error != null) {
map.put("message", "Username and Password is invalid!");
}
if (logout != null) {
map.put("logout", "You have logged out successfully!");
}
return map;
}
}
Please tell me why i am getting this error and how to solve it.
You have to add proxy address to your package.json file, e.g.:
},
"proxy": "http://localhost:8080",
"devDependencies": {
Next, you just add all the which is after the localhost, i.e.
axios.get("/onlineshopping/login")
After adding CORS filter configuration in spring boot and content type to application/x-www-form-urlencoded in axios request my problem solved.
export const addProjectTask = (username,password, history) => async dispatch => {
axios.post('http://localhost:8080/onlineshopping/login',
Qs.stringify({
username: username,
password: password
}), {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}})
.then(function (response) {
console.log(response);
history.push("/");
})
.catch(function (error) {
console.log(error);
});
};
You have to create a proxy for API calls.
Here, proxy uses url pattern to match to the api calls and redirecting them to the corresponding server.
Try with the following:
Install http-proxy-middleware
npm install http-proxy-middleware --save
create src/setupProxy.js
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
app.use(proxy('/api', { target: 'http://localhost:8080/' }));
};
Then run your local Dev server

I can't consume microservice Spring

I'm learning java Spring and I want to consume one microservice so I created a form in HTML and I try to send the user and password with axios
var helloWorld = new Vue({
el: '#vue-app',
data:
{
user: "user",
username : "",
password : ""
},
methods:
{
enviar: function()
{
axios.post('/user/login', {
user: this.username,
password: this.password
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
}
});
and I try to get the information
#Controller("/user")
public class UserController {
private final Log log = LogFactory.getLog(UserController.class);
#PostMapping("/login")
public boolean login(#RequestParam("user") String user, #RequestParam("password") String password)
{
log.info("user: " + user + " password: " + password);
return user.equals("hitzu") && password.equals("250693");
}
}`
But when I try to run the code I get error 404 and I try to set the URL in Postman
http://localhost:8080/user/login?user=hitzu&password=250693
but get the same error.
You are probably getting 404 because your controller thinks it should bind a View with the data it fetches.
Tell it not to bind a View essentially making it a REST endpoint and directly write into the HTTP Response Body by annotating your method with #ResponseBody.
Some further info on #ResponseBody from the Documentation

ASP.NET WEB API 2 OWIN Authentication unsuported grant_Type

Hi I am trying to set up OAuth bearrer token authentication in my ASP.NET Web API 2 project.
I have two project one will be the WEB API Project and the other a SPA project.
Here is what I have done so far:
I have created the OWIN Startup class:
[assembly: OwinStartup(typeof(CodeArt.WebApi.App_Start.Startup))]
namespace CodeArt.WebApi.App_Start
{
public class Startup
{
static Startup()
{
PublicClientId = "self";
UserManagerFactory = () => new UserManager<UserModel>(new UserStore<UserModel>());
OAuthOptions = new OAuthAuthorizationServerOptions {
TokenEndpointPath = new PathString("/Token"),
Provider = new OAuthAuthorizatonServer(PublicClientId, UserManagerFactory),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
}
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static Func<UserManager<UserModel>> UserManagerFactory { get; set; }
public static string PublicClientId { get; private set; }
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalBearer);
app.UseOAuthBearerTokens(OAuthOptions);
}
}
I have configured Web API to use only bearer token authentication:
private static void ConfigureBearerTokenAuthentication(HttpConfiguration config)
{
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(Startup.OAuthOptions.AuthenticationType));
}
I have configured WEB API to support CORS:
private static void ConfigureCrossOriginResourseSharing(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
}
I have created the OAuthAuthorizationServerProvider class.From this class I only managed to make my code call this method:
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
if(context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
The if condition inside of it always gets executed.
On my spa project I have the following:
This is my viewModel:
var vm = {
grant_type: "password",
userName: ko.observable(),
password: ko.observable()
};
When the login button gets clicked I call this function:
var http = {
post:function(url, data) {
return $.ajax({
url: url,
data: data,
type: 'POST',
contentType: 'application/json',
dataType: 'jsonp'
});
}
}
function loginClick() {
var model = ko.mapping.toJS(vm.loginModel);
var rez = $.param(model);
http.post("http://localhost:3439/Token", rez)
.done(function (data) {
console.log(data);
})
.fail(function(eror, stuff, otherstuff) {
console.log(eror);
console.log(stuff);
console.log(otherstuff);
});
}
My first attempt I have set the post calls dataType to json and I got this errors:
OPTIONS ...:3439/Token 400 (Bad Request) jquery.js:7845
OPTIONS ...:3439/Token No 'Access-Control-Allow-Origin'
header is present on the requested resource. Origin
'...:3304' is therefore not allowed access.
jquery.js:7845
XMLHttpRequest cannot load ...3439/Token. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin '...3304' is therefore not allowed
access.
The 3 dots represent http://localhost.
The second time arround I set it datatype to jsonp and I got back an error that stated unsupported "unsupported_grant_type".
Both calls make it to ValidateClientAuthentication that I mentioned above but they are both sent back as a failed request.
Now I am guessing that the problem is more related to how I am sending data instead of the grand_type because the SPA template in Visual Studion set's the grant type to grant_type: "password" like I did.
Also I have read that I have to serialize the data not send it in json in order for this to work here is the exact json serialized data that get's sent:
"grant_type=password&userName=aleczandru&password=happynewYear&moduleId=models%2FappPostModels%2FloginModel"
The model id property get's set to all my object in my SPA template by Durandal Framework.
Can anyone tell me what I am doing wrong I have been trying to figure this out for the last two days?
Add the following line of code to GrantResourceOwnerCredentials, which will add the header to the response.
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
for more information refer to:
web-api-2-0-cors-and-individual-account-identity
Like Robin Karlsson said, you should use:
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
in your Startup configuration.
And make sure it's the only cors statement (don't mix them) and the first statement in your Startup.

Resources