问题一:
在oauth2+jwt格式的鉴权授权认证token中,增加自定义字段并获取该字段
1.继承JwtAccessTokenConverter类,重写enhance方法,将userId放在jwt格式的payload中
public class UaaJwtAccessTokenConverter extends JwtAccessTokenConverter {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
if (accessToken instanceof DefaultOAuth2AccessToken) {
Object principal = authentication.getPrincipal();if (principal instanceof com.kunfei.uaa.service.dto.UserDTO) {
UserDTO user = (UserDTO) principal;
HashMap<String, Object> map = new HashMap<>();
map.put("userId", user.getId());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(map);
}
}
return super.enhance(accessToken, authentication);
}
}
2.在认证服务器中,增加自定义的UaaJwtAccessTokenConverter类到spring上下文
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new UaaJwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(
new ClassPathResource(uaaProperties.getKeyStore().getName()), uaaProperties.getKeyStore().getPassword().toCharArray())
.getKeyPair(uaaProperties.getKeyStore().getAlias());
converter.setKeyPair(keyPair);
return converter;
}
3.获取tokne并解析token中的payload,得到userId
注入JwtTokenStore
@Autowired
public JwtTokenStore tokenStore;
public static Optional<Long> getCurrentUserId(JwtTokenStore tokenStore) {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
if (authentication != null) {
Object details = authentication.getDetails();
if (details instanceof OAuth2AuthenticationDetails) {
String userId = null;
Object decodedDetails = ((OAuth2AuthenticationDetails) details).getDecodedDetails();
if (decodedDetails != null&& decodedDetails instanceof Map) {
userId = ((Map<?, ?>) decodedDetails).get("userId").toString();
}else {
String accessToken = ((OAuth2AuthenticationDetails) details).getTokenValue();
Map<String, Object> extraInfoMap = tokenStore.readAccessToken(accessToken).getAdditionalInformation();
userId = extraInfoMap.get("userId").toString();
}
return Optional.ofNullable(Long.valueOf(userId));
}
}
return Optional.ofNullable(null);
}
问题二:
在Restful API接口中,增加过滤器,修改response中body体的内容
1.继承HttpServletResponseWrapper(HttpServletResponse的包装实现类)
public class BodyCachingHttpServletResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
private HttpServletResponse response;
private PrintWriter pwrite;
public BodyCachingHttpServletResponseWrapper(HttpServletResponse response) {
super(response);
this.response = response;
}
public byte[] getBytes() {
if(pwrite != null) {
pwrite.close();
return byteArrayOutputStream.toByteArray();
}
if(byteArrayOutputStream != null) {
try {
byteArrayOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
return byteArrayOutputStream.toByteArray();
}
@Override
public ServletOutputStream getOutputStream() {
return new ServletOutputStreamWrapper(this.byteArrayOutputStream , this.response);
}
@Override
public PrintWriter getWriter() throws IOException {
pwrite = new PrintWriter(new OutputStreamWriter(this.byteArrayOutputStream , this.response.getCharacterEncoding()));
return pwrite;
}
private static class ServletOutputStreamWrapper extends ServletOutputStream {
private ByteArrayOutputStream outputStream;
private HttpServletResponse response;
public ServletOutputStreamWrapper(ByteArrayOutputStream outputStream, HttpServletResponse response) {
super();
this.outputStream = outputStream;
this.response = response;
}@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener listener) {
}
@Override
public void write(int b) throws IOException {
this.outputStream.write(b);
}
//在原有body的基础上,提交原有的内容,先是新增而不是替换,需要注释掉
// @Override
// public void flush() throws IOException {
// if (! this.response.isCommitted()) {
// byte[] body = this.outputStream.toByteArray();
// ServletOutputStream outputStream = this.response.getOutputStream();
// outputStream.write(body);
// outputStream.flush();
// }
// }
}
}
2.增加过滤器,替换response中body的内容
@WebFilter(filterName = "responseFilter",urlPatterns = "/*")
public class ResponseFilter implements Filter {@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
BodyCachingHttpServletResponseWrapper responseWrapper = new BodyCachingHttpServletResponseWrapper((HttpServletResponse) servletResponse);
chain.doFilter(servletRequest, responseWrapper);
Optional<String> xTotalCount = Optional.ofNullable(responseWrapper.getHeader("X-Total-Count"));
byte[] writeValueByte = null;
if(xTotalCount.isPresent() && responseWrapper.getBytes() != null) {
String currentTotal = xTotalCount.get();
String currentData = new String(responseWrapper.getBytes());
String writeValue = "{\"total\":"+currentTotal+",\"data\":"+currentData+"}";
writeValueByte = writeValue.getBytes();
}else {
writeValueByte = responseWrapper.getBytes();
}//重新写入输出流
ServletOutputStream outputStream = servletResponse.getOutputStream();
outputStream.write(writeValueByte);
outputStream.flush();
outputStream.close();
}
}
3.在启动器上增加扫描servlet的注解
@ServletComponentScan