目录
一.spring security控制权限
二:后端验证
1.验证流程
2.配置
(1)配置自定义角色权限验证
(2)在config中声明改配置
(3).controller中配置权限
(4)注意点
(5)说明
三:权限控制按钮权限的显示
1.引入依赖
2.页面引入与控制
3.使用标签
4.修改登录方法
security的核心功能就是控制权限。这里,我们通过以下几个方面来说明:
(1)数据库动态配置权限
(2)前端页面控制(控制按钮或者菜单是否显示)
(3)后端验证(验证某一个请求是否合法)
在security中,权限的验证是由PermissionEvaluator来实现的,这里我们需要自定义并集成
package com.config.Seurity.permission;
import java.io.Serializable;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import com.config.Seurity.util.UserUtil;
import com.moudle.system.model.Menu;
import com.moudle.system.service.MenuService;
/**
*
* ClassName: 自定义URL拦截
* Function: 一句话描述功能.
* auth: monxz
* date: 2019年8月29日 下午7:23:44
*
*
*/
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator{
@Autowired
private MenuService menuService;
/**
* 我的url和权限全部放在菜单表中了
* TODO 注意这里,我们这里直接加载菜单中URL以及权限,是应为在MenuService中自动过滤掉了相应权限的路径了
* @see
*/
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
if(UserUtil.currentUser().getRole().getRoleRange() == 0) {
return true;
}
List
package com.config.Seurity.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
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.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import com.config.Seurity.hander.AjaxSuccessHander;
import com.config.Seurity.hander.AjaxfailHander;
import com.config.Seurity.permission.CustomPermissionEvaluator;
import com.config.Seurity.pwdEnder.MyPasswordEncoder;
import com.config.Seurity.service.LoginService;
import lombok.extern.slf4j.Slf4j;
/**
* spring security的配置
* ClassName: SecurityConfig
* Function: 一句话描述功能.
* auth: monxz
* date: 2019年8月28日 上午10:04:50
*
*
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private LoginService loginService;
@Autowired
private DataSource dataSource;
// 注入自定义url和权限验证器
@Bean
public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() {
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(new CustomPermissionEvaluator());
return handler;
}
//记住我功能的Token存储在数据库中
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
// 配置数据源
jdbcTokenRepository.setDataSource(dataSource);
// 第一次启动的时候自动建表(可以不用这句话,自己手动建表,源码中有语句的)
// jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
//登录执行的逻辑
@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(loginService).passwordEncoder(new MyPasswordEncoder());
}
//配置信息
@Override
protected void configure(HttpSecurity http) throws Exception {
String[] allowedUrl= {"/api/**"};
//配置访问权限
http.authorizeRequests()
//允许匿名访问(如api)
.antMatchers(allowedUrl)
.permitAll()
//其他地址的访问均需验证权限
.anyRequest()
.authenticated();
//配置登录以及成功失败的处理方式
http.formLogin()
//指定登录页是"/view/login"
.loginPage("/view/login").permitAll() //
//ajax方式登录
.successHandler(new AjaxSuccessHander())
.failureHandler(new AjaxfailHander())
.loginProcessingUrl("/login")
.usernameParameter("username") //ajax请求必须的
.passwordParameter("password");
//form表单登录
// .defaultSuccessUrl("/view/index") //登录成功后默认跳转到路径"
//注销 ,直接访问 ip:port/logout
http .logout()
.logoutSuccessUrl("/view/login") //退出登录后跳转到登录主界面"
.deleteCookies() //有记住我功能,删除cookie
.permitAll();
//记住我
http.rememberMe()
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(60);
//跨域以及其他的一些配置
http .csrf()
.disable() // 关闭CSRF跨域
.headers()
.frameOptions()
.sameOrigin(); // 允许加载frame子菜单
}
//静态资源
@Override
public void configure(WebSecurity web) throws Exception {
String[] allowedRes= {"/static/**","/css/**","/js/**","/my/**","/img/**","/ajax/**","favicon.ico"};
// 设置拦截忽略文件夹,可以对静态资源放行
web.ignoring().antMatchers(allowedRes);
}
}
这里我就举个例子
@PreAuthorize("hasPermission('/user/user/list','user:user:list')")
@RequestMapping(value = {"/list"})
public DataResult list(User user) {
startPage();
PageInfo page=new PageInfo(userService.findList( user));
return DataResult.buildSuccess(page);
}
在我配置用户管理没有权限时,前端/后台请求时这样的,很奇怪即使没有权限你也放回个没有数据吧。
看到后台的结果发现不允许请求是以异常的方式跑出来的。因此我去了项目统一异常处理中看了一下:
原来是我的ajax请求并没有返回前端分页所需的page信息。
在上面我只是对ajax请求做了返回,但是页面的跳转并没有处理,我是这样考虑的,即使你请求到页面,但是页面的各种按钮权限你是没有的。
当前一个用户只有查询用户的权限,但是没有修改用户的权限,这里我们在该用户前端页面就不应该有修改按钮的显示。
html标签控制元素显示:
js控制元素显示
目录
一.spring security控制权限
二:后端验证
1.验证流程
2.配置
(1)配置自定义角色权限验证
(2)在config中声明改配置
(3).controller中配置权限
(4)注意点
(5)说明
三:前端页面权限的显示
1.引入依赖
2.页面引入与控制
3.使用标签
4.修改登录方法
5.在js中获取到权限
该功能依赖于springsecurity.tld的相关jar包,在mavne文件中引入:
注意这里springsecurity5最好和你的项目里的springescurity版本匹配,我这里通过mavne的版本可以看到
注意,我后来测试了sec:authorize="hahsRole('')"有局限性,跟版本有关系,建议换成sec:authorize="hahsAuthory(' ')"
记过多次的测试,发现3步骤只能对于对于 角色 (Role)做控制,而不能针对具体请求具体的权限。这里的加载的是登录时验证的角色,因此修改登录方法,具体到某一个权限()
package com.config.Seurity.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.tomcat.util.security.MD5Encoder;
import org.springframework.beans.factory.annotation.Autowired;
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 com.config.Seurity.model.CurrentUser;
import com.moudle.system.dao.MenuDao;
import com.moudle.system.model.Menu;
import com.moudle.system.service.MenuService;
import com.moudle.user.model.Role;
import com.moudle.user.model.User;
import com.moudle.user.model.UserRole;
import com.moudle.user.service.RoleMenuService;
import com.moudle.user.service.RoleService;
import com.moudle.user.service.UserRoleService;
import com.moudle.user.service.UserService;
import commons.utils.Md5Utils;
/*
* 自定义用户登录授权service
*/
@Service("userDetailsService")
public class LoginService implements UserDetailsService{
@Autowired
private UserService userService;
@Autowired
private MenuDao menuDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List userList = userService.login(username, null);
if (userList == null || userList.isEmpty()) {
throw new UsernameNotFoundException("该用户不存在!");
}
User currentUser=userList.get(0);
//添加权限
List permsList=new ArrayList();
permsList =currentUser.getPerms()==null?
new ArrayList():currentUser.getPerms();
if(currentUser.getRole().getRoleRange() == 0) {
//超级管理员
List
在上面的例子中,我们看到了的是在Html的标签使用Security的,但是如果我们在js中,就比如下面的我使用bootstrap来在js中构建Table,但是当前用户并没有 编辑 权限怎么办啊?我翻阅了很多资料,都没有看到相关的处理
这里我们使用了thyleaf模板渲染页面,也可以使用它去验证权限。
我们看一下做了几个事情?
(1)将当前的js域声明可以使用thymeleaf:
(2)调用后台方法
这里首先去后台声明@Service(“menu”)中的findByPerms()方法
(3)既然第(2)调用了后台方法,那么后台这个方法怎么定义呢?
其实就是后台查询权限的service的实现层(我的权限在菜单中),我在@Service后加了一个("menu")声明罢了,然后在这个类中声明一个前台刚才说明的方法:
其实,看到这里就是用Thymeleaf去查询方法,建议这个方法中的数据直接放入缓存,而不是数据库中,以免增加执行时间。