美文网首页
【晓时代】SpringBoot + Jpa + Security

【晓时代】SpringBoot + Jpa + Security

作者: Negen | 来源:发表于2020-01-18 11:36 被阅读0次

    [toc]

    零、项目结构

    图片.png图片.png

    一、创建数据库

    图片.png图片.png

    二、创建项目

    1、基础配置


    图片.png图片.png

    2、选择基础依赖


    图片.png图片.png

    3、引入 LomBok 依赖,让开发跑的飞起

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <scope>provided</scope>
            </dependency>
    

    4、去掉 mysql 依赖的 scope 标签


    图片.png图片.png

    5、完整依赖

    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <!-- <scope>runtime</scope> -->
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
    <!--            <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions> -->
            </dependency>
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-test</artifactId>
                <scope>test</scope>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <scope>provided</scope>
            </dependency>
    

    三、修改application.properties 文件名为 application.yml 并写入如下配置

    server:
      port: 8081
    spring:
      datasource:
        #mysql驱动类
        driver-class-name: com.mysql.cj.jdbc.Driver 
        #数据库连接地址
        url: jdbc:mysql://127.0.0.1:3306/db_spring_security_tutorial?serverTimezone=Asia/Shanghai&autoReconnect=true
        #数据库账号
        username: root
        #密码
        password: 123456
      jpa:
        hibernate:
          #自动建表
          ddl-auto: update
        #方言
        database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
        #显示sql语句
        show-sql: true
    

    四、创建实体类,并创建 UserRepository.java

    1、Permission.java

    @Entity
    @Table(name = "permission")
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Permission {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        long id;
        String permissionName;  //权限名称
        
        public Permission(String permissionName){
            this.permissionName = permissionName;
        }
    }
    

    2、Role.java

    @Entity
    @Table(name = "role")
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Role {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        long id;
        String roleName;    //角色名称
        @OneToMany(cascade = {CascadeType.ALL} , fetch = FetchType.EAGER)
        @JoinColumn(name = "role_id")
        List<Permission> permissions;
    }
    

    3、User.java

    @Entity
    @Table(name = "user")
    @Data
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        long id;
        String userName;    //账号
        String password;    //密码
        String salt;        //盐
        @OneToMany(cascade = {CascadeType.ALL} , fetch = FetchType.EAGER)
        @JoinColumn(name = "user_id")
        List<Role> roles;
    }
    

    4、UserRepository.java

    @Repository
    public interface UserRepository extends JpaRepository<User, Long>{
        User findByUserName(String username);
    }
    

    五、更改账号验证方式,自定义UserDetailsService

    --创建 TemplateUserDetailsService.java

    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    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 com.negen.entity.Permission;
    import com.negen.entity.Role;
    import com.negen.entity.User;
    import com.negen.repository.UserRepository;
    @Service
    public class TemplateUserDetailsService implements UserDetailsService{
        @Autowired
        UserRepository userRepository;
        
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            User loginUser = userRepository.findByUserName(username);
            if (null == loginUser) {
                //账号不存在,抛出异常
                throw new UsernameNotFoundException(username);
            } else {
                //用户存在,创建 SimpleGrantedAuthority集合
                List<SimpleGrantedAuthority> authorities = 
                        new ArrayList<SimpleGrantedAuthority>();
                //遍历角色
                for(Role role:loginUser.getRoles()) {
                    //遍历权限
                    for(Permission permission:role.getPermissions()) {
                        //根据权限名称创建 SimpleGrantedAuthority
                        SimpleGrantedAuthority authority = 
                                new SimpleGrantedAuthority(permission.getPermissionName());
                        authorities.add(authority);
                    }
                }
                return new org.springframework.security.core.userdetails.User(
                        username,   //用户名
                        loginUser.getPassword(),    //用户密码
                        authorities     //权限集合
                        );
            }
        }
    }
    

    六、自定义配置类

    1、创建 TemplateWebSecurityConfig.java 并继承 WebSecurityConfigurerAdapter
    2、重写两个 configure

    图片.png图片.png

    3、完整代码 TemplateWebSecurityConfig.java 如下:

    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.authentication.AuthenticationFailureHandler;
    import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    
    import com.negen.repository.UserRepository;
    import com.negen.service.impl.TemplateUserDetailsService;
    
    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class TemplateWebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        UserRepository userRepository;
        @Autowired
        TemplateUserDetailsService templateUserDetailsService;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(authenticationProvider());
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.cors().and().csrf().disable().authorizeRequests()
                    .antMatchers("/user/register",
                            "/swagger*//**",
                            "/v2/api-docs",
                            "/webjars*//**").permitAll()    //过滤 swagger2       
                    .anyRequest().authenticated()    //配置所有除上面以为的所有请求必须认证(登录)后才能访问
                    .and()
                    .formLogin()
                    .loginPage("/user/login")
                    .loginProcessingUrl("/login")    //登录接口地址
                    .successHandler(authenticationSuccessHandler())  //登录成功处理
                    .failureHandler(authenticationFailureHandler())  //登录失败处理
                    .permitAll();
        }
    
        // 密码加密方式
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Bean
        public DaoAuthenticationProvider authenticationProvider() {
            DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
            provider.setHideUserNotFoundExceptions(false); // 设置是否隐藏 UserNotFoundException
            provider.setUserDetailsService(templateUserDetailsService);
            provider.setPasswordEncoder(passwordEncoder());
            return provider;
        }
    
        // 认证成功处理
        @Bean
        public AuthenticationSuccessHandler authenticationSuccessHandler() {
            // 认证(登录)成功
            return new AuthenticationSuccessHandler() {
                @Override
                public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                        Authentication authentication) throws IOException, ServletException {
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter out = response.getWriter();
                    out.write("登录成功");
                    out.flush();
                }
            };
        }
    
        // 认证失败处理
        @Bean
        public AuthenticationFailureHandler authenticationFailureHandler() {
            return new AuthenticationFailureHandler() {
    
                @Override
                public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                        AuthenticationException exception) throws IOException, ServletException {
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter out = response.getWriter();
                    if (exception instanceof UsernameNotFoundException) {
                        // 账号不存在
                        out.write("账号不存在");
                        out.flush();
                        return;
                    }
                    // 密码错误
                    out.write("密码错误");
                    out.flush();
                }
            };
        }
    }
    

    七、创建测试类新增一条用户记录

    1、UserTest.java 完整代码如下:

    import java.util.ArrayList;
    import java.util.List;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import com.negen.entity.Permission;
    import com.negen.entity.Role;
    import com.negen.entity.User;
    import com.negen.repository.UserRepository;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class UserTest {
        @Autowired
        UserRepository userRepository;
        
        @Test
        public void testAddUser() {
            List<Role> roles = new ArrayList<Role>();
            List<Permission> permissions = new ArrayList<Permission>();
            User user = new User();
            Role role = new Role();
            Permission p1 = new Permission("create");
            Permission p2 = new Permission("delete");
            permissions.add(p1);
            permissions.add(p2);
            role.setRoleName("admin");
            role.setPermissions(permissions);
            roles.add(role);
            user.setUserName("Negen");
            user.setPassword(new BCryptPasswordEncoder().encode("123456"));
            user.setRoles(roles);
            userRepository.save(user);
            System.out.println("====>添加用户成功");
        }
    }
    

    2、运行单元测试添加一位用户

    八、测试

    打开postman进行登录接口测试
    1、账号不存在


    图片.png图片.png

    2、密码错误


    图片.png图片.png
    3、登录成功
    图片.png图片.png

    九、示例下载地址

    https://github.com/Negen9527/spring-security-tutorial-template

    相关文章

      网友评论

          本文标题:【晓时代】SpringBoot + Jpa + Security

          本文链接:https://www.haomeiwen.com/subject/fqskzctx.html