上一篇博客 sPRingBoot+springSecurity 数据库动态管理用户、角色、权限(二) 只是实现了用户、角色、权限的动态管理,但是其权限管理是有缺陷的,他不支持restful风格的接口权限管理,因为他无法区分客户端的请求方式。
本片博客是为了弥补此缺陷的,本篇博客将在 springBoot+springSecurity 数据库动态管理用户、角色、权限(二) 的基础上进行修改使其支持 restful 风格的接口的权限管理。
本文目录: 1. 分析工作量 2. 修改代码 3. 准备数据 4. 测试
首先分析一下工作量吧,因为要支持 restful 风格的接口,那么我们在判断用户是不是有权限访问的时候不仅要判断 url 还要判断 请求方式。 所以我门需要修改数据库表,因为我门的权限表还没有method 字段。
由于要判断 url 和 method 所以要在CustomUserService 类的 loadUserByUsername 方法中要添加 权限的 url 和 method 。但是SimpleGrantedAuthority 只支持传入一个参数。 所以我门考虑要再写一个类 实现 GrantedAuthority 接口,并在构造函数中传入两个参数。嘻嘻。
由于我们不仅要判断url 还要 判断请求方法,所以当然要修改 MyaccessDecisionManager 的decide 方法的内容了。因为:decide 方法是判定是否拥有权限的决策方法 ,三个参数的含义分别为: //authentication 是释CustomUserService中循环添加到 GrantedAuthority 对象中的权限信息集合. //object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest(); //configAttributes 为MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。当然在 修改一下 MyInvocationSecurityMetadataSourceService 的getAttributes 方法。//此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。 //因为我不想每一次来了请求,都先要匹配一下权限表中的信息是不是包含此url,我准备直接拦截,不管请求的url 是什么都直接拦截,然后在MyAccessDecisionManager的decide 方法中做 拦截还是放行的决策。5.关闭csrf 6.添加restful 风格的接口
好了分析完了,接下来就是编码了。
添加method 字段,当然Permission 的java bean 中 也要添加此属性和其get set方法。
新建java类MyGrantedAuthority 实现 GrantedAuthority 接口
package com.us.example.service;import org.springframework.security.core.GrantedAuthority;/** * Created by yangyibo on 17/2/15. */public class MyGrantedAuthority implements GrantedAuthority { private String url; private String method; public String getPermissionUrl() { return url; } public void setPermissionUrl(String permissionUrl) { this.url = permissionUrl; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public MyGrantedAuthority(String url, String method) { this.url = url; this.method = method; } @Override public String getAuthority() { return this.url + ";" + this.method; }}在CustomUserService 类中使用MyGrantedAuthority
public UserDetails loadUserByUsername(String username) { SysUser user = userDao.findByUserName(username); if (user != null) { List<Permission> permissions = permissionDao.findByAdminUserId(user.getId()); List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); for (Permission permission : permissions) { if (permission != null && permission.getName() != null) { GrantedAuthority grantedAuthority = new MyGrantedAuthority(permission.getUrl(), permission.getMethod()); grantedAuthorities.add(grantedAuthority); } } return new User(user.getUsername(), user.getPassWord(), grantedAuthorities); } else { throw new UsernameNotFoundException("admin: " + username + " do not exist!"); } }关于 什么是csrf 请看我的这篇博客
spring security CSRF 问题
修改 WebSecurityConfig 的configure(HttpSecurity http) 方法 ,添加 .csrf().disable();
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() //任何请求,登录后可以访问 .and() .formLogin() .loginPage("/login") .failureUrl("/login?error") .permitAll() //登录页面用户任意访问 .and() .logout().permitAll(); //注销行为任意访问 http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class) .csrf().disable(); }由于我们是要测试restful 风格的权限,所以我门要有restful 的接口
package com.us.example.controller;import com.us.example.domain.Msg;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;/** * Created by yangyibo on 17/1/18. */@Controllerpublic class HomeController { @RequestMapping("/") public String index(Model model){ Msg msg = new Msg("测试标题","测试内容","欢迎来到HOME页面,您拥有 ROLE_HOME 权限"); model.addAttribute("msg", msg); return "home"; } @RequestMapping("/admin") @ResponseBody public String hello(){ return "hello admin"; } @RequestMapping("/login") public String login(){ return "login"; } @RequestMapping(value = "/user", method = RequestMethod.GET) @ResponseBody public String getList(){ return "hello getList"; } @RequestMapping(value = "/user", method = RequestMethod.POST) @ResponseBody public String save(){ return "hello save"; } @RequestMapping(value = "/user", method = RequestMethod.PUT) @ResponseBody public String update(){ return "hello update"; }}好了编码部分完成了
在数据库中添加测试数据,主要是权限表和权限角色中间表。
结果(角色1 可以访问 /user 下的所有接口, 角色2 只可以访问 /user 下的GET请求)权限表:
权限角色中间表:(此处角色1拥有 权限 6 ,权限6的方法为 ALL 也就是角色6 可以访问所有路径为/user 的接口)
启动项目,然后在postman 中测试, 1. 登录admin 后访问 user 的所有权限,都可以正常访问。
put 方法访问成功 。
登录abel 后访问 user 的所有权限,只有GET 权限可以访问。put 方法访问失败。
半夜码字。。。 如果本文对您有帮助请给个好评,谢谢。
本文源码:https://github.com/527515025/springBoot
参考文献: http://www.cnblogs.com/dongying/p/6106855.html http://www.cnblogs.com/dongying/p/6128268.html
新闻热点
疑难解答