使用Spring Security 4以编程方式验证用户身份

时间:2016-02-02 14:17:58

标签: spring-mvc spring-security

我使用inMemoryAuthentication,并且需要在访问特定端点时以编程方式验证用户(出于测试原因)。因此,我使用基于Programmatically login in a user using spring security的以下方法:

private void login(Role role) {
    logger.warn("Login User with role: " + role.toString());
    Authentication auth =
        new UsernamePasswordAuthenticationToken("user", "password", getAuthorities(role));
    SecurityContext securityContext = SecurityContextHolder.getContext();
    securityContext.setAuthentication(auth);
}

private Collection<GrantedAuthority> getAuthorities(Role role) {
    Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
    GrantedAuthority grantedAuthority = (GrantedAuthority) () -> role.toString();
    grantedAuthorities.add(grantedAuthority);
    return grantedAuthorities;
}

正确设置了securityContext(getAuthentication按预期返回用户),但是未设置JSESSIONID cookie。

1 个答案:

答案 0 :(得分:0)

我可以解决我的问题,但这并不容易,我不确定是否有更好的解决方案。

我创建了一个过滤器,一个自定义authenticationProvider和一个自定义authenticationToken

public class E2EAuthenticationFilter extends GenericFilterBean {
    private final Logger logger = LoggerFactory.getLogger(E2EAuthenticationFilter.class);

    private AuthenticationManager authenticationManager;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        Role role = null;
        String username = null;
        String password = null;
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        if(isLoginRequest(request.getRequestURI())){
            String roleName = getRoleName(request.getRequestURI());
            switch(roleName.toUpperCase()){
                case "ADMIN":
                    role = Role.ADMIN;
                    username = "admin";
                    password = "admin";
                    break;
                case "REPORTER":
                    role = Role.REPORTER;
                    username = "reporter";
                    password = "reporter";
                    break;
                default:
                    break;
            }

            authenticateUser(username, password, role);
        }

        chain.doFilter(request, response);
    }

    public AuthenticationManager getAuthenticationManager() {
        return authenticationManager;
    }

    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    private Collection<GrantedAuthority> getAuthorities(Role role) {
        Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        GrantedAuthority grantedAuthority = (GrantedAuthority) () -> "ROLE_"+role.toString();
        grantedAuthorities.add(grantedAuthority);
        return grantedAuthorities;
    }

    private String getRoleName(String uri){
        String[] requestUriParts = uri.split("/");
        return requestUriParts[requestUriParts.length-1];
    }

    private void authenticateUser(String username, String password, Role role){
        E2EAuthenticationToken token = new E2EAuthenticationToken(username, password, getAuthorities(role));
        Authentication authResult = authenticationManager.authenticate(token);
        SecurityContextHolder.getContext().setAuthentication(authResult);
    }

    private boolean isLoginRequest(String uri) {
        return uri.matches("\\/e2e\\/auth\\/login\\/(\\w)+");
    }
}

authProvider类:

@Component
public class E2EAuthenticationProvider implements AuthenticationProvider {


    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        E2EAuthenticationToken token = (E2EAuthenticationToken) authentication;
        E2EAuthenticationToken authenticated = new E2EAuthenticationToken(token.getUsername(), token.getPassword(), token.getAuthorities());

        authenticated.setAuthenticated(true);
        return  authenticated;
    }

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

令牌类:

public class E2EAuthenticationToken extends AbstractAuthenticationToken {
    private String username;
    private String password;

    public E2EAuthenticationToken(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.username = username;
    }

    @Override
    public Object getCredentials() {
        return this.username;
    }

    @Override
    public Object getPrincipal() {
        return this.username;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

最后弹簧配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class InMemorySecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private E2EAuthenticationProvider e2eAuthenticationProvider;

    @Bean
    public E2EAuthenticationFilter e2eAuthenticationFilter() throws Exception {
        E2EAuthenticationFilter filter = new E2EAuthenticationFilter();
        filter.setAuthenticationManager( authenticationManager() );
        return filter;
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(e2eAuthenticationProvider);

        auth.inMemoryAuthentication()
            .withUser("admin")
            .password("admin")
            .roles(Role.ADMIN.name())
            .and()
            .withUser("reporter")
            .password("reporter")
            .roles(Role.REPORTER.name());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .requestMatchers().antMatchers("/api/**", "/e2e/auth/**", "/acuator/**")
            .and().addFilterBefore(e2eAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
            .authorizeRequests()
            .antMatchers("/actuator/health").permitAll()
            .antMatchers("/actuator/info").permitAll()
            .anyRequest().authenticated()
            .and().httpBasic()
            .and().csrf().disable();
    }
}

您可能已经注意到,我将此代码用于端点(当然仅在E2E配置中可用)以登录用户进行硒测试。

相关问题