spring-mvc - Spring Security 自定义注销

标签 spring-mvc spring-security spring-boot

我有一个使用 Spring 安全性的 SpringBoot 应用程序,但我想在身份验证而非授权时对其进行自定义。我已成功登录,但我不知道我必须将注销操作放在哪里。 这是我的一些代码: 1. Controller :

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

    return new ModelAndView("pages/login");

    }
  1. 网络安全配置

    @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. UAMS 登录:

    @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;
        }
    
    }
    

如您所见,我正在使用 UAMS 来查看此用户是否有效。我仍然不知道如何记住每个 session ,所以你可以看到有脏代码 HashMap containsKey。更重要的是,如果我制作 session.logout(username); 我应该在哪里调用它? UAMS是我公司用的一个Jar。

如果你觉得这个问题不清楚,我很抱歉,请问我。 任何帮助将不胜感激。

最佳答案

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

如果这就是您所说的,我最好使用自定义 LogoutSuccessHandler并将其在您的配置中绑定(bind)到注销操作。

LogoutSuccessHandler 接口(interface)只有一个您应该实现的方法:

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");

    }

}

在这里您可以做任何您需要的事情,甚至可以在 session 注销后重定向到您应该去的任何页面。

编辑:

你应该像我说的那样使用一个 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();
    }

关于spring-mvc - Spring Security 自定义注销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38479878/

相关文章:

spring-boot - Kafka、Spring Kafka 和重新传递旧消息

java - 自定义 validator 停止 spring 内部验证

java - 如何从 HttpMethodParams 获取值

spring-boot - Thymeleaf 下载登录空白文件,而不是导航到 login.html (Springboot)

javascript - 图像未插入到 Spring Boot 中

java - 获取Page对象的每个页面 - Spring

java - SPRING MVC - 如何获取表单:input path from JSP to Controller的值

java - 如何在 Spring MVC 中使用转发处理 Controller 之间的 ModelMap 的有效方法

spring-boot - 即使提供了有效 token ,Keycloak 也会要求提供登录凭据

java - 你能以编程方式配置 Spring-Security 吗?