WebApi's were working fine, then I added a few odata controllers, now my webapi's return not found. I assume its in the routing somewhere but I don't see it. returns 404 not found. how do I fix my webapi's to return data gain.
Global Config
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Web API Config
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}/{action}",
defaults: new { id = RouteParameter.Optional }
);
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<pp_tsr_accounts_tab_Result>("pp_tsr_accounts_tab_Result");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
config.EnableSystemDiagnosticsTracing();
}
Call
http://localhost:xxx/api/pp_tsr_offer_calc_Result/Getpp_tsr_offer_calc_Result?id=0801314923
well I win the idiot award.
routeTemplate: "api/{controller}/{action}/{id}",
not
routeTemplate: "api/{controller}/{id}/{action}",
Related
This is my axios, I use get method and add username&password into request. But I don't know why this can not pass backend check. By the way I'm pretty sure about the url is correct. đ
axios({
method:'get',
url,
auth: {
username: 'From_Website',
password: 'aycfgz!'
}
}).then((response) =>{
console.log(response.data);
this.myblogs = response.data;
this.len = this.myblogs.length;
}).catch(err =>{
console.log(err);
});
And this is my backend configration code.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception{
authenticationManagerBuilder.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder())
.withUser("From_Website")
.password(new BCryptPasswordEncoder().encode("aycfgz!"))
.roles("from_website");
}
}
What error are you getting and where? From the top of my head, you can try adding withCredentials: true config to your request.
Running a service on localhost:8000. I route to it with Spring Gateway and only get a white page instead of the login page of the service.
I've tried routing using java, and also through a yml file.
Java
#SpringBootApplication
public class GsGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GsGatewayApplication.class, args);
}
#Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder){
return builder.routes()
.route(p->p
.path("/get")
.uri("localhost:8000/login"))
.build();
}
}
application.yml
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: weblogin
uri: localhost:8000/login
predicates:
- Path=/get
I expect a login page, but get only a blank white page.
By your configuration, when you access localhost/get you will be route to localhost:8080/get
I am doing spring boot 1.5+ security with auth2 authentication and reactjs. for http calls using restful http client. Authentication is working perfectly and I am successfully accessing data from resource server. The issue is logout code is not working and I am getting this error on console:
POST http://localhost:8080/logout 403 ()
error: "Forbidden"
message: "Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'.
I am sharing my code also.
1) ReactJs code
handleLogout = (e) => {
client({
method: 'POST',
path: '/logout',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}}).then(response => {
console.log(response);
});
}
2) restful http client
'use strict';
// client is custom code that configures rest.js to include support for HAL, URI Templates,
// and other things. It also sets the default Accept request header to application/hal+json.
// get the rest client
var rest = require('rest');
// provides default values for the request object. default values can be provided for the method, path, params, headers, entity
// If the value does not exist in the request already than the default value utilized
var defaultRequest = require('rest/interceptor/defaultRequest');
// Converts request and response entities using MIME converter registry
// Converters are looked up by the Content-Type header value. Content types without a converter default to plain text.
var mime = require('rest/interceptor/mime');
// define the request URI by expanding the path as a URI template
var uriTemplateInterceptor = require('./uriTemplateInterceptor');
// Marks the response as an error based on the status code
// The errorCode interceptor will mark a request in error if the status code is equal or greater than the configured value.
var errorCode = require('rest/interceptor/errorCode');
var csrf = require('rest/interceptor/csrf');
// A registry of converters for MIME types is provided. Each time a request or response entity needs to be encoded or
// decoded, the 'Content-Type' is used to lookup a converter from the registry.
// The converter is then used to serialize/deserialize the entity across the wire.
var baseRegistry = require('rest/mime/registry');
var registry = baseRegistry.child();
registry.register('text/uri-list', require('./uriListConverter'));
registry.register('application/hal+json', require('rest/mime/type/application/hal'));
// wrap all the above interceptors in rest client
// default interceptor provide Accept header value 'application/hal+json' if there is not accept header in request
module.exports = rest
.wrap(mime, { registry: registry })
.wrap(uriTemplateInterceptor)
.wrap(errorCode)
.wrap(csrf)
.wrap(defaultRequest, { headers: { 'Accept': 'application/hal+json' }});
3) application.yml of client application
debug: true
spring:
aop:
proxy-target-class: true
security:
user:
password: none
oauth2:
client:
access-token-uri: http://localhost:9999/uaa/oauth/token
user-authorization-uri: http://localhost:9999/uaa/oauth/authorize
client-id: acme
client-secret: acmesecret
resource:
user-info-uri: http://localhost:9999/uaa/user
jwt:
key-value: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgnBn+WU3i6KarB6gYlg40ckBiWmtVEpYkggvHxow74T19oDyO2VRqyY9oaJ/cvnlsZgTOYAUjTECjL8Ww7F7NJZpxMPFviqbx/ZeIEoOvd7DOqK3P5RBtLsV5A8tjtfqYw/Th4YEmzY/XkxjHH+KMyhmkPO+/tp3eGmcMDJgH+LwA6yhDgCI4ztLqJYY73gX0pEDTPwVmo6g1+MW8x6Ctry3AWBZyULGt+I82xv+snqEriF4uzO6CP2ixPCnMfF1k4dqnRZ/V98hnSLclfMkchEnfKYg1CWgD+oCJo+kBuCiMqmeQBFFw908OyFKxL7Yw0KEkkySxpa4Ndu978yxEwIDAQAB
-----END PUBLIC KEY-----
zuul:
routes:
resource:
path: /resource/**
url: http://localhost:9000/resource
user:
path: /user/**
url: http://localhost:9999/uaa/user
logging:
level:
org.springframework.security: DEBUG
4) CorsFilter configuration in authorization server
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
System.out.println("*********** running doFilter method of CorsFilter of auth-server***********");
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.addHeader("Access-Control-Allow-Headers", "x-auth-token, x-requested-with");
response.addHeader("Access-Control-Max-Age", "3600");
if (request.getMethod()!="OPTIONS") {
try {
chain.doFilter(req, res);
} catch (IOException e) {
e.printStackTrace();
} catch (ServletException e) {
e.printStackTrace();
}
} else {
}
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
5) AuthrorizationServerConfigurerAdapter of authentication server
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Bean
public #Autowired JwtAccessTokenConverter jwtAccessTokenConverter() throws Exception {
System.out.println("*********** running jwtAccessTokenConverter ***********");
// Setting up a JWT token using JwtAccessTokenConverter.
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
// JWT token signing key
KeyPair keyPair = new KeyStoreKeyFactory(
new ClassPathResource("keystore.jks"), "suleman123".toCharArray())
.getKeyPair("resourcekey");
converter.setKeyPair(keyPair);
return converter;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
System.out.println("*********** running configure(ClientDetailsServiceConfigurer clients) ***********");
clients.inMemory()
.withClient("acme") // registers a client with client Id 'acme'
.secret("acmesecret") // registers a client with password 'acmesecret'
.authorizedGrantTypes("authorization_code", "refresh_token",
"password") // We registered the client and authorized the âpasswordâ, âauthorization_codeâ and ârefresh_tokenâ grant types
.scopes("openid") // scope to which the client is limited
.autoApprove(true);
}
/**
*
*/
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
System.out.println("*********** running configure(AuthorizationServerEndpointsConfigurer endpoints) ***********");
// we choose to inject an existing authentication manager from the spring container
// With this step we can share the authentication manager with the Basic authentication filter
endpoints.authenticationManager(authenticationManager)
.accessTokenConverter(jwtAccessTokenConverter());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
System.out.println("*********** running configure(AuthorizationServerSecurityConfigurer oauthServer) ***********");
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess(
"isAuthenticated()");
}
}
Finally got this working. What I have done to make it work:
1) I have installed 'react-cookie' library
npm install react-cookie --save
2) In my reactjs code I have imported react-cookie library and in method where I am using restful http client to generate logout request I am fetching Csrf-Token from cookie and sending it as request header.
handleLogout = (e) => {
client({
method: 'POST',
path: 'logout',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf8',
'X-Requested-With': 'XMLHttpRequest',
'X-Csrf-Token': Cookie.load('XSRF-TOKEN')
}
}).then(response => {
this.setState({authenticated: false});
console.log(response);
});
}
3) In authorization server instead of using my custom Cors Filter class which I have mentioned in my question, now I am using Spring Cors Filter code
#Configuration
public class CorsFilterConfig {
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
4) In application.properties file of Authorization Server I have added this property, so CorsFilter will run before SpringSecurityFilterChain
security.filter-order=50
This is my configuration for OAuth2 login with Instagram
instagram:
client:
clientId: clientId
clientSecret: clientSeret
accessTokenUri: https://api.instagram.com/oauth/access_token
userAuthorizationUri: https://api.instagram.com/oauth/authorize
clientAuthenticationScheme: form
scope:
- basic
- public_content
resource:
userInfoUri: https://api.instagram.com/v1/users/self/
delimiter: +
This is the request made by Spring:
https://api.instagram.com/oauth/authorize?client_id=clientId&redirect_uri=http://localhost:8080/login/instagram&response_type=code&state=CG6mMQ
How can I change the response_type to &response_type=token and how can I why isn't Spring adding the scopes?
Here is the App class:
#SpringBootApplication
#EnableOAuth2Client
public class App extends WebSecurityConfigurerAdapter {
#Autowired
OAuth2ClientContext oauth2ClientContext;
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/", "/login**", "/webjars/**")
.permitAll()
.anyRequest()
.authenticated().and().exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/"))
// logout
.and().logout().logoutSuccessUrl("/").permitAll()
// CSRF
.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// filters
.and().addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
}
private Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
// facebook ...
// google ...
// instagram
OAuth2ClientAuthenticationProcessingFilter instagramFilter =
new OAuth2ClientAuthenticationProcessingFilter("/login/instagram");
OAuth2RestTemplate instagramTemplate =
new OAuth2RestTemplate(instagram(), oauth2ClientContext);
instagramFilter.setRestTemplate(instagramTemplate);
instagramFilter.setTokenServices(
new UserInfoTokenServices(instagramResource().getUserInfoUri(), instagram().getClientId()));
filters.add(instagramFilter);
filter.setFilters(filters);
return filter;
}
#Bean
#ConfigurationProperties("instagram.client")
public AuthorizationCodeResourceDetails instagram() {
return new AuthorizationCodeResourceDetails();
}
#Bean
#ConfigurationProperties("instagram.resource")
public ResourceServerProperties instagramResource() {
return new ResourceServerProperties();
}
#Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(
OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
}
How can I change the response_type to &response_type=token
As I read the code, AuthorizationCodeAccessTokenProviderâs response_type is hard code.
private UserRedirectRequiredException getRedirectForAuthorization(AuthorizationCodeResourceDetails resource,
AccessTokenRequest request) {
// we don't have an authorization code yet. So first get that.
TreeMap<String, String> requestParameters = new TreeMap<String, String>();
requestParameters.put("response_type", "code"); // oauth2 spec, section 3
So, If you want to change the response_code, you can extend the AuthorizationCodeAccessTokenProvider, or implements the AccessTokenProvider, and then inject to the OAuth2RestTemplate accessTokenProvider(the default value is a AccessTokenProviderChain that contains AuthorizationCodeAccessTokenProvider, ResourceOwnerPasswordAccessTokenProvider and so on, use your own provider instead of AuthorizationCodeAccessTokenProvider).
Or you can change the redirectStrategy in OAuth2ClientContextFilter, and change the request param when redirect, but I don't recommend this.
How can I why isn't Spring adding the scopes?
AuthorizationCodeAccessTokenProvider will get scopes from AuthorizationCodeResourceDetails, and add them to UserRedirectRequiredException. I think the scope can't be injected to AuthorizationCodeResourceDetails, because the scope is not under the client. Maybe you need to change to this.
instagram:
client:
clientId: clientId
clientSecret: clientSeret
accessTokenUri: https://api.instagram.com/oauth/access_token
userAuthorizationUri: https://api.instagram.com/oauth/authorize
clientAuthenticationScheme: form
scope:
- basic
- public_content
You can access the query parameters from the UserRedirectRequiredException. So in the code which throws the exception and thus causes the redirect to happen, e.g. in your filter, you can do something like:
try {
accessToken = restTemplate.getAccessToken();
}
catch (UserRedirectRequiredException e) {
Map<String, String> requestParams = e.getRequestParams();
requestParams.put("response_type", "token");
throw e; //don't forget to rethrow
}
You can only replace values this way. If you needed to add a parameter value alongside an existing value, you'd need to use a delimiter such as '+'. There is no standard way of adding multiple parameter values and would depend on what the owner of the API accepts. Some APIs may not accept delimeters at all.
I've added Web Api controller to MVC 5 application but all the time I get Error 404 - The resource cannot be found. I've added GlobalConfiguration.Configure(WebApiConfig.Register) to Application_Start()
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
and I have route registred
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
WebApi routing started to work after I've changed the position of Register api method to be above of register routes:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
If this may help somebody.
In my case the problem was that i deleted default controllers and in RouteConfig.cs file Home controller was still being referenced.