I am using Restangular with Spring's oauth security and in the client side i am using Restangular for login request.
Code in OAuth2ServerConfiguration:
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("clientapp")
.authorizedGrantTypes("password", "refresh_token")
.authorities("USER")
.scopes("read", "write")
.secret("abc");
}
Login with postman needs these configurations:
1-Set Authorization as "Basic Auth".
2-Set username,password as {"username":"clientapp","password":"abc"}//credentials to access server side
3-In request body through "x-www-form-urlencoded" three parameters are sent.
{"username":"abc#gmail.com","password":"abc123","grant_type":"password"}//credentials to login which are checked from database.
This will do a successful login.but i cannot understand how to use these configurations in Angular JS Restangular call.
currently m trying with this.
In Config:
RestangularProvider.withConfig(function (RestangularConfigurer) {
return RestangularConfigurer.setDefaultHeaders({ "Authorization": "Basic Y2xpZW50YXBwOkxNUw==",
"username":"clientapp",
"password":"abc",
"Content-type": "application/x-www-form-urlencoded; charset=utf-8"
});
In Controller:
Restangualar.all("oauth/login").post({username;$scope.user.username,
password:"$scope.user.password","grant_type":"password"}).then(function(){
console.log(res);
});
But I am getting this error:
error:"unauthorized",error_description:"Full authentication is required to access this resource"
in browser.
Note:This resource is not secured.
Any Solution???
Update: I forgot to added a main information that my frontend with angular is running independently on localhost(through xampp) while spring login backend is on localhost:8080..
Error in network tab:
2-
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.anyRequest().permitAll()
//.antMatchers("/users").permitAll()
.antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll()
.and().csrf().disable();
}
3-
endpoints
.tokenStore(this.tokenStore)
.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService)
.addInterceptor(new HandlerInterceptorAdapter() {
public boolean preHandle(HttpServletRequest hsr, HttpServletResponse rs, Object o,FilterChain chain) throws Exception {
rs.setHeader("Access-Control-Allow-Origin", "*");
rs.setHeader("Access-Control-Allow-Methods", "GET,OPTIONS,POST");
// rs.setHeader("Access-Control-Max-Age", "7200");
rs.setHeader("Access-Control-Allow-Headers", "Origin, X- Requested-With, Content-Type, Accept, Authorization");
HttpServletRequest httpServletRequest = (HttpServletRequest) hsr;
if (httpServletRequest.getMethod().equalsIgnoreCase("OPTIONS")) {
chain.doFilter(hsr, rs);
} else {
// In case of HTTP OPTIONS method, just return the response
return true;
}
return false;
}
});
You can use Restangular custom post. See documentation.
Example:
Restangular.service("/oauth/login").one().customPOST(
{},
'',
{
// Params...
grant_type: 'password',
client_id: 'clientapp',
client_secret: 'abc',
username: 'abc#gmail.com',
password: 'abc123',
scope: 'read, write'
},
{
// headers...
}).then(
function (response) {
// Manage successfull response
},
function () {
// Manage error response
}
);
Hope it helps
UPDATED:
It seems to be a CORS problem, lots of answers already for it, but in your case using XAMPP you will need to configure your apache server:
https://enable-cors.org/server_apache.html.
PREVIOUS ANSWER BEFORE UPDATE:
The advantage of using restangular is the ability to manage resources in a more semantic way and the ability to get nested resources. All these advantages don't really apply for a call just to retrieve a token from an oauth2 provider.
I would recommend to forget about using restangular for this specific call (you still can use it for everything else in your application) and convert this call to a simple $http.post.
$http.post('oauth/login',
{ username;$scope.user.username,
password:"$scope.user.password",
"grant_type":"password"
},
{
headers: { "Authorization": "Basic Y2xpZW50YXBwOkxNUw==",
"username":"clientapp",
"password":"abc",
"Content-type": "application/x-www-form-urlencoded; charset=utf-8"
}
})
.then(function(response) {
Restangular.setDefaultHeaders({
"Authorization": "Bearer " + response.token
});
});
So, you just use $http.post, and on its response set the default headers in angular to use the retrieved token.
Cheers,
Related
When I send axios put to login, My back-end (Spring Boot) used UserDetails get empty login (""). I thought that, my variables in axios is incorrect. Even I set hardcoded data to check whether the collected data from the form is correct. Unfortunately, I'm still sending an empty string.
const handleSubmit = (event) => {
const axios = require('axios').default;
event.preventDefault();
axios.defaults.withCredentials = true
axios({
method: 'post',
url: 'http://localhost:8080/login',
data: {
'accountLogin': accountLogin,
'passwordAccount': passwordAccount
}
})
.then(function (response) {
console.log(response);
console.log('Good!')
})
.catch(function (error) {
console.log(error);
console.log('error :<')
});
result username in spring UserDetails
[result in my browser]
Spring security configure:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/", "/login", "/register", "/swagger-ui**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("http://localhost:3000")
.defaultSuccessUrl("/index", true)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.logout().permitAll()
.invalidateHttpSession(true);
}
there are several faults in your code and i highly suggest you read the chapter on formLogin in the spring security documentation
You have configured this:
.formLogin()
formLogin means that you are going to use the built in login functionality in spring security. This is a form login, meaning it takes FORM parameters. You are sending your login parameters as JSON which is completely different.
sending form data with fetch
const formData = new FormData();
formData.append('username', accountLogin);
formData.append('password', accountPassword);
axios({
url: "http://localhost:8080/login",
method: "POST",
data: formData
});
Spring security formLogin takes in a usernameand a password per default as form parameters. Not json. And it will create a default login address for you to post the data to at http://localhost:8080/login
.loginPage("http://localhost:3000")
Should be removed. Spring will provide a custom built in login page that will get served if you hit a protected endpoint when you are unauthorized. If you wish to serve a different endpoint, you set this here and make sure that a pake is served there. For instance:
.loginPage("/myCustomLogin")
And then it is up to you to make sure that a login page is served from here otherwise you will get a 404 from spring security.
Depending on how you are packaging your application, if you have a node server for your frontend and a spring server for the backend, then you dont need to use loginPage you just post form data to /login. If you on the otherhand server the loginpage from the spring server, you set loginPage to some value, build an endpoint there, package the html files in the spring server, and write code that will serve the HTML page when you hit that endpoint.
This is a better way of sending post requests with Axios. try this, if it didn't work I guess the problem is with your back-end code.
axios.post('http://localhost:8080/login', {
accountLogin: accountLogin,
passwordAccount: passwordAccount
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
let input = {
'email': email,
'password': password
};
axios({
method:'POST',
url: URL,
headers: {
'Content-type': 'application/json; charset=utf-8',
'Accept': 'application/json; charset=utf-8'
},
data: input
}).then(function (response){
console.log(response);
})
.catch(function (error) {
});
I try to request API with axios using method post. It not seen set request headers content-type,but if I using jquery ajax it ok.
Usually the charset=utf-8 is not set along with headers.
Content-type: application/json; charset=utf-8 designates the content to be in JSON format, encoded in the UTF-8 character encoding. Designating the encoding is somewhat redundant for JSON, since the default (only?) encoding for JSON is UTF-8.
its a bug in axios -.- there are multiple issues for this Problem.
I can show you my solution. I hope it's working for you, too.
import qs from 'qs'
let input = qs.stringify {
'email': email,
'password': password
});
axios
.post(URL, input)
.then(response => {
console.log(response.headers)
console.log(response.data)
})
.catch(function(error) {
console.error(error)
})
Spring Framework provides first class support for CORS. CORS must be processed before Spring Security because the pre-flight request will not contain any cookies (i.e. the JSESSIONID). If the request does not contain any cookies and Spring Security is first, the request will determine the user is not authenticated (since there are no cookies in the request) and reject it.
The easiest way to ensure that CORS is handled first is to use the CorsFilter. Users can integrate the CorsFilter with Spring Security by providing a CorsConfigurationSource using the following:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// by default uses a Bean by the name of corsConfigurationSource
.cors().and()
...
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
UrlBasedCorsConfigurationSource source = new
UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
My app uses IBM Watson Speech-to-Text, which requires an access token. From the command line I can get the access token with curl:
curl -X GET --user my-user-account:password \
--output token \
"https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api"
When I make an HTTP request using Angular's $http service I get a CORS error:
var data = {
user: 'my-user-account:password',
output: 'token'
};
$http({
method: 'GET',
url: 'https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api',
data: data,
}).then(function successCallback(response) {
console.log("HTTP GET successful");
}, function errorCallback(response) {
console.log("HTTP GET failed");
});
The error message says:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://127.0.0.1:8080' is therefore not allowed
access. The response had HTTP status code 401.
As I understand, it's not possible to do CORS from Angular; CORS has to be done from the server. I know how to do CORS with Node but I'm using Firebase as the server.
Firebase has documentation about making HTTP requests with CORS. The documentation says to write this:
$scope.getIBMToken = functions.https.onRequest((req, res) => {
cors(req, res, () => {
});
});
First, that doesn't work. The error message is functions is not defined. Apparently functions isn't in the Firebase library? I call Firebase from index.html:
<script src="https://www.gstatic.com/firebasejs/4.3.0/firebase.js"></script>
My controller injects dependencies for $firebaseArray, $firebaseAuth, and $firebaseStorage. Do I need to inject a dependency for $firebaseHttp or something like that?
Second, how do I specify the method ('GET'), the URL, and the data (my account and password)?
if you want to send credentials with angular, just set withCredentials=true. I am also using CORS with Angular v4, for your HTTP header error, you are right. Header Access-Control-Allow-Origin must be added on server side, check if you have settings in your api to allow certain domains, urls, pages, because google api's has this function, so check where you get token there should be some settings.
Here is example, how I am calling API with CORS, using typescript:
broadcastPresense(clientId: string) {
const headers = new Headers({'Content-Type':'application/json','withCredentials':'true'});
return this.http.post('http://localhost/api.php',
{
'jsonrpc': '2.0',
'method': 'somemethod',
'params': {'client_id': clientId},
'id': CommonClass.generateRandomString(16)
},{headers: headers, withCredentials:true}).map(
(res: Response) => {
console.log(res);
const data = res.json();
console.log(data);
if (data.error == null) {
return data.result;
} else if (data.error != null) {
throw data.error;
}
throw data.error;
}
).catch(
(error) => {
this.router.navigate(['/error',3],{queryParams: {desc:'Server error'}});
return Observable.throw(error);
}
);
}
Hope it helps :)
The answer is to use Cloud Functions for Firebase, which enable running Node functions from the server. Then you use the Node module request to send the HTTP request from Node.
i have some rest service deployed in my local machine(running on localhost). I am accessing those service using my angular js app. But when i deploy this in firefox i am getting cross origin request block exception but i am able to deploy same angular app on other browser IE and Chrome. Please help me out on this issue.
ErrorMessage:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/helloworld/rest/sayhi. This can be fixed by moving the resource to the same domain or enabling CORS.
$http( { url: 'http://localhost:8080/helloworld/rest/sayhi/'+$scope.userquery, method: 'GET', dataType: 'json',
transformResponse: function(data){
console.log("transformlog "+data);
return JSON.parse(data);
},
headers: {
'Content-Type': 'application/json'
} }).then(function(data){console.log(data);} );
Where the spring mvc services are hosted in tomcat server. Both the server are browsers are in some machine.
http://patrickgrimard.com/2013/12/12/cross-origin-resource-sharing-cors-requests-with-spring-mvc/
I followed above link. I have added Cors headers in my spring-mvc-rest controller using filters and it worked perfect for me.
I think, actually it is problem on server side. You should enable CORS support on your spring application. It can be done by adding the filter
public class CORSFilter extends OncePerRequestFilter {
private final Logger LOG = LoggerFactory.getLogger(CORSFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException {
LOG.info("Adding CORS Headers ........................");
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.setHeader("Access-Control-Max-Age", "3600");
res.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");
res.addHeader("Access-Control-Expose-Headers", "xsrf-token");
if ("OPTIONS".equals(req.getMethod())) {
res.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
}
I found it from the link angularjs spring cross-origin request blocked
I am new to angular and am from .net framework. I need to post a angular request to .net service, where it expects two custom headers from the client.
angular post command:
var request = $http(
{
url: "http://localhost:53585/api/myService/Validate",
method: "POST",
data: JSON.stringify(payload),
headers: { 'first_token': sessionService.first_token, 'second_token': sessionService.second_token }
});
But in the service side, I can see only first_token in the request header and not the second token. What I am missing here?
Issue is with my service. I figured out and restarted the IIS and then service was able to read both the headers token
I found this method in a forum, it works.
return this.http.post<any>('https://yourendpoint', { username, password }, { headers: new HttpHeaders().set('Authorizaion', 'your token')})
.pipe(map(user => {
// login successful if there's a jwt token in the response
if (user && user.token) {
// sto`enter code here`re user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
}
console.log(user);
return user;