zoukankan      html  css  js  c++  java
  • spring security使用hibernate进行查询数据库验证

    前面查询数据库采用的都是jdbc方式,如果系统使用的是hibernate,该如何进行呢,下面就是实现步骤,关键还是实现自定义的UserDetailsService
    项目结构如下:
    使用hibernate,pom.xml文件如下:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.petter</groupId>
      <artifactId>security-hibernate-annotation</artifactId>
      <packaging>war</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>security-hibernate-annotation Maven Webapp</name>
      <url>http://maven.apache.org</url>
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring.version>4.3.5.RELEASE</spring.version>
        <spring.security.version>4.2.1.RELEASE</spring.security.version>
        <mysql.connector.version>5.1.40</mysql.connector.version>
        <dbcp.version>2.1.1</dbcp.version>
          <hibernate.version>5.2.9.Final</hibernate.version>
      </properties>
      <dependencies>
        <!-- database pool -->
        <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-dbcp2</artifactId>
          <version>${dbcp.version}</version>
        </dependency>
          <!-- Hibernate ORM -->
          <dependency>
              <groupId>org.hibernate</groupId>
              <artifactId>hibernate-core</artifactId>
              <version>${hibernate.version}</version>
          </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>${spring.version}</version>
        </dependency>
          <!-- ORM integration, e.g Hibernate -->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-orm</artifactId>
              <version>${spring.version}</version>
          </dependency>
          <!-- Spring + aspects -->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-aspects</artifactId>
              <version>${spring.version}</version>
          </dependency>
        <dependency>
          <groupId>org.thymeleaf</groupId>
          <artifactId>thymeleaf-spring4</artifactId>
          <version>3.0.3.RELEASE</version>
        </dependency>
        <!-- Spring Security -->
        <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-web</artifactId>
          <version>${spring.security.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-config</artifactId>
          <version>${spring.security.version}</version>
        </dependency>
        <!-- 用于thymeleaf中使用security的标签 -->
        <dependency>
          <groupId>org.thymeleaf.extras</groupId>
          <artifactId>thymeleaf-extras-springsecurity4</artifactId>
          <version>3.0.2.RELEASE</version>
        </dependency>
        <!-- mysql -->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>${mysql.connector.version}</version>
        </dependency>
      </dependencies>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.3</version>
            <configuration>
              <source>1.8</source>
              <target>1.8</target>
              <encoding>utf8</encoding>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>

    一、由于使用hibernate,我们使用jpa自己生成数据库表,具体是

    1、用于实现基于持久化Token的记住我功能的表persistent_logins,对应的类是PersistentLogin
    package com.petter.model;
    import javax.persistence.*;
    import java.util.Date;
    /**
     * @author hongxf
     * @since 2017-04-17 14:42
     */
    @Entity
    @Table(name = "persistent_logins")
    public class PersistentLogin {
        private String series;
        private String username;
        private String token;
        private Date lastUsed;
        @Id
        @Column(name = "series")
        public String getSeries() {
            return series;
        }
        public void setSeries(String series) {
            this.series = series;
        }
        @Column(name = "username", nullable = false)
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        @Column(name = "token", nullable = false)
        public String getToken() {
            return token;
        }
        public void setToken(String token) {
            this.token = token;
        }
        @Temporal(TemporalType.TIMESTAMP)
        @Column(name = "last_used", nullable = false)
        public Date getLastUsed() {
            return lastUsed;
        }
        public void setLastUsed(Date lastUsed) {
            this.lastUsed = lastUsed;
        }
    }

    2、用户类User对应表users

    package com.petter.model;
    import javax.persistence.*;
    import java.util.HashSet;
    import java.util.Set;
    /**
     * @author hongxf
     * @since 2017-04-17 10:29
     */
    @Entity
    @Table(name = "users")
    public class User {
        private String username;
        private String password;
        private boolean enabled;
        private boolean accountNonExpired;
        private boolean accountNonLocked;
        private boolean credentialsNonExpired;
        private Set<UserRole> userRole = new HashSet<>();
        @Id
        @Column(name = "username", unique = true, nullable = false, length = 45)
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        @Column(name = "password", nullable = false, length = 60)
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        @Column(name = "enable", nullable = false)
        public boolean isEnabled() {
            return enabled;
        }
        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
        @Column(name = "accountNonExpired", nullable = false)
        public boolean isAccountNonExpired() {
            return accountNonExpired;
        }
        public void setAccountNonExpired(boolean accountNonExpired) {
            this.accountNonExpired = accountNonExpired;
        }
        @Column(name = "accountNonLocked", nullable = false)
        public boolean isAccountNonLocked() {
            return accountNonLocked;
        }
        public void setAccountNonLocked(boolean accountNonLocked) {
            this.accountNonLocked = accountNonLocked;
        }
        @Column(name = "credentialsNonExpired", nullable = false)
        public boolean isCredentialsNonExpired() {
            return credentialsNonExpired;
        }
        public void setCredentialsNonExpired(boolean credentialsNonExpired) {
            this.credentialsNonExpired = credentialsNonExpired;
        }
        @OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
        public Set<UserRole> getUserRole() {
            return userRole;
        }
        public void setUserRole(Set<UserRole> userRole) {
            this.userRole = userRole;
        }
    }

    3、用户权限表user_roles对应类UserRole

    package com.petter.model;
    import javax.persistence.*;
    /**
     * @author hongxf
     * @since 2017-04-17 10:32
     */
    @Entity
    @Table(name = "user_roles", uniqueConstraints = @UniqueConstraint(columnNames = {"role", "username"}))
    public class UserRole {
        private Integer userRoleId;
        private User user;
        private String role;
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "user_role_id")
        public Integer getUserRoleId() {
            return userRoleId;
        }
        public void setUserRoleId(Integer userRoleId) {
            this.userRoleId = userRoleId;
        }
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "username", nullable = false)
        public User getUser() {
            return user;
        }
        public void setUser(User user) {
            this.user = user;
        }
        @Column(name = "role", nullable = false, length = 45)
        public String getRole() {
            return role;
        }
        public void setRole(String role) {
            this.role = role;
        }
    }

    4、用于保存登录失败尝试次数的UserAttempts

    package com.petter.model;
    import javax.persistence.*;
    import java.util.Date;
    /**
     * @author hongxf
     * @since 2017-03-20 10:50
     */
    @Entity
    @Table(name = "user_attempts")
    public class UserAttempts {
        private int id;
        private String username;
        private int attempts;
        private Date lastModified;
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        @Column(name = "username")
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        @Column(name = "attempts")
        public int getAttempts() {
            return attempts;
        }
        public void setAttempts(int attempts) {
            this.attempts = attempts;
        }
        @Temporal(TemporalType.TIMESTAMP)
        @Column(name = "lastModified")
        public Date getLastModified() {
            return lastModified;
        }
        public void setLastModified(Date lastModified) {
            this.lastModified = lastModified;
        }
    }

    二、配置hibernate,在AppConfig类中添加hibernate的配置

    package com.petter.config;
    import org.apache.commons.dbcp2.BasicDataSource;
    import org.hibernate.SessionFactory;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    import org.springframework.orm.hibernate5.HibernateTransactionManager;
    import org.springframework.orm.hibernate5.LocalSessionFactoryBuilder;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect;
    import org.thymeleaf.spring4.SpringTemplateEngine;
    import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
    import org.thymeleaf.spring4.view.ThymeleafViewResolver;
    import org.thymeleaf.templatemode.TemplateMode;
    import java.util.Properties;
    /**
     * 相当于
     * @author hongxf
     * @since 2017-03-08 10:11
     */
    @EnableWebMvc
    @Configuration
    @ComponentScan({"com.petter.*"})
    @EnableTransactionManagement
    @Import({SecurityConfig.class})
    public class AppConfig  {
        @Bean
        public SessionFactory sessionFactory() {
            LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
            builder.scanPackages("com.petter.model")
                    .addProperties(getHibernateProperties());
            return builder.buildSessionFactory();
        }
        private Properties getHibernateProperties() {
            Properties prop = new Properties();
            prop.put("hibernate.format_sql", "true");
            prop.put("hibernate.show_sql", "true");
            prop.put("hibernate.hbm2ddl.auto", "update");
            prop.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
            return prop;
        }
        @Bean(name = "dataSource")
        public BasicDataSource dataSource() {
            BasicDataSource ds = new BasicDataSource();
            ds.setDriverClassName("com.mysql.jdbc.Driver");
            ds.setUrl("jdbc:mysql://192.168.11.81:3306/security_learning_3");
            ds.setUsername("petter");
            ds.setPassword("petter");
            return ds;
        }
        @Bean
        public HibernateTransactionManager txManager() {
            return new HibernateTransactionManager(sessionFactory());
        }
        @Bean
        public SpringResourceTemplateResolver springResourceTemplateResolver() {
            SpringResourceTemplateResolver springResourceTemplateResolver = new SpringResourceTemplateResolver();
            springResourceTemplateResolver.setPrefix("/WEB-INF/pages/");
            springResourceTemplateResolver.setSuffix(".html");
            springResourceTemplateResolver.setTemplateMode(TemplateMode.HTML);
            springResourceTemplateResolver.setCacheable(false);
            springResourceTemplateResolver.setCharacterEncoding("UTF-8");
            return springResourceTemplateResolver;
        }
        @Bean
        public SpringTemplateEngine springTemplateEngine() {
            SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
            springTemplateEngine.setTemplateResolver(springResourceTemplateResolver());
            springTemplateEngine.addDialect(new SpringSecurityDialect());
            return springTemplateEngine;
        }
        @Bean
        public ThymeleafViewResolver thymeleafViewResolver() {
            ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
            thymeleafViewResolver.setTemplateEngine(springTemplateEngine());
            thymeleafViewResolver.setCharacterEncoding("UTF-8");
            return thymeleafViewResolver;
        }
    }

    注意这里添加了事务注解@EnableTransactionManagement,否则运行会报无事务错误,并且需要在具体的repository中添加@Transactional注解

    三、使用hibernate查询数据库获得User
    1、定义接口UserDao
    package com.petter.dao;
    import com.petter.model.User;
    /**
     * @author hongxf
     * @since 2017-04-17 10:41
     */
    public interface UserDao {
        User findByUserName(String username);
    }

    2、实现接口UserDao

    package com.petter.dao.impl;
    import com.petter.dao.UserDao;
    import com.petter.model.User;
    import org.hibernate.SessionFactory;
    import org.springframework.stereotype.Repository;
    import org.springframework.transaction.annotation.Transactional;
    import javax.annotation.Resource;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * @author hongxf
     * @since 2017-04-17 10:42
     */
    @Repository
    public class UserDaoImpl implements UserDao {
        @Resource
        private SessionFactory sessionFactory;
        @SuppressWarnings("unchecked")
        @Transactional(readOnly = true)
        @Override
        public User findByUserName(String username) {
            List<User> users = sessionFactory.getCurrentSession()
                    .createQuery("from User where username = ?")
                    .setParameter(0, username)
                    .list();
            if (users.size() > 0) {
                return users.get(0);
            } else {
                return null;
            }
        }
    }

    四、实现自定义UserDetailsService

    package com.petter.service;
    import com.petter.dao.UserDao;
    import com.petter.model.User;
    import com.petter.model.UserRole;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Service;
    import javax.annotation.Resource;
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    /**
     * security的验证过程会调用指定的UserDetailsService
     * 自定义的UserDetailsService查询数据库得到自己User后
     * 组装org.springframework.security.core.userdetails.User返回
     * @author hongxf
     * @since 2017-04-17 10:45
     */
    @Service("userDetailsService")
    public class CustomUserDetailsService implements UserDetailsService {
        @Resource
        private UserDao userDao;
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            User user = userDao.findByUserName(username);
            if (user == null) {
                throw new UsernameNotFoundException("该用户不存在:" + username);
            }
            List<GrantedAuthority> authorities =  buildUserAuthority(user.getUserRole());
            return buildUserForAuthentication(user, authorities);
        }
        // 把自定义的User转换成org.springframework.security.core.userdetails.User
        private org.springframework.security.core.userdetails.User buildUserForAuthentication(
                User user,
                List<GrantedAuthority> authorities) {
            return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
                    user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), authorities);
        }
        private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {
            Set<GrantedAuthority> setAuths = new HashSet<>();
            // Build user's authorities
            for (UserRole userRole : userRoles) {
                setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
            }
            return new ArrayList<>(setAuths);
        }
    }

    五、修改SecurityConfig配置

    package com.petter.config;
    import com.petter.handler.CustomAuthenticationProvider;
    import com.petter.service.CustomUserDetailsService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
    import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
    import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
    import javax.annotation.Resource;
    import javax.sql.DataSource;
    /**
     * 相当于spring-security.xml中的配置
     * @author hongxf
     * @since 2017-03-08 9:30
     */
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Resource
        private DataSource dataSource;
        @Resource
        private CustomAuthenticationProvider authenticationProvider;
        @Resource
        private CustomUserDetailsService userDetailsService;
        @Bean
        public PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            //authenticationProvider.setPasswordEncoder(passwordEncoder());
            //auth.authenticationProvider(authenticationProvider);
            auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        }
        /**
         * 配置权限要求
         * 采用注解方式,默认开启csrf
         * @param http
         * @throws Exception
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/admin/**").hasRole("ADMIN")
                    .antMatchers("/dba/**").hasAnyRole("ADMIN", "DBA")
                .and()
                    .formLogin().successHandler(savedRequestAwareAuthenticationSuccessHandler())
                    .loginPage("/login") //指定自定义登录页
                    .failureUrl("/login?error") //登录失败的跳转路径
                    .loginProcessingUrl("/auth/login_check") //指定了登录的form表单提交的路径,需与表单的action值保存一致,默认是login
                    .usernameParameter("user-name").passwordParameter("pwd")
                .and()
                    .logout().logoutSuccessUrl("/login?logout")
                .and()
                    .exceptionHandling().accessDeniedPage("/403")
                .and()
                    .csrf()
                .and()
                    //.rememberMe().rememberMeParameter("remember-me") //其实默认就是remember-me,这里可以指定更换
                    //.tokenValiditySeconds(1209600)
                    //.key("hongxf");
                    .rememberMe().tokenRepository(persistentTokenRepository())
                    .tokenValiditySeconds(1209600);
        }
        //如果采用持久化 token 的方法则需要指定保存token的方法
        @Bean
        public PersistentTokenRepository persistentTokenRepository() {
            JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
            db.setDataSource(dataSource);
            return db;
        }
        //使用remember-me必须指定UserDetailsService
        @Override
        protected UserDetailsService userDetailsService() {
            return userDetailsService;
        }
        /**
         * 这里是登录成功以后的处理逻辑
         * 设置目标地址参数为targetUrl
         * /auth/login_check?targetUrl=/admin/update
         * 这个地址就会被解析跳转到/admin/update,否则就是默认页面
         *
         * 本示例中访问update页面时候会判断用户是手动登录还是remember-me登录的
         * 如果是remember-me登录的则会跳转到登录页面进行手动登录再跳转
         * @return
         */
        @Bean
        public SavedRequestAwareAuthenticationSuccessHandler savedRequestAwareAuthenticationSuccessHandler() {
            SavedRequestAwareAuthenticationSuccessHandler auth = new SavedRequestAwareAuthenticationSuccessHandler();
            auth.setTargetUrlParameter("targetUrl");
            return auth;
        }
    }

    至此进行测试完全没有问题,但是此处的配置没有实现多次登录失败锁定用户的功能,因为这里没有指定自定义的AuthenticationProvider,使用的是默认的AuthenticationProvider的实现类DaoAuthenticationProvider。

    于是使用自定义的AuthenticationProvider实现类CustomAuthenticationProvider
    package com.petter.handler;
    import com.petter.dao.UserDetailsDao;
    import com.petter.model.UserAttempts;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.security.authentication.BadCredentialsException;
    import org.springframework.security.authentication.LockedException;
    import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.stereotype.Component;
    import javax.annotation.Resource;
    import java.util.Date;
    /**
     * 自定义验证程序,可以在这里进行其他附属操作,具体验证程序仍然调用上层接口即可
     * @author hongxf
     * @since 2017-03-20 14:28
     */
    @Component("authenticationProvider")
    public class CustomAuthenticationProvider extends DaoAuthenticationProvider {
        @Resource
        private UserDetailsDao userDetailsDao;
        @Autowired
        @Qualifier("userDetailsService")
        @Override
        public void setUserDetailsService(UserDetailsService userDetailsService) {
            super.setUserDetailsService(userDetailsService);
        }
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            try {
                //调用上层验证逻辑
                Authentication auth = super.authenticate(authentication);
                //如果验证通过登录成功则重置尝试次数, 否则抛出异常
                userDetailsDao.resetFailAttempts(authentication.getName());
                return auth;
            } catch (BadCredentialsException e) {
                //如果验证不通过,则更新尝试次数,当超过次数以后抛出账号锁定异常
                userDetailsDao.updateFailAttempts(authentication.getName());
                throw e;
            } catch (LockedException e){
                //该用户已经被锁定,则进入这个异常
                String error;
                UserAttempts userAttempts =
                        userDetailsDao.getUserAttempts(authentication.getName());
                if(userAttempts != null){
                    Date lastAttempts = userAttempts.getLastModified();
                    error = "用户已经被锁定,用户名 : "
                            + authentication.getName() + "最后尝试登陆时间 : " + lastAttempts;
                }else{
                    error = e.getMessage();
                }
                throw new LockedException(error);
            }
        }
    }

    相应的使用hibernate修改之前的UserDetailsDao接口的实现方法

    package com.petter.dao.impl;
    import com.petter.dao.UserDetailsDao;
    import com.petter.model.UserAttempts;
    import org.hibernate.SessionFactory;
    import org.springframework.dao.EmptyResultDataAccessException;
    import org.springframework.jdbc.core.support.JdbcDaoSupport;
    import org.springframework.security.authentication.LockedException;
    import org.springframework.stereotype.Repository;
    import org.springframework.transaction.annotation.Transactional;
    import javax.annotation.PostConstruct;
    import javax.annotation.Resource;
    import javax.sql.DataSource;
    import java.util.Date;
    import java.util.List;
    /**
     * @author hongxf
     * @since 2017-03-20 10:54
     */
    @Repository
    public class UserDetailsDaoImpl implements UserDetailsDao {
        @Resource
        private SessionFactory sessionFactory;
        private static final int MAX_ATTEMPTS = 3;
        @Transactional
        @Override
        public void updateFailAttempts(String username) {
            UserAttempts userAttempts = getUserAttempts(username);
            if (userAttempts == null) {
                if (isUserExists(username)) { //如果存在这个用户
                    // 如果之前没有记录,添加一条
                    userAttempts = new UserAttempts();
                    userAttempts.setUsername(username);
                    userAttempts.setAttempts(1);
                    userAttempts.setLastModified(new Date());
                    sessionFactory.getCurrentSession().save(userAttempts);
                }
            } else {
                if (isUserExists(username)) {
                    userAttempts.setAttempts(userAttempts.getAttempts() + 1);
                    userAttempts.setLastModified(new Date());
                    sessionFactory.getCurrentSession().update(userAttempts);
                    sessionFactory.getCurrentSession().flush();
                }
                if (userAttempts.getAttempts() >= MAX_ATTEMPTS) {
                    // 大于尝试次数则锁定
                    sessionFactory.getCurrentSession()
                            .createQuery("update User u set u.accountNonLocked =:accountNonLocked where u.username =:username")
                            .setParameter("accountNonLocked", false)
                            .setParameter("username", username)
                            .executeUpdate();
                    // 并且抛出账号锁定异常
                    throw new LockedException("用户账号已被锁定,请联系管理员解锁");
                }
            }
        }
        @SuppressWarnings("unchecked")
        @Transactional(readOnly = true)
        @Override
        public UserAttempts getUserAttempts(String username) {
            List<UserAttempts> list = sessionFactory.getCurrentSession()
                    .createQuery("from UserAttempts where username =:username")
                    .setParameter("username", username)
                    .list();
            if (list.size() > 0) {
                return list.get(0);
            } else {
                return null;
            }
        }
        @Transactional
        @Override
        public void resetFailAttempts(String username) {
            sessionFactory.getCurrentSession()
                    .createQuery("update UserAttempts ua set ua.attempts = 0, ua.lastModified = null where ua.username =:username")
                    .setParameter("username", username)
                    .executeUpdate();
        }
        /**
         * 判断用户是否存在
         * @param username
         * @return
         */
        private boolean isUserExists(String username) {
            boolean result = false;
            Long count = (Long) sessionFactory.getCurrentSession()
                    .createQuery("select count(*) from User u where u.username =:username")
                    .setParameter("username", username)
                    .iterate().next();
            if (count > 0) {
                result = true;
            }
            return result;
        }
    }

    当然最后还要修改下SecurityConfig配置

    @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            authenticationProvider.setPasswordEncoder(passwordEncoder());
            auth.authenticationProvider(authenticationProvider);
            //auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        }

    指定自定义的authenticationProvider

    其他有关的对应页面和Controlller参考之前的例子即可,运行测试。
  • 相关阅读:
    JQUERY1.9学习笔记 之基本过滤器(八) 最后元素选择器
    解决接收参数乱码,tomcat的URIEncoding=UTF-8
    mac下配置maven
    [forwarding] Struts2中action接收中文参数为乱码解决方法
    [forwarding]软考复习之软件架构风格
    [forwarding]Write operations are not allowed in read-only mode 只读模式下(FlushMode.NEVER/MANUAL)写操作不允许问题
    [forwarding]详解Linux命令行下常用svn命令
    [forwarding]mysql用户授权
    【转】Hibernate 查询语言Query Language(HQL)
    java.lang.NoSuchMethodError: antlr.collections.AST.getLine()I错误
  • 原文地址:https://www.cnblogs.com/hongxf1990/p/6726058.html
Copyright © 2011-2022 走看看