java过滤器验证app用户token,使用Java Config的Spring Security自定义身份验证过滤器

I'm trying to configure Spring Security using Java config in a basic web application to authenticate against an external web service using an encrypted token provided in a URL request parameter.

I would like (I think) to have a security filter that intercepts requests from the Login Portal (they all go to /authenticate), the filter will use an AuthenticationProvider to process the bussiness logic of the authentication process.

Login Portal --> Redirect '\authenticate' (+ Token) --> Authenticate Token back to Login Portal (WS) --> If success get roles and setup user.

I have created a filter..

@Component

public final class OEWebTokenFilter extends GenericFilterBean {

@Override

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

if (request instanceof HttpServletRequest) {

OEToken token = extractToken(request);

// dump token into security context (for authentication-provider to pick up)

SecurityContextHolder.getContext().setAuthentication(token);

}

}

chain.doFilter(request, response);

}

An AuthenticationProvider...

@Component

public final class OEWebTokenAuthenticationProvider implements AuthenticationProvider {

@Autowired

private WebTokenService webTokenService;

@Override

public boolean supports(final Class> authentication) {

return OEWebToken.class.isAssignableFrom(authentication);

}

@Override

public Authentication authenticate(final Authentication authentication) {

if (!(authentication instanceof OEWebToken)) {

throw new AuthenticationServiceException("expecting a OEWebToken, got " + authentication);

}

try {

// validate token locally

OEWebToken token = (OEWebToken) authentication;

checkAccessToken(token);

// validate token remotely

webTokenService.validateToken(token);

// obtain user info from the token

User userFromToken = webTokenService.obtainUserInfo(token);

// obtain the user from the db

User userFromDB = userDao.findByUserName(userFromToken.getUsername());

// validate the user status

checkUserStatus(userFromDB);

// update ncss db with values from OE

updateUserInDb(userFromToken, userFromDB);

// determine access rights

List roles = determineRoles(userFromDB);

// put account into security context (for controllers to use)

return new AuthenticatedAccount(userFromDB, roles);

} catch (AuthenticationException e) {

throw e;

} catch (Exception e) {

// stop non-AuthenticationExceptions. otherwise full stacktraces returned to the requester

throw new AuthenticationServiceException("Internal error occurred");

}

}

And my Spring Security Config

@Configuration

@EnableWebSecurity

@EnableGlobalMethodSecurity(prePostEnabled = true)

public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired

OESettings oeSettings;

@Bean(name="oeAuthenticationService")

public AuthenticationService oeAuthenticationService() throws AuthenticationServiceException {

return new AuthenticationServiceImpl(new OEAuthenticationServiceImpl(), oeSettings.getAuthenticateUrl(), oeSettings.getApplicationKey());

}

@Autowired

private OEWebTokenFilter tokenFilter;

@Autowired

private OEWebTokenAuthenticationProvider tokenAuthenticationProvider;

@Autowired

private OEWebTokenEntryPoint tokenEntryPoint;

@Bean(name="authenticationManager")

@Override

public AuthenticationManager authenticationManagerBean() throws Exception {

return super.authenticationManagerBean();

}

@Override

public void configure(AuthenticationManagerBuilder auth) throws Exception {

auth.authenticationProvider(tokenAuthenticationProvider);

}

@Bean

public FilterRegistrationBean filterRegistrationBean () {

FilterRegistrationBean registrationBean = new FilterRegistrationBean();

registrationBean.setFilter(tokenFilter);

registrationBean.setEnabled(false);

return registrationBean;

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http.csrf().disable()

.authorizeRequests()

.antMatchers("/authenticate**").permitAll()

.antMatchers("/resources/**").hasAuthority("ROLE_USER")

.antMatchers("/home**").hasAuthority("ROLE_USER")

.antMatchers("/personSearch**").hasAuthority("ROLE_ADMIN")

// Spring Boot actuator endpoints

.antMatchers("/autoconfig**").hasAuthority("ROLE_ADMIN")

.antMatchers("/beans**").hasAuthority("ROLE_ADMIN")

.antMatchers("/configprops**").hasAuthority("ROLE_ADMIN")

.antMatchers("/dump**").hasAuthority("ROLE_ADMIN")

.antMatchers("/env**").hasAuthority("ROLE_ADMIN")

.antMatchers("/health**").hasAuthority("ROLE_ADMIN")

.antMatchers("/info**").hasAuthority("ROLE_ADMIN")

.antMatchers("/mappings**").hasAuthority("ROLE_ADMIN")

.antMatchers("/metrics**").hasAuthority("ROLE_ADMIN")

.antMatchers("/trace**").hasAuthority("ROLE_ADMIN")

.and()

.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)

.authenticationProvider(tokenAuthenticationProvider)

.antMatcher("/authenticate/**")

.exceptionHandling().authenticationEntryPoint(tokenEntryPoint)

.and()

.logout().logoutSuccessUrl(oeSettings.getUrl());

}

}

My problem is the configuration of the filter in my SpringConfig class. I want the filter to only come into effect when the request is for the /authenticate URL, I've added .antMatcher("/authenticate/**") to the filter configuration.

.and()

.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)

.authenticationProvider(tokenAuthenticationProvider)

.antMatcher("/authenticate/**")

.exceptionHandling().authenticationEntryPoint(tokenEntryPoint)

When I have this line in all other URLs are no longer secured, I can manually navigate to /home without authenticating, remove the line and /home is authenticated.

Should I be declaring a filter that is only applicable to a specific URL?

How can I implement this whilst maintaining the security of other URLs?

解决方案

I've resolved my issue by performing a check on the authentication status in the filter before involking the authentication provider....

Config

.and()

.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)

.authenticationProvider(tokenAuthenticationProvider)

.exceptionHandling().authenticationEntryPoint(tokenEntryPoint)

Filter

@Override

public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)

throws IOException, ServletException {

logger.debug(this + "received authentication request from " + request.getRemoteHost() + " to " + request.getLocalName());

if (request instanceof HttpServletRequest) {

if (isAuthenticationRequired()) {

// extract token from header

OEWebToken token = extractToken(request);

// dump token into security context (for authentication-provider to pick up)

SecurityContextHolder.getContext().setAuthentication(token);

} else {

logger.debug("session already contained valid Authentication - not checking again");

}

}

chain.doFilter(request, response);

}

private boolean isAuthenticationRequired() {

// apparently filters have to check this themselves. So make sure they have a proper AuthenticatedAccount in their session.

Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();

if ((existingAuth == null) || !existingAuth.isAuthenticated()) {

return true;

}

if (!(existingAuth instanceof AuthenticatedAccount)) {

return true;

}

// current session already authenticated

return false;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值