SpringBoot 2.0.5简单整合Spring Security遇到的坑

SpringBoot整合Security的博客案例网上已经很多了,但个人觉得对于一个初次整合Security的同学来说,一个简单的案例还是很有必要的。为此,上传一个本人整合的案例,仅供大家参考,也为自己记录一下,话不多说,表演开始。

版本介绍:SpringBoot 2.0.5,JDK 1.8

首先创建SpringBoot项目,能看到这里的同学,相信这一步就不用多说了,可以使用Eclipse中的Spring插件创建,简单又省事。

引入依赖:

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.peng.demo</groupId>
	<artifactId>SpringBoot-security</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>SpringBoot-security</name>
	<description>SpringBoot-security</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.5.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<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>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

创建认证类,用于认证用户

public class UserDetailsServiceImpl implements UserDetailsService {
	
	@Reference
	private UserService userService;
	
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		//构建角色
		List<GrantedAuthority> authorities=new ArrayList<GrantedAuthority>();
		authorities.add(new SimpleGrantedAuthority("ADMIN"));
		//查询用户
		TbUser tbUser = userService.findOne(username);
		if (tbUser!=null) {
			if (tbUser.getStatus().equals("1")) {
				return new User(username,tbUser.getPassword(), authorities);
			}else{
				return null;
			}
		}else{
			return null;
		}
	}

}

注:本人在实现本案例的时候,SpringBoot已整合Dubbo,所以其中的UserService是操作用户的service,读者可自己实现,通过查询数据库,返回用户对象。@Reference注解为Dubbo中注解,读者可用@Autowired代替。loadUserByUsername方法中的参数为页面表单中输入的参数值,后台拿到username,通过userService查询数据库,即可判断用户是否存在。返回User对象,即可为用户授权,其中的authorities为用户的角色列表,这个角色列表也可以从数据库中查询出来,具体咋实现,可根据业务进行表设计。

注:SprintBoot2.0.5整合Security时,登录密码需要进行编码,所以在授权时,从数据库中查询的登录密码需要经过编码的,如果不进行编码,需要注入

@Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

返回的User为,对登陆密码进行编码:

return new User(username,bCryptPasswordEncoder.encode(tbUser.getPassword()), authorities);

创建WebSecurityConfigurerAdapter的实现,配置Security

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		//配置用户名及密码及角色
		auth.userDetailsService(userDetailsServiceImpl()).passwordEncoder(bCryptPasswordEncoder());
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		//配置拦截规则----配置访问所有地址均需要ADMIN权限,使用内存用户使用hasAnyRole验证用户角色,使用数据库用户,使用hasAnyAuthority验证用户权限
		http.authorizeRequests().antMatchers("/**").hasAnyAuthority("ADMIN");
		
		//配置登录页面及退出等相关页面
		http.formLogin().loginPage("/login.html")//登录页面
		.usernameParameter("username").passwordParameter("password")//配置用户名密码参数名称
		.loginProcessingUrl("/login")//配置登录请求路径
		.defaultSuccessUrl("/admin/index.html",true)//登录成功跳转,并且始终跳转到/admin/index.html
		.failureUrl("/login.html")//登录失败跳转
		.and().logout().logoutUrl("/logout")//退出登录访问地址
		.logoutSuccessUrl("/login.html")//退出成功后访问页面
		.and().csrf().disable()//配置不进行csrf拦截
		.headers().frameOptions().sameOrigin();//配置可以加载框架页面  如iframe
	
		//自动登录
		http.rememberMe()
		.tokenValiditySeconds(432000);//设置cookie保存时间 单位秒
	}
	
	@Override
    public void configure(WebSecurity web) throws Exception {
        //解决静态资源被拦截的问题
        web.ignoring().antMatchers("/*.html","/css/**","/img/**","/js/**");
    }
	
	
	@Bean
	public BCryptPasswordEncoder bCryptPasswordEncoder() {
		return new BCryptPasswordEncoder();
	}
	
	@Bean
	public UserDetailsServiceImpl userDetailsServiceImpl() {
		return new UserDetailsServiceImpl();
	}
	
}

 

注:网上看到很多博客写到该配置时都会在当前配置的类头上在加一个@Configuration注解,其实是没必要的,查看@EnableWebSecurity注解源码,即可查看到其实已经配置@Configuration注解啦。在当前配置类中使用@Bean注解向IOC容器中加入密码加密组件及我们自己配置的用户认证组件,重写WebSecurityConfigurerAdapter的三个方法,配置自己的登录及拦截规则,具体解释代码中已有注释。

注:Security也可以配置内存中的用户名及密码,当使用内存用户名及密码时,配置拦截规则可以为:http.authorizeRequests().antMatchers("/**").hasRole("ADMIN");

但使用数据库中的用户名及密码通过GrantedAuthority设置角色时,配置拦截规则为:

http.authorizeRequests().antMatchers("/**").hasAnyAuthority("ADMIN");

这是一个坑,使用错误就会一直提示没有权限

编写登录页面login.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form id="myForm" action="/login" method="post">
		<input name="username" type="text" placeholder="邮箱/用户名/手机号"><br/>
		<input name="password" type="password" placeholder="请输入密码"><br/>
		<input name="remember-me" type="checkbox">自动登录<br/>
		<input type="submit" value="登陆">
	</form>
</body>
</html>

注:登录方式为post提交,提交地址为/login

编写/admin/index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	登陆成功<a href="/logout">退出登陆</a>
</body>
</html>

到此,SpringBoot整合Security就完成了,水平有限,如有错误,希望留言修正。

 

猜你喜欢

转载自blog.csdn.net/qq_36625757/article/details/83351810
今日推荐