具有凭证安全性的Spring令牌安全性(springboot)

时间:2017-06-02 01:42:02

标签: java spring security spring-security

我对我服务器上的安全实施有疑问。我正在制作一个SpringBoot应用程序,它有一个像网站一样的控制面板,其中1个管理员输入需要的数据,我已经成功保护了这部分,如下所示:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {




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


      http.antMatcher("/*").authorizeRequests().anyRequest().hasRole("ADMIN")
        .and().formLogin().loginPage("/login.jsp")
        .failureUrl("/login.jsp?error=1").loginProcessingUrl("/login")
        .permitAll().and().logout()
        .logoutSuccessUrl("/login.jsp");

  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    // Create a default account
    auth.inMemoryAuthentication()
        .withUser("admin")
        .password("admin")
        .roles("ADMIN");
  }

每个网站网址都在/ *上,并且工作正常。我需要做的下一件事是从我的移动应用程序中检索数据,它需要是安全的。应用应该使用的网址是/ rest / **。我有一个Student类,用于存储该管理员在网站上创建的电子邮件(用户名)和密码。据我所知,我需要令牌实现。

如何实现令牌身份验证?

1 个答案:

答案 0 :(得分:1)

使用Spring Boot和Spring Security为移动应用程序实现基于令牌的身份验证。

创建TokenAuthenticationFilter

public class TokenAuthenticationFilter extends GenericFilterBean {

    private AuthenticationManager authenticationManager;

    public TokenAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

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

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        String apiKey = httpRequest.getHeader("API-Key");
        String token = httpRequest.getHeader("Access-Token");

        try {
            if (!StringUtils.isEmpty(apiKey)) {
                processTokenAuthentication(apiKey);
            }
            chain.doFilter(request, response);
        } catch (InternalAuthenticationServiceException internalAuthenticationServiceException)
        {
            SecurityContextHolder.clearContext();
            logger.error("Internal authentication service exception", internalAuthenticationServiceException);
            httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
            catch(AuthenticationException authenticationException)
        {
            SecurityContextHolder.clearContext();
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
        }
    }

    private void processTokenAuthentication(String apiKey) {
        SessionCredentials authCredentials = new SessionCredentials(apiKey);
        Authentication requestAuthentication = new PreAuthenticatedAuthenticationToken(authCredentials, authCredentials);
        Authentication resultOfAuthentication = tryToAuthenticate(requestAuthentication);
        SecurityContextHolder.getContext().setAuthentication(resultOfAuthentication);
    }

    private Authentication tryToAuthenticate(Authentication requestAuthentication) {
        Authentication responseAuthentication = authenticationManager.authenticate(requestAuthentication);
        if (responseAuthentication == null || !responseAuthentication.isAuthenticated()) {
            throw new InternalAuthenticationServiceException("Unable to authenticate Domain User for provided credentials");
        }
        return responseAuthentication;
    }
}

public class TokenAuthenticationProvider implements AuthenticationProvider {

    private String apiKey;

    public TokenAuthenticationProvider(String apiKey) {
        this.apiKey = apiKey;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SessionCredentials credentials = (SessionCredentials) authentication.getCredentials();
        if (credentials != null && credentials.apiKey.equals(this.apiKey)) {

            //Also evaluate the token here

            Authentication newAuthentication = new PreAuthenticatedAuthenticationToken(apiKey, credentials);
            newAuthentication.setAuthenticated(true);
            return newAuthentication;
        }
        throw new BadCredentialsException("Bad credentials given.");
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return aClass.equals(PreAuthenticatedAuthenticationToken.class);
    }
}

创建会话凭据持有人

public class SessionCredentials {

    String apiKey;
    String accessToken;

    public SessionCredentials(String apiKey, String accessToken) {
        this.apiKey = apiKey;
        this.accessToken = accessToken;
    }

    public String getApiKey() {
        return apiKey;
    }

    public String getAccessToken() {
        return accessToken;
    }
}

最后在您的安全配置中注册这些

//Leave whatever you had here
@Override
public void configure(HttpSecurity http) throws Exception {
    http.addFilterBefore(new TokenAuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class);

    String contentPathDir = String.format("/%s/**", contentPath);

    http.csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and().authorizeRequests()
            .antMatchers("/authorization/**", "/public/**", "/management/**", "/health/**", contentPathDir).permitAll()
            .antMatchers("/**").authenticated();
}




//Add these two below. 
@Override
public void configure(AuthenticationManagerBuilder auth) {
    auth.authenticationProvider(apiKeyAuthenticationProvider());
}

@Bean
public TokenAuthenticationProvider apiKeyAuthenticationProvider() {
    return new TokenAuthenticationProvider(apiKey);
}