Spring-Security-Oauth2 study notes (2): return custom token format

1 Introduction

The last chapter we have built a good authorization authentication server can successfully return a token, oauth2 default format is as follows:

{
    "access_token": "86d17c41-4de9-470a-a637-0acb7237099d",
    "token_type": "bearer",
    "refresh_token": "fb255411-9535-47ad-9f7e-40b21fac42cf",
    "expires_in": 43199,
    "scope": "all"
}

But generally the front and rear end when interacting about API data format convention, I would now like to return in the following format token:

{
    "code": 0,
    "msg": "登录成功!",
    "data": {
        "access_token": "86d17c41-4de9-470a-a637-0acb7237099d",
        "token_type": "bearer",
        "refresh_token": "fb255411-9535-47ad-9f7e-40b21fac42cf",
        "expires_in": 43097,
        "scope": "all"
    }
}

During which I have taken a lot of other information, such as https://blog.csdn.net/u013905744/article/details/100637224 , this article will use the aspects programmatically / oauth / token returned interface data re-packaging, this method I feel a little trouble, so I have not tried. Another https://segmentfault.com/a/1190000020317220?utm_source=tag-newest , using the method of this article is to rewrite / oauth / token interface directly call postAccessToken TokenEndpoint method of obtaining token then repackage this method I tried, can be used, but a little problem, exception handling, a little problem with this method, specifically not to say.
In the course of the investigation information, but also to see others made the issue postings, requirements like me, but there is no specific answer to the following code, but there are some words that can forward the request to the backend / oauth / token, get The results then packaged. I think this approach should be feasible, so with specific implementation below, now put dry goods.

2 custom token format Back

Agreed with the front end the following format:

{
	"code":0,//表示成功
	"msg":"",//信息
	"data":{//数据
	}
}

So we wrote a ResponseResult tools to return the data, the code is as follows:

package com.example.oauth2.util;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResponseResult {
    //返回状态码
    private int code;

    //返回信息
    private String msg;

    //返回数据
    private Object data;

    public ResponseResult(Object data){
        this.code=0;
        this.msg="操作成功!";
        this.data=data;
    }

    public ResponseResult(String msg,Object data){
        this.code=0;
        this.msg=msg;
        this.data=data;
    }

    public ResponseResult(int code,String msg){
        this.code=code;
        this.msg=msg;
        this.data=null;
    }
}

To the core code, in particular a write / oauth / login, using RestTemplate request / oauth / token interfaces in the interface, and then return to get the token used ResponseResult package. code show as below:

package com.example.oauth2.controller;

import com.example.oauth2.util.ResponseResult;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

@RestController
@RequestMapping("/oauth")
public class OauthController {
    @PostMapping("/login")
    public ResponseResult login(@RequestParam Map<String,Object> map){
        MultiValueMap<String,Object> paramsMap=new LinkedMultiValueMap<>();
        paramsMap.set("username",map.get("username"));
        paramsMap.set("password",map.get("password"));
        paramsMap.set("grant_type",map.get("grant_type"));
        RestTemplate restTemplate=new RestTemplate();
        restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(map.get("client_id").toString(),map.get("client_secret").toString()));
        OAuth2AccessToken token=restTemplate.postForObject("http://localhost:8080/oauth/token",paramsMap,OAuth2AccessToken.class);
        return new ResponseResult("登录成功!",token);
    }
}

Which, restTemplate.getInterceptors () is very important, if you do not add this line of code, will be reported 401 errors when using restTemplate. Here we have to test, open the postman, as in the previous chapter test, but the / oauth / token read / oauth / login, results are as follows:
Here Insert Picture Description
can we see the return format is already in the format required, but there's question, we use the last chapter there is a function refresh_token refresh access_token, so the need to make / oauth / login transform the look, first determine in what way grant_type request token, then the request. code show as below:

	@PostMapping("/login")
    public ResponseResult login(@RequestParam Map<String,Object> map){
        MultiValueMap<String,Object> paramsMap=new LinkedMultiValueMap<>();
        if(map.get("grant_type").equals("password")){
            paramsMap.set("username",map.get("username"));
            paramsMap.set("password",map.get("password"));
        }else if(map.get("grant_type").equals("refresh_token")){
            paramsMap.set("refresh_token",map.get("refresh_token"));
        }
        paramsMap.set("grant_type",map.get("grant_type"));
        RestTemplate restTemplate=new RestTemplate();
        restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(map.get("client_id").toString(),map.get("client_secret").toString()));
        OAuth2AccessToken token=restTemplate.postForObject("http://localhost:8080/oauth/token",paramsMap,OAuth2AccessToken.class);
        return new ResponseResult("登录成功!",token);
    }

Now we'll test refresh_token, results are as follows:
Here Insert Picture Description
you can see refresh_token you can also refresh access_token, and our custom format is also returned. Of course, I have to explain the way I am now using the parameters in client_id and client_secret on request, also said that the last chapter, you can also use the Basic credentials to the request, the specific method is to start to change requests in advance Gets Authorization, and see if that begin with "Basic", put it on if there is a request restTemplate in advance, and if not, then the parameters added to it in the client_id and client_secret by restTemplate.getInterceptors () way. Further, the request can not always succeed, if an exception occurs, the exception token which is returned to the line out to, the following specific change method:

		if(token.getValue()==null){
            return new ResponseResult(Integer.parseInt(token.getAdditionalInformation().get("code").toString()),token.getAdditionalInformation().get("msg").toString());
        }else{
            return new ResponseResult("登录成功!",token);
        }

token in the code and custom msg course I had abnormalities, such as wrong password displays the following information:
Here Insert Picture Description
About custom exception handling, will be described in detail in the next chapter, so stay tuned.

3 Add additional token information

After we request token, the front if there is a demand, for example, you want the user information displayed on the page, then the time of the request token can add some additional parameters to do it? The answer is yes, but also relatively simple, only need to implement TokenEnhancer interfaces on it, the specific code as follows:

package com.example.oauth2.service.impl;

import com.example.oauth2.entity.Account;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.stereotype.Service;

import java.util.LinkedHashMap;
import java.util.Map;

@Service
public class TokenEnhancerImpl implements TokenEnhancer {
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {
        Account account=(Account)oAuth2Authentication.getPrincipal();
        DefaultOAuth2AccessToken token=(DefaultOAuth2AccessToken)oAuth2AccessToken;
        Map<String,Object> map=new LinkedHashMap<>();
        map.put("username",account.getUsername());
        map.put("nickname",account.getNickname());
        token.setAdditionalInformation(map);
        return oAuth2AccessToken;
    }
}

Then add the last line of code in AuthorizationServerConfig public void configure (AuthorizationServerEndpointsConfigurer endpoints) method in:

	@Autowired
    @Qualifier("tokenEnhancerImpl")
    private TokenEnhancer tokenEnhancer;

	@Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(new InMemoryTokenStore())
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .tokenEnhancer(tokenEnhancer);
    }

Now let's test:
Here Insert Picture Description
can be seen in two new data inside information. At this point, the custom token work has been completed.

4 Conclusion

I do not know this usage is not the most reasonable usage, but as long as meet the needs, cares so much?
In the latest chapter 2.4, we have a @EnableGlobalMethodSecurity (prePostEnabled = true) this code on access control and exception handling, the next chapter in detail to learn.
Hope that China will overcome the epidemic, come on!

Released two original articles · won praise 0 · Views 19

Guess you like

Origin blog.csdn.net/qq_26121913/article/details/104296595