【晓时代】SpringBoot + Jpa + Security 简单实例

时光毁灭记忆、已成空白 提交于 2020-01-18 13:31:15

零、项目结构

图片.png

一、创建数据库

图片.png

二、创建项目

1、基础配置
图片.png

2、选择基础依赖
图片.png

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

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

4、去掉 mysql 依赖的 scope 标签
图片.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

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
2、密码错误
图片.png
3、登录成功
图片.png

九、示例下载地址

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!