Spring Security自定义注销

时间:2016-07-20 11:22:00

标签: spring-mvc spring-security spring-boot

我有一个使用Spring安全性的SpringBoot应用程序,但我希望在身份验证时自定义它,而不是授权。我已成功登录,但我不知道在哪里进行注销操作。 以下是我的一些代码: 1.控制器:

    @RequestMapping(value={"/login"}, method=RequestMethod.GET)
    public ModelAndView login(){

    return new ModelAndView("pages/login");

    }
  1. WebSecurityConfig

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        private @Autowired CustomAuthenticationProvider authenticationManager;
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
            .authorizeRequests()
                .anyRequest()
                    .authenticated()
                .and()
                .formLogin()
                    .usernameParameter("username")
                    .passwordParameter("password")
                    .failureUrl("/login?error")
                    .defaultSuccessUrl("/")
                    .loginPage("/login")
                    .permitAll()
                .and()
                    .logout()
                    .logoutRequestMatcher(
                            new AntPathRequestMatcher("/login?logout")
                    ).logoutSuccessUrl("/login").permitAll()
                .and()
                .csrf().disable();
        }
    
        @Autowired
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
          auth.authenticationProvider( authenticationManager );
        }
    
        @Bean
        protected AuthenticationProvider getServicesAuthenticationProvider() {
        //stackoverflow.com/questions/22453550/custom-authentication-provider-not-being-called/22457561#22457561
             return new CustomAuthenticationProvider();
        }
    
        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring()
                    .antMatchers("/**/*.css")
                    .antMatchers("/**/*.js")
                    .antMatchers("/**/*.jpg")
                    .antMatchers("/**/*.png")
                    .antMatchers("/**/*.gif")
                    .antMatchers("/resources/**");
        }
        public PasswordEncoder passwordEncoder(){
            PasswordEncoder encoder = NoOpPasswordEncoder.getInstance();
            return encoder;
        }
    }
    
  2. CustomAuthenticationProvider

    @Component
    public class CustomAuthenticationProvider implements AuthenticationProvider{
        private static Logger logger = Logger.getLogger(CustomAuthenticationProvider.class);
        private @Autowired UAMSLogin uamsLogin;
        private Map<String, Boolean> userLoggedIn = new HashMap<String, Boolean>();
    
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            String username = authentication.getPrincipal() + "";
            String password = authentication.getCredentials() + "";
            logger.info("authenticating....");
            if(username.equals("")|| username==null || password.equals("")|| password==null){
                logger.fatal("username or password cannot be empty!");
                return null;
            }
            else if(userLoggedIn.containsKey(username)){
                UsernamePasswordAuthenticationToken a = new UsernamePasswordAuthenticationToken(username, password);
                return a;
            }
            try {
                if (uamsLogin.loginUams(username, password)) {
                    logger.info("authentication success");
                    UamsSession sessionInfo = uamsLogin.getUams();
                    logger.info("authentication success");
                    String role = "USER";
                    userLoggedIn.put(username, true);
                    UsernamePasswordAuthenticationToken a = new UsernamePasswordAuthenticationToken(username, password);
                    return a;
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                logger.info("authentication failed");
                e.printStackTrace();
                throw new BadCredentialsException("1000");
            }
            return null;
        }
    
        @Override
        public boolean supports(Class<?> authentication) {
            return authentication.equals(UsernamePasswordAuthenticationToken.class);
        }
    }
    
  3. UAMSLogin:

    @Component
    public class UAMSLogin implements Serializable {
    
    
        private static Logger logger = Logger.getLogger(UAMSLogin.class);
        private static final long serialVersionUID = 1L;
        private static boolean isConnected = false;
        private UamsSession session;
        @Value("${UAMS.SEC_SRV_CONN}")
        private String UAMS_SERVER_CONNECTION;
    
        @Value("${UAMS.CSM_SERVER_URL}")
        private String UAMS_CSM_SERVER_URL;
    
        @Value("${amdocs.ticketapplicationid}")
        private String amdocs_ticketapplicationid;
    
        @Value("${amdocs.ticketparam}")
        private String amdocs_ticketparam;  
        public UAMSLogin(){
    
        }
        // Login with UAMS
        public boolean loginUams(String username, String password) throws Exception {
            logger.info("loginUams with " + username + "/" + password);
            session = this.createSession();
            logger.info("create session success: "+session.toString());
            String ticket=null;
    
            logger.info("UamsSystem version: "+UamsSystem.getVersionString());
            try {
                session.ensureSession(username, password);
                ticket = session.getTicket();
                if (ticket != null && ticket !="") {
                    logger.info("login success : " + session.getTicket());
                    isConnected = true;
                    return true;
                } else {
                    logger.info("login failed: ticket is NULL");
                    return false;
                }
            } catch (Exception e) {
                logger.info("login failed: ", e);
                return false;
            }
        }
    
        protected UamsSession createSession() throws Exception {
            UamsSession session     = new UamsSession(ReadConfig.readInputStream());
    
            logger.info("UAMS_SERVER_CONNECTION: "+UAMS_SERVER_CONNECTION);
            logger.info("UAMS_CSM_SERVER_URL: "+UAMS_CSM_SERVER_URL);
            logger.info("amdocs_ticketapplicationid: "+amdocs_ticketapplicationid);
            logger.info("amdocs_ticketparam:  "+amdocs_ticketparam);
            session.setSecurityUrl(UAMS_SERVER_CONNECTION);
            session.setProviderUrl(UAMS_CSM_SERVER_URL);
    
            session.setApplicationId(amdocs_ticketapplicationid);
            session.setParam(amdocs_ticketparam);
            return session;
        }
    
        public static boolean isConnected() {
            return isConnected;
        }
    
    
        public UamsSession getUams(){
            return session;
        }
    
    }
    
  4. 正如您所看到的,我正在使用UAMS来查看此用户是否有效。我仍然不知道如何记住每个会话,因为你可以看到有脏代码HashMap containsKey。更重要的是,如果我让session.logout(username);我应该在哪里打电话? UAMS是我公司使用的Jar。

    如果你发现这个问题不明确我很抱歉请你问我。 任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:4)

如果我理解,我想你想在Spring Security中完成注销后对你谈到的UAMS库执行一些操作。

如果您正在谈论这个问题,我最好使用自定义LogoutSuccessHandler并将其在您的配置中绑定到注销操作。

LogoutSuccessHandler接口只有一个你应该实现的方法:

public class CustomLogoutHandler implements LogoutSuccessHandler {

    private Logger logger = Logger.getLogger(this.getClass());

    /* (non-Javadoc)
     * @see org.springframework.security.web.authentication.logout.LogoutSuccessHandler#onLogoutSuccess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication)
     */
    @Override
    public void onLogoutSuccess(HttpServletRequest request,
            HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException {

        logger.debug("CustomLogoutHandler.onLogoutSuccess");

    }

}

在这里,您可以根据需要进行监视,然后重定向到会话注销后应该转到的任何页面。

修改

你应该像我说的那样使用LogoutSuccessHandler,或者甚至更好地添加LogoutHandler

public class TaskImplementingLogoutHandler implements LogoutHandler {

    /* (non-Javadoc)
     * @see org.springframework.security.web.authentication.logout.LogoutHandler#logout(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication)
     */
    @Override
    public void logout(HttpServletRequest req, HttpServletResponse res,
            Authentication authentication) {
        // do whatever you need
    }

} 

一旦实现了符合您需求的LogoutHandler,您应该将其添加到您的配置中。看一下java安全配置logout section

您的java安全配置必须如下:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .authorizeRequests()
            .anyRequest()
                .authenticated()
            .and()
            .formLogin()
                .usernameParameter("username")
                .passwordParameter("password")
                .failureUrl("/login?error")
                .defaultSuccessUrl("/")
                .loginPage("/login")
                .permitAll()
            .and()
                .logout()
                .logoutRequestMatcher(
                        new AntPathRequestMatcher("/login?logout")
                )
                .addLogoutHandler(new TaskImplementingLogoutHandler())
                .logoutSuccessUrl("/login").permitAll()
            .and()
            .csrf().disable();
    }

答案 1 :(得分:0)

将此行添加到安全上下文xml文件中:

<security:logout invalidate-session="true" logout-url="/logout" />

这样,当用户的会话到达urldomain/logout时,会使该会话无效。

在此处查看更复杂的示例:spring security customize logout handler

我发现了一些教程:http://www.baeldung.com/spring-security-logout http://websystique.com/spring-security/spring-security-4-logout-example/

希望这有帮助。