Version: Next
动态加载资源鉴权规则
查看某用户权限的SQL语句
SELECT url
FROM sys_menu m
LEFT JOIN sys_role_menu rm ON m.id = rm.menu_id
LEFT JOIN sys_role r ON r.id = rm.role_id
LEFT JOIN sys_user_role ur ON r.id = ur.role_id
LEFT JOIN sys_user u ON u.id = ur.user_id
WHERE u.username = 'admin'
先把之前写死的规则注释掉
- 首页只要登录了就允许访问
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() //禁用跨站csrf攻击防御,后面的章节会专门讲解
.formLogin()
.loginPage("/login.html")//用户未登录时,访问任何资源都转跳到该路径,即登录页面
.loginProcessingUrl("/login")//登录表单form中action的地址,也就是处理认证请求的路径
.usernameParameter("username")///登录表单form中用户名输入框input的name名,不修改的话默认是username
.passwordParameter("password")//form中密码输入框input的name名,不修改的话默认是password
// .defaultSuccessUrl("/index")//登录认证成功后默认转跳的路径
.successHandler(myAuthenticationSuccessHandler)
.failureHandler(myAuthenticationFaliureHandler)
.and()
.authorizeRequests()
.antMatchers("/login.html", "/login").permitAll()//不需要通过登录验证就可以被访问的资源路径
.antMatchers("/index").authenticated()// 首页只要登录了就可以访问
/* .antMatchers("/biz1", "/biz2") //需要对外暴露的资源路径
.hasAnyAuthority("ROLE_user", "ROLE_admin") //user角色和admin角色都可以访问
// .antMatchers("/syslog", "/sysuser")
// .hasAnyRole("admin") //admin角色可以访问
.antMatchers("/syslog").hasAuthority("/syslog")
.antMatchers("/sysuser").hasAuthority("/sysuser")
.anyRequest().authenticated();*/
;
}
MyRBACService
@Service("rbacService")
public class MyRBACService {
@Resource
MyRBACServiceMapper myRBACServiceMapper;
/**
* 判断某用户是否具有该request资源的访问权限
*/
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
// 获取验证主体,就是MyUserDetails
Object principal = authentication.getPrincipal();
if (principal instanceof UserDetails) {
UserDetails userDetails = ((UserDetails)principal);
List<GrantedAuthority> authorityList =
AuthorityUtils.commaSeparatedStringToAuthorityList(request.getRequestURI());
return userDetails.getAuthorities().contains(authorityList.get(0));
}
return false;
}
}
MyRBACServiceMapper——通过用户名查询用户权限
public interface MyRBACServiceMapper {
@Select("SELECT url\n" +
"FROM sys_menu m\n" +
"LEFT JOIN sys_role_menu rm ON m.id = rm.menu_id\n" +
"LEFT JOIN sys_role r ON r.id = rm.role_id\n" +
"LEFT JOIN sys_user_role ur ON r.id = ur.role_id\n" +
"LEFT JOIN sys_user u ON u.id = ur.user_id\n" +
"WHERE u.username = #{username}")
List<String> findUrlsByUsername(@Param("username") String username);
}
在Config类中,书写权限表达式
- 用
access()
- 参数必须叫
request
和authentication
->access(request, authenticaiton)
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() //禁用跨站csrf攻击防御,后面的章节会专门讲解
.formLogin()
.loginPage("/login.html")//用户未登录时,访问任何资源都转跳到该路径,即登录页面
.loginProcessingUrl("/login")//登录表单form中action的地址,也就是处理认证请求的路径
.usernameParameter("username")///登录表单form中用户名输入框input的name名,不修改的话默认是username
.passwordParameter("password")//form中密码输入框input的name名,不修改的话默认是password
// .defaultSuccessUrl("/index")//登录认证成功后默认转跳的路径
.successHandler(myAuthenticationSuccessHandler)
.failureHandler(myAuthenticationFaliureHandler)
.and()
.authorizeRequests()
.antMatchers("/login.html", "/login").permitAll()//不需要通过登录验证就可以被访问的资源路径
.antMatchers("/index").authenticated()// 首页只要登录了就可以访问
.anyRequest().access("@rbacService.hasPermission(request, authentication)")
/* .antMatchers("/biz1", "/biz2") //需要对外暴露的资源路径
.hasAnyAuthority("ROLE_user", "ROLE_admin") //user角色和admin角色都可以访问
// .antMatchers("/syslog", "/sysuser")
// .hasAnyRole("admin") //admin角色可以访问
.antMatchers("/syslog").hasAuthority("/syslog")
.antMatchers("/sysuser").hasAuthority("/sysuser")
.anyRequest().authenticated();*/
;
}
除了登录页与首页,所有其他的访问必须经过rbacService的hasPermission方法,动态从数据库查询是否有对应访问路径的访问权限
处理Bug
- 登录后直接报403,通过控制台,发现请求地址是
/
,数据库中没配置/
这个权限,也没有在Spring Security中配置/
的权限,所以把/
这个路径加上,并且还要给/
这个路径设置一个Controller
.antMatchers("/login.html", "/login").permitAll()//不需要通过登录验证就可以被访问的资源路径
.antMatchers("/index", "/").authenticated()// 首页只要登录了就可以访问
@GetMapping({"/index", "/"})
public String index() {
return "index";
}
测试
用
admin
登录,发现可以看系统日志和用户管理,不能访问业务1和业务2
- 直接修改数据库,给admin角色添加业务1和业务2的权限
INSERT INTO sys_role_menu VALUES (NULL, 1, 4)
INSERT INTO sys_role_menu VALUES (NULL, 1, 5)
- 无序重启项目,直接访问业务1业务2,现在能访问了