Java - doFilter

解决问题:

1. 在认证之前做个过滤InternalServerTokenFilter。如没有带内部token, 就不继续认证controller的处理了
2. 过滤拿走request 的body后,controller不可再次消费,此时需要重新生成一个InternalServerTokenRequestWrapper, 可永久保存request body
3. 过滤器需要捕捉异常,进行特殊处理返回给前端 InternalServerTokenFilter::exceptionHandle

 
public class InternalServerTokenFilter extends GenericFilterBean {
	private static final Logger logger = LoggerFactory
			.getLogger(InternalServerTokenFilter.class);
	private InternalServerUiConf internalServerUiConf;
	private InternalTokenService internalTokenService;

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws ServletException, IOException {

		if (false == internalServerUiConf.getEnable()) {
			// Disable: do nothing
			chain.doFilter(request, response);
			return;
		}

		// Enable: validate it.
		// Consume input stream of request and wrap a new request for control
		// consumption.
		// Because input stream can be consumed only once.
		InternalServerTokenRequestWrapper requestWrapper = new InternalServerTokenRequestWrapper(
				(HttpServletRequest) request);
		String body = requestWrapper.getBody();
		try {
			internalTokenService.validate(body);
		} catch (InvalidInternalTokenException e) {
			exceptionHandle((HttpServletRequest) request,
					(HttpServletResponse) response, e);
			return;
		} catch (Exception e) {
			logger.error("internal token filter exception. ", e.getMessage());
			throw new ServletException(e);
		}

		// Pass through
		chain.doFilter((ServletRequest) requestWrapper, response);
	}

	private void exceptionHandle(HttpServletRequest request,
			HttpServletResponse response, InvalidInternalTokenException e)
			throws IOException {

		response.setStatus(HttpStatus.FORBIDDEN.value());

		InternalTokenResponse internalTokenResponse = new InternalTokenResponse(
				e.getCode(), e.getMessage());
		JSONObject objResponse = JSONObject.fromObject(internalTokenResponse);
		String strResponse = objResponse.toString();
		PrintWriter outBody = response.getWriter();
		outBody.println(strResponse);
		outBody.flush();
		outBody.close();
	}

	public InternalTokenService getInternalTokenService() {
		return internalTokenService;
	}
	public void setInternalTokenService(
			InternalTokenService internalTokenService) {
		this.internalTokenService = internalTokenService;
	}

	public InternalServerUiConf getInternalServerUiConf() {
		return internalServerUiConf;
	}

	public void setInternalServerUiConf(
			InternalServerUiConf internalServerUiConf) {
		this.internalServerUiConf = internalServerUiConf;
	}
}

package com.hp.ccue.identity.utilities;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class InternalServerTokenRequestWrapper
		extends
			HttpServletRequestWrapper {

	private final String body;
	public InternalServerTokenRequestWrapper(HttpServletRequest request)
			throws IOException {
		super(request);
		StringBuilder stringBuilder = new StringBuilder();
		BufferedReader bufferedReader = null;
		try {
			InputStream inputStream = request.getInputStream();
			if (inputStream != null) {
				bufferedReader = new BufferedReader(
						new InputStreamReader(inputStream));
				char[] charBuffer = new char[1024];
				int bytesRead = -1;
				while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
					stringBuilder.append(charBuffer, 0, bytesRead);
				}
			} else {
				stringBuilder.append("");
			}
		} catch (IOException e) {
			throw e;
		} finally {
			if (bufferedReader != null) {
				try {
					bufferedReader.close();
				} catch (IOException e) {
					throw e;
				}
			}
		}
		body = stringBuilder.toString();
	}

	@Override
	public ServletInputStream getInputStream() throws IOException {
		final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
				body.getBytes());
		ServletInputStream servletInputStream = new ServletInputStream() {
			public int read() throws IOException {
				return byteArrayInputStream.read();
			}
		};
		return servletInputStream;
	}

	@Override
	public BufferedReader getReader() throws IOException {
		return new BufferedReader(new InputStreamReader(this.getInputStream()));
	}

	public String getBody() {
		return this.body;
	}
}


    <bean id="internalServerTokenFilter" class="com.hp.ccue.identity.filter.InternalServerTokenFilter">
        <property name="internalServerUiConf" ref="internalServerUiConf"/>
        <property name="internalTokenService" ref="internalTokenService"/>
    </bean>
   <security:http pattern="/../v0/.." use-expressions="true" auto-config="false">
        <security:csrf disabled="true" />
        <security:custom-filter ref="internalServerTokenFilter" />
        <security:http-basic />
    </security:http>




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过以下步骤在Spring Boot中集成JWT: 1. 添加java-jwt依赖包到pom.xml文件中: ```xml <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.18.1</version> </dependency> ``` 2. 创建一个JWT工具类来生成和验证JWT令牌: ```java import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; import java.util.Date; public class JwtUtils { private static final long EXPIRATION_TIME = 86400000; // 24 hours private static final String SECRET = "mySecret"; private static final String ISSUER = "myIssuer"; public static String generateToken(String username) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME); return JWT.create() .withSubject(username) .withIssuer(ISSUER) .withIssuedAt(now) .withExpiresAt(expiryDate) .sign(Algorithm.HMAC512(SECRET)); } public static String getUsernameFromToken(String token) throws JWTVerificationException { DecodedJWT jwt = JWT.require(Algorithm.HMAC512(SECRET)) .withIssuer(ISSUER) .build() .verify(token); return jwt.getSubject(); } } ``` 3. 在Spring Security配置中添加JWT过滤器,以验证JWT令牌: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.HttpStatusEntryPoint; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Configuration @Order(1) public class JwtConfig extends SecurityConfigurerAdapter<javax.servlet.Filter, HttpSecurity> { @Autowired private JwtAuthenticationProvider jwtAuthenticationProvider; @Override public void configure(HttpSecurity http) throws Exception { JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(); jwtAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); jwtAuthenticationFilter.setAuthenticationFailureHandler(new JwtAuthenticationFailureHandler()); http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } private class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter { @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { String token = request.getHeader("Authorization"); if (token == null || !token.startsWith("Bearer ")) { throw new JwtAuthenticationException("Invalid JWT token"); } String username = JwtUtils.getUsernameFromToken(token.substring(7)); if (username == null) { throw new JwtAuthenticationException("Invalid JWT token"); } return jwtAuthenticationProvider.authenticate(new UsernamePasswordAuthenticationToken(username, "")); } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { super.successfulAuthentication(request, response, chain, authResult); chain.doFilter(request, response); } } private class JwtAuthenticationFailureHandler extends HttpStatusEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { response.setStatus(HttpStatus.UNAUTHORIZED.value()); } } } ``` 4. 创建一个JwtAuthenticationProvider来验证用户名和密码: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; @Component public class JwtAuthenticationProvider implements AuthenticationProvider { @Autowired private UserDetailsService userDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = (String) authentication.getCredentials(); UserDetails userDetails = userDetailsService.loadUserByUsername(username); if (!passwordEncoder.matches(password, userDetails.getPassword())) { throw new JwtAuthenticationException("Invalid username or password"); } return new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities()); } @Override public boolean supports(Class<?> authentication) { return authentication.equals(UsernamePasswordAuthenticationToken.class); } } ``` 5. 在Spring Security配置中添加JwtConfig: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; 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.configuration.WebSecurityConfigurerAdapter; @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtAuthenticationProvider jwtAuthenticationProvider; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(jwtAuthenticationProvider); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .antMatcher("/**") .authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and() .apply(new JwtConfig()); } } ``` 现在你就可以在Spring Boot应用程序中使用JWT进行身份验证了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值