我们已经掌握了权限管理理论,核心就是用户认证和用户授权。那么我们就来学习springsecurity如何解决这两个问题。

springboot数据访问控制权限 springboot 权限_xml

springboot整合springsecurity比较简单,pom中引入直接使用starter相关的jar。

<!-- spring boot security -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
			<version>1.5.4.RELEASE</version>
		</dependency>
		<!-- 让html中能够使用security的标签 xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4" -->
		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-springsecurity4</artifactId>
			<version>2.1.3.RELEASE</version>
		</dependency>

这里重点注意一下springboot的版本号【1.5.4.RELEASE】;
因为我们还引用了thymeleaf-extras-springsecurity4版本【2.1.3.RELEASE】,用于页面权限管理
这是为了后面在html使用中springsecurity4的标签,如果版本冲突就无法生效

使用springsecurity只需要两步就可以了,
第一步,创建用户信息服务;

@Service
public class WebUserDetailsService implements UserDetailsService {

	private final static Logger logger = LoggerFactory.getLogger(WebUserDetailsService.class); 
	
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {
		
		logger.info("用户登录:"+username);
		
		/**
		 * 这里直接创建UserDetails对象,
		 * 简化了用户信息数据库查询的逻辑,
		 * 让springsecurity研究更加专注框架本身
		 */
		if (StringUtils.isEmpty(username)) {
			return null;
		}else if("admin".equals(username) ){
			//admin用户,密码123456
			//roles("ADMIN","NORMAL"),角色不能加"ROLE_",security已经强制了。
			UserDetails user = User.withUsername(username).password("123456").roles("ADMIN","NORMAL").build();
	        return user;
		}else{
			//普通用户,密码为123
			UserDetails user = User.withUsername(username).password("123").roles("NORMAL").build();
	        return user;
		}

	}

}

重点注意:
这里直接返回了UserDetails 对象,没有查询数据库;
另外管理员和普通用户密码不一样;
roles角色字符串,已经不能用“ROLE_”前缀了。
最后UserDetailsService服务直接注册到spring中@Service就可以了
security会自动识别到自定义的服务

第二步,配置security的拦截信息;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	
	protected void configure(HttpSecurity http) throws Exception {
	    http
	    		//URL权限控制,优先级从上到下
	    		.authorizeRequests()
		        .antMatchers("/easyui/**","/**/*.js","/**/*.css","/**/*.png").permitAll()      //无需授权的资源     
	            .antMatchers("/test/admin/**").hasRole("ADMIN")		//指定角色授权,直接使用hasRole方法                                    
	            .antMatchers("/test/web/**").access("hasRole('ADMIN') or hasRole('NORMAL')")  //指定角色授权,使用access方法      
	            .anyRequest().authenticated()	//默认所有资源都需要授权
	            
	           //自定义登录逻辑
		        .and()
		        .formLogin()
	            .loginPage("/login.html") 	//自定义登录页面
	            .loginProcessingUrl("/login")  //登录请求,默认url是/login
//	            .successForwardUrl("successForwardUrl")	//登录成功跳转地址
//	            .failureForwardUrl("failureForwardUrl")		//登录失败跳转地址
	            .permitAll()     //允许登录相关的请求,所有人可以访问
		            
	            //自定义注销逻辑
		    	.and()
		    	.logout()
//		        .logoutUrl("/my/logout")     //默认url是/logout                                           
	            .logoutSuccessUrl("/")      //注销成功后,跳转指定页面                                     
	            .invalidateHttpSession(true)    
	            
	            //关闭额外安全机制
	            .and()
	            .csrf().disable()//关闭csrf防跨站请求伪造机制,不然ajax访问无法使用
	           .headers().frameOptions().disable();//关闭iframe防攻击机制,不然iframe无法调用URL
	}
	
}

重点注意:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
三个注解,后面用到方法限制权限,需要EnableGlobalMethodSecurity
HttpSecurity 配置大家可以自己看,比较简单,其他的功能也是这么配置,这个是使用security的方法。

security的整合配置就结束了,下面就是案例创建了。
我们自定义了登录页面,login.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title> Web Demo</title>
</head>
<body >
<form action="/login" method="post"  >       
		<p th:if="${param.logout}" >已注销</p>
        <p th:if="${param.error}" >有错误,请重试</p>
    <p>
        <label for="username">Username</label>
        <input type="text" id="username" name="username"/>  
    </p>
    <p>
        <label for="password">Password</label>
        <input type="password" id="password" name="password"/>  
    </p>
    <button type="submit" class="btn">Log in</button>
</form>
</body>
</html>

创建请求案例,TestController

@Controller()
public class TestController {
	
	@RequestMapping("/login.html")
	public String loginPage() {
		return "auth/login";
	}
	
	/*================================
	 * 测试springsecurity的权限控制
	 * ================================
	 */
	
	/**
	 * 正则表达式配置拦截器权限控制,.antMatchers("/test/admin/**").hasRole("ADMIN")	
	 */
	@RequestMapping("/admin/hello")
	@ResponseBody  
	public String adminHello() {
		return "hello admin!";
	}
	
	/**
	 * 提前配置拦截器权限控制,.antMatchers("/test/web/**").access("hasRole('ADMIN') or hasRole('NORMAL')") 
	 */
	@RequestMapping("/web/{name}")
	@ResponseBody  
	public String web(@PathVariable String name) {
		return "hello web "+name+"!";
	}
	
	/**
	 * 方法名称上使用注解控制权限,@PreAuthorize("hasRole('ADMIN')")
	 */
	@RequestMapping("/only/admin")
	@ResponseBody  
	@PreAuthorize("hasRole('ADMIN')")
	public String authOnly() {
		return "hello auth!";
	}
	
	/**
	 * html页面使用权限控制标签,<div sec:authorize="hasRole('ADMIN')">
	 */
	@RequestMapping("/auth")
	public String auth() {
		return "auth/success";
	}
	
	
}

最后是html使用security的标签页面,success.html

<!DOCTYPE html>
<html 
	  xmlns:th="http://www.thymeleaf.org" 
	  xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta charset="UTF-8" />
<title>Security Demo</title>
</head>
<body th:inline="text">

	
	<div sec:authorize="isAuthenticated()">
		<!-- 用户认证通过才能才显示 -->
		<p>
			用户名:<span sec:authentication="name"></span>
		</p>
		<p>
			权限:<span sec:authentication="principal.authorities"></span>
		</p>
	</div>

	<div sec:authorize="hasRole('ADMIN')">
	<!-- 用户角色为“ADMIN”才显示 -->
		<p>【管理员】才能看见的内容</p>
	</div>
	<div sec:authorize="hasRole('NORMAL')">
	<!-- 用户角色为“NORMAL”才显示 -->
		<p>【普通用户】才能看到的内容</p>
	</div>

	<form th:action="@{/logout}" method="post">
		<input type="submit"  value="注销" />
	</form>

</body>
</html>

重点注意:
xmlns:sec=“http://www.thymeleaf.org/thymeleaf-extras-springsecurity4
sec:authorize=“hasRole(‘NORMAL’)”
先要添加html的xmlns命名空间信息,然后才能使用sec标签

看看页面访问效果吧。

springboot数据访问控制权限 springboot 权限_spring_02


springboot数据访问控制权限 springboot 权限_xml_03

回顾总结,springboot整合springsecurity,只需要自定义UserDetailsService,然后在WebSecurityConfigurerAdapter中配置权限控制,就完成了。使用权限方式有4种,咱们这里用到了正则表达式、方法注解、html标签。配置信息有请求控制、用户登录、用户注销。

常用注解

@PreAuthorize, 在方法调用前,基于表达式计算结果来限制方法访问
@PostAuthorize,允许方法调用,但是如果表达式结果为fasle则抛出异常
@PostFilter,允许方法调用,但必须按表达式过滤方法结果。
@PreFilter,允许方法调用,但必须在进入方法前过滤输入值
@EnableWebSecurity,打开安全验证服务
@EnableGlobalMethodSecurity,全局方法安全
@Order,多个拦截器时,添加拦截优先级
@Secured,控制方法访问

补充下springsecurity常用的权限判定方法。

springboot数据访问控制权限 springboot 权限_spring_04