简体   繁体   English

JERSEY-将javax.ws.rs.core.Response作为JSON对象返回,错误为:…或令牌:

[英]JERSEY - returning javax.ws.rs.core.Response as a JSON object with either error:… or token:

EDIT : Is there any way to return a simple object that has either: 编辑 :有没有办法返回具有以下任一条件的简单对象:

  • token 代币
  • error 错误
  • error and details 错误 详细信息

...without having to create new Objects. ...而无需创建新对象。 what's the most efficient and understandable way to do this? 什么是最有效和最容易理解的方法?

I am trying to make a login service that @Consumes(MediaType.APPLICATION_JSON) (containing login credentials: username, password, consumer(boolean)). 我正在尝试提供一个@Consumes(MediaType.APPLICATION_JSON)的登录服务(包含登录凭据:用户名,密码,consumer(boolean))。

If the credentials are valid I want to return a token, for future on the front end, and a RESPONSE CODE OK / 200 ; 如果凭据有效,我想返回一个令牌,以备将来在前端使用,并返回一个响应代码 OK / 200 something like this JSON object: 类似于以下JSON对象:

{"token":"aAKGKas211"}

Otherwise I have specific errors for every case and I want to return a different RESPONSE CODE , which would look something like this: 否则,在每种情况下我都会遇到特定的错误,我想返回一个不同的RESPONSE CODE ,它看起来像这样:

{"error":"Invalid username or password"}

I tried to add a String error (="Invalid username or password") to the Response.Status.NOT_ACCEPTABLE).entity(error), but I'm getting the string as a string not as a JSON object.. 我试图向Response.Status.NOT_ACCEPTABLE).entity(error)添加一个字符串错误(=“无效的用户名或密码”),但是我将字符串作为字符串而不是作为JSON对象。

this is how my code looks like: 这是我的代码的样子:

@POST
@Path("/login")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response login(@Context HttpServletRequest req, LoginInfo loginInfo) {
    CouponClientFacade facade = null;
    String token = null, error = null;

    // validate the REQUESTer's token, if he is already logged in return ERROR RESPONSE.
    System.out.println(loginInfo);
    System.out.println(req.getSession().getId());
    if (loginInfo == null)
        return Response.ok("Test").build();
    if (validateCredentials(loginInfo))
        return Response.status(Response.Status.NOT_ACCEPTABLE).entity("Invalid username or password").build();


    try { // Try to login into administrator
        facade = ClientType.ADMIN.login(loginInfo.getUsername(), loginInfo.getPassword());
    } catch (Exception E) { // Couldn't login into administrator
        try {
            if (loginInfo.isCustomer()) // Try to login into CUSTOMER account
                facade = ClientType.CUSTOMER.login(loginInfo.getUsername(), loginInfo.getPassword());
            else // Try to login into COMPANY account
                facade = ClientType.COMPANY.login(loginInfo.getUsername(), loginInfo.getPassword());

        } catch (BadUsernamePassword e) {
            return Response.status(Response.Status.FORBIDDEN).entity(error=e.getMessage()).build();
        } catch (UnexpectedError e) {
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error=e.getMessage()).build();
        }
    }
    if (facade != null) {
        token = SessionManager.generateToken(req.getSession().getId(), facade);
        return Response.ok(token).build();
    } else return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error="111").build();
}

edit: 编辑:

pass your token in "Authorization" header 在“授权”标题中传递令牌

Basic Authentication provides a solution for this problem, although not very secure. 尽管不是很安全,但是基本身份验证为该问题提供了解决方案。 With Basic Authentication, clients send it's Base64 encoded credentials with each request, using HTTP [Authorization] header . 借助基本身份验证,客户端将使用HTTP [Authorization]标头随每个请求发送其Base64编码的凭据。 That means each request is independent of other request and server may/does not maintain any state information for the client, which is good for scalability point of view. 这意味着每个请求都独立于其他请求,并且服务器可能/不为客户端维护任何状态信息,这从可伸缩性的角度来看是有益的。

A Word on HTTPS : For any sort of Security implementation, ranging from Basic authentication to a full fledged OAuth2 implementation, HTTPS is a must have. HTTPS简介:从基本身份验证到成熟的OAuth2实现,对于任何类型的安全性实现,HTTPS都是必须具备的。 Without HTTPS, no matter what your implementation is, security is vulnerable to be compromised. 没有HTTPS,无论您的实现是什么,安全性都容易受到损害。

String plainClientCredentials="myusername:mypassword";
String base64ClientCredentials = new String(Base64.encodeBase64(plainClientCredentials.getBytes()));

HttpHeaders headers = getHeaders();
headers.add("Authorization", "Basic " + base64ClientCredentials);

which may in turn produce something like: 反过来可能会产生类似以下内容:

Authorization : Basic bXktdHJ1c3FOO1jbGllbnQ6c2VjcmV0...

Basic Authentication & Spring Security With two steps, you can enable the Basic Authentication in Spring Security Configuration. 基本身份验证和Spring Security通过两个步骤,您可以在Spring Security Configuration中启用基本身份验证。 1. Configure httpBasic : Configures HTTP Basic authentication. 1.配置httpBasic:配置HTTP基本身份验证。 [http-basic in XML] 2. Configure authentication entry point with BasicAuthenticationEntryPoint : In case the Authentication fails [invalid/missing credentials], this entry point will get triggered. [XML中的http-basic] 2.使用BasicAuthenticationEntryPoint配置身份验证入口点:如果身份验证失败[无效/缺少凭据],将触发此入口点。 It is very important, because we don't want [Spring Security default behavior] of redirecting to a login page on authentication failure [ We don't have a login page]. 这非常重要,因为我们不希望[Spring Security默认行为]在身份验证失败时重定向到登录页面[我们没有登录页面]。

Shown below is the complete Spring Security configuration with httpBasic and entry point setup. 下面显示的是带有httpBasic和入口点设置的完整Spring Security配置。

package com.websystique.springmvc.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private static String REALM="MY_TEST_REALM";

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("tom").password("abc123").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

      http.csrf().disable()
        .authorizeRequests()
        .antMatchers("/user/**").hasRole("ADMIN")
        .and().httpBasic().realmName(REALM).authenticationEntryPoint(getBasicAuthEntryPoint())
        .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);//We don't need sessions to be created.
    }

    @Bean
    public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
        return new CustomBasicAuthenticationEntryPoint();
    }

    /* To allow Pre-flight [OPTIONS] request from browser */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }
}

And the actual Entry point, which will get triggerd if authentication failed. 以及实际的入口点,如果身份验证失败,它将被触发。 You can customize it to send custom content in response. 您可以对其进行自定义以发送自定义内容作为响应。

package com.websystique.springmvc.security;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;

public class CustomBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

    @Override
    public void commence(final HttpServletRequest request, 
            final HttpServletResponse response, 
            final AuthenticationException authException) throws IOException, ServletException {
        //Authentication failed, send error response.
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName() + "");

        PrintWriter writer = response.getWriter();
        writer.println("HTTP Status 401 : " + authException.getMessage());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        setRealmName("MY_TEST_REALM");
        super.afterPropertiesSet();
    }
}

That's all you need to configure basic security. 这就是配置基本安全性所需的全部。 Now let's see everything in action, with our good old REST API 现在,让我们通过良好的旧REST API来了解一切

REST API Simple Spring REST API, which serves user(s). REST API简单的Spring REST API,可为用户提供服务。 A client can perform CRUD operations using Standard HTML verbs, compliant with REST style. 客户端可以使用符合REST风格的标准HTML动词执行CRUD操作。

package com.websystique.springmvc.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

import com.websystique.springmvc.model.User;
import com.websystique.springmvc.service.UserService;

@RestController
public class HelloWorldRestController {

    @Autowired
    UserService userService;  //Service which will do all data retrieval/manipulation work


    //-------------------Retrieve All Users--------------------------------------------------------

    @RequestMapping(value = "/user/", method = RequestMethod.GET)
    public ResponseEntity<List<User>> listAllUsers() {
        List<User> users = userService.findAllUsers();
        if(users.isEmpty()){
            return new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
        }
        return new ResponseEntity<List<User>>(users, HttpStatus.OK);
    }


    //-------------------Retrieve Single User--------------------------------------------------------

    @RequestMapping(value = "/user/{id}", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE,MediaType.APPLICATION_XML_VALUE})
    public ResponseEntity<User> getUser(@PathVariable("id") long id) {
        System.out.println("Fetching User with id " + id);
        User user = userService.findById(id);
        if (user == null) {
            System.out.println("User with id " + id + " not found");
            return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity<User>(user, HttpStatus.OK);
    }



    //-------------------Create a User--------------------------------------------------------

    @RequestMapping(value = "/user/", method = RequestMethod.POST)
    public ResponseEntity<Void> createUser(@RequestBody User user, UriComponentsBuilder ucBuilder) {
        System.out.println("Creating User " + user.getName());

        if (userService.isUserExist(user)) {
            System.out.println("A User with name " + user.getName() + " already exist");
            return new ResponseEntity<Void>(HttpStatus.CONFLICT);
        }

        userService.saveUser(user);

        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(ucBuilder.path("/user/{id}").buildAndExpand(user.getId()).toUri());
        return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
    }


    //------------------- Update a User --------------------------------------------------------

    @RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)
    public ResponseEntity<User> updateUser(@PathVariable("id") long id, @RequestBody User user) {
        System.out.println("Updating User " + id);

        User currentUser = userService.findById(id);

        if (currentUser==null) {
            System.out.println("User with id " + id + " not found");
            return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
        }

        currentUser.setName(user.getName());
        currentUser.setAge(user.getAge());
        currentUser.setSalary(user.getSalary());

        userService.updateUser(currentUser);
        return new ResponseEntity<User>(currentUser, HttpStatus.OK);
    }

    //------------------- Delete a User --------------------------------------------------------

    @RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
    public ResponseEntity<User> deleteUser(@PathVariable("id") long id) {
        System.out.println("Fetching & Deleting User with id " + id);

        User user = userService.findById(id);
        if (user == null) {
            System.out.println("Unable to delete. User with id " + id + " not found");
            return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
        }

        userService.deleteUserById(id);
        return new ResponseEntity<User>(HttpStatus.NO_CONTENT);
    }


    //------------------- Delete All Users --------------------------------------------------------

    @RequestMapping(value = "/user/", method = RequestMethod.DELETE)
    public ResponseEntity<User> deleteAllUsers() {
        System.out.println("Deleting All Users");

        userService.deleteAllUsers();
        return new ResponseEntity<User>(HttpStatus.NO_CONTENT);
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM