1

我想在我现有的 spring 项目中添加两步验证。到现在为止,我正在检查用户名和密码,如果凭据正确,则用户已登录。我想要的是,如果凭据正确,则应将 otp 发送到电子邮件并呈现 otp 验证表。如果用户输入正确的 otp,那么他应该登录。我添加了 CustomAuthenticationProvider 和 CustomAuthenticationSuccessHandler 。

我的 SecurityConfiguration 的相关部分如下所示。

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{

    @Autowired
    @Qualifier("customUserDetailsService")
    UserDetailsService userDetailService;
    
    @Autowired
    AuthenticationSuccessHandlerImpl successHandler;
    
    @Autowired
    @Qualifier("tokenRepositoryDao")
    PersistentTokenRepository tokenRepository;
    
    @Autowired
    @Qualifier("customAuthenticationProvider")
    AuthenticationProvider  authenticationProvider;

    private static String key = "rem-me-key";

    @Bean
    public RememberMeServices rememberMeServices() throws Exception {
        return new CustomRememberMeService(key, userDetailService, tokenRepository);
    }
     
    @Autowired
    protected void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService);
        auth.authenticationProvider(authenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/login","/loginVerify" ,"/public/**","/KMD/**","/forgetPassword/**","/changePswd/**","/verifyOtp/**").permitAll()
            .antMatchers("/","/common/**","/logout/**", "/accessDenied/**").access("hasRole('Admin') or hasRole('NormalUser') ")        
            .antMatchers("/normalUser/**").access("hasRole('NormalUser')")
            .antMatchers("/device/**","/softwares/**","/manual/**","/user/**","/addNewUser/**","/manageUser/**","/manageUserEdit/**",
                    "/addNewDevice/**","/manageDevice/**","/addNewSoftManual/**","/editUserPage/**","/view/**").access("hasRole('Admin')") 
            .and()
            .csrf().disable()
            .formLogin().loginPage("/login").loginProcessingUrl("/checkLoginAction").usernameParameter("username").passwordParameter("password")
            .successHandler(successHandler)
            .and()
            .rememberMe().key("rem-me-key").authenticationSuccessHandler(successHandler).rememberMeParameter("remember-me").rememberMeServices(rememberMeServices())
            .tokenRepository(tokenRepository).tokenValiditySeconds(86400).alwaysRemember(true)
            .and()
            .exceptionHandling().accessDeniedPage("/accessDenied");
    }

}

这是 CustomAuthenticationProvider 中编写的代码

@Override
    public Authentication authenticate(Authentication authentication) {

        String name = authentication.getName();
        String password = authentication.getCredentials().toString();
        String hashPassword = null ;
        UsernamePasswordAuthenticationToken token = null;
        try {
             hashPassword = LoadParam.generateHash(password.trim(), name.trim());
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         if (!StringUtils.isEmpty(name) && !StringUtils.isEmpty(password)) {
             try {
                 UserDetails userDetail = null;
                 try {
                        userDetail = userDetailService.loadUserByUsername(name);
                         if(!userDetail.isEnabled()) {
                            return null;
                        }
                        if(hashPassword.matches(userDetail.getPassword())) {
                            token = new UsernamePasswordAuthenticationToken(userDetail,userDetail.getPassword(), userDetail.getAuthorities());
                            token.setDetails(userDetail);
                         }
                         else {
                             return null;
                         }
                    }
                    catch (Exception e) {
                        stringWriter = new StringWriter();
                        printWriter = new PrintWriter(stringWriter);
                        e.printStackTrace(printWriter);
                        logger.error(stringWriter.toString());
                    }
                 return token;
             } 
             catch (UsernameNotFoundException exception) {
                 return new UsernamePasswordAuthenticationToken(name, password, new ArrayList<>());
             }
         }
         else {
             return new UsernamePasswordAuthenticationToken(name, password, new ArrayList<>());
         }
    }

这是我的 CustomUserDetailService 代码

@Service("customUserDetailsService")
public class CustomUserDetailService implements UserDetailsService {
    
    @Autowired 
    @Qualifier("commonDAOImpl")
    private CommonDAO  commonDAO;
    

    @Override
    public UserDetails loadUserByUsername(String username ) throws UsernameNotFoundException {
        HashMap<String, Object> hashMap = new HashMap<>();
        TblUser tblUser = null;
        hashMap = commonDAO.findUserByUserId(username, hashMap);
        if(hashMap.get("status").equals("0")) {
            throw new UsernameNotFoundException("User Not Found");
        }
        else {
             tblUser = (TblUser) hashMap.get("tblUser");
             UserDetails userDetails =  new User(tblUser.getEmailId(), tblUser.getPassword(), 
                     tblUser.isEnabled(), true, true, true, getGrantedAuthorities((List<TblUserRole>) hashMap.get("roles")));
                return userDetails; 
        }
    }
    
     private List<GrantedAuthority> getGrantedAuthorities(List<TblUserRole> tblUserRoles){
            List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
             for(TblUserRole tblUserRole : tblUserRoles) {
                authorities.add(new SimpleGrantedAuthority("ROLE_"+  tblUserRole.getTblRole().getRoleName() ));
            }
            return authorities;
        }
}

我不明白如何处理重定向。请建议我如何实现这一点。如果有人可以为我提供一些帮助,我将不胜感激。

4

0 回答 0