解决Spring Security的权限配置不生效问题

网友投稿 571 2022-08-21


解决Spring Security的权限配置不生效问题

目录SpringSecurity权限配置不生效1、不生效的例子 2、解决办法SpringSecurity动态配置权限导入依赖相关配置创建UserMapper类&&UserMapper.xml创建UserServiceMenuService创建CustomFilterInvocationSecurityMetadataSource创建CustomAccessDecisionManager创建WebSecurityConfig配置类

Spring Security权限配置不生效

在集成Spring Security做接口权限配置时,在给用户配置的权限后,还是一直显示“无权限”或者"权限不足"。

1、不生效的例子

接口

@RequestMapping("/admin")

@ResponseBody

@PreAuthorize("hasRole('ADMIN')")

public String printAdmin() {

return "如果你看见这句话,说明你有ROLE_ADMIN角色";

}

@RequestMapping("/user")

@ResponseBody

@PreAuthorize("hasRole('USER')")

public String printUser() {

return "如果你看见这句话,说明你有ROLE_USER角色";

}

SecurityConfig

.and()

.authorizeRequests()

.antMatchers("/user").hasAnyRole("USER")

.antMatchers("/admin").hasAnyRole("ADMIN")

.anyRequest().authenticated() //必须授权才能范围

用户携带权限

2、解决办法

经测试,只有用户携带权限的字段为 “ROLE_” + 接口/配置 中的权限字段,才能控制生效,举例:

将上面的用户携带权限改为

Spring Security动态配置权限

导入依赖

org.springframework.boot

spring-boot-starter-security

org.springframework.boot

spring-boot-starter-web

org.mybatis.spring.boot

mybatis-spring-boot-starter

2.1.3

com.alibaba

druid-spring-boot-starter

1.1.22

mysql

mysql-connector-java

runtime

5.1.46

org.springframework.boot

spring-boot-starter-test

test

org.junit.vintage

junit-vintage-engine

org.springframework.security

spring-security-test

test

相关配置

application.properties

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/javaboy?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC

spring.datasource.username=root

spring.datasource.password=root

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

实体类User,Role,Menu

这里要实现UserDetails接口,这个接口好比一个规范。防止开发者定义的密码变量名各不相同,从而导致springSecurity不知道哪个方法是你的密码

public class User implements UserDetails {

private Integer id;

private String username;

private String password;

private Boolean enabled;

private Boolean locked;

private List roleList;

@Override

public Collection extends GrantedAuthority> getAuthorities() {

List authorities = new ArrayList<>();

for (Role role : roleList) {

authorities.add(new SimpleGrantedAuthority(role.getName()));

}

return authorities;

}

@Override

public String getPassword() {

return password;

}

@Override

public String getUsername() {

return username;

}

@Override

public boolean isAccountNonExpired() {

return true;

}

@Override

public boolean isAccountNonLocked() {

return !locked;

}

@Override

public boolean isCredentialsNonExpired() {

return true;

}

@Override

public boolean isEnabled() {

return enabled;

}

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public void setUsername(String username) {

this.username = username;

}

public void setPassword(String password) {

this.password = password;

}

public Boolean getEnabled() {

return enabled;

}

public void setEnabled(Boolean enabled) {

this.enabled = enabled;

}

public Boolean getLocked() {

return locked;

}

public void setLocked(Boolean locked) {

this.locked = locked;

}

public List getRoleList() {

return roleList;

}

public void setRoleList(List roleList) {

this.roleList = roleList;

}

}

public class Role {

private Integer id;

private String name;

private String nameZh;

...

}

public class Menu {

private Integer id;

private String pattern;

private List roles;

...

}

创建UserMapper类&&UserMapper.xml

和MenuMapper类&&MenuMapperxml

UserMapper

@Mapper

public interface UserMapper {

User getUserByName(String name);

List getRoleById(Integer id);

}

UserMapper.xml

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

select * from user where username= #{name}

select * from role where id in (select rid from user_role where uid = #{uid})

MenuMapper

@Mapper

public interface MenuMapper {

List

}

MemuMapper.xml

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

select m.*,r.id as rid,r.name as rname,r.nameZh as rnameZh from menu_role mr left join

menu m on mr.mid = m.id left join role r on mr.rid = r.id

创建UserService MenuService

创建UserService实现UserServiceDetails接口

@Service

public class UserService implements UserDetailsService {

@Autowired

private UserMapper userMapper;

@Override

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

User user = userMapper.getUserByName(username);

if(user ==null){

throw new UsernameNotFoundException("用户名不存在");

}

user.setRoleList(userMapper.getRoleById(user.getId()));

return user;

}

}

创建MenuService

@Service

public class MenuService {

@Autowired

private MenuMapper menuMapper;

public List

}

创建CustomFilterInvocationSecurityMetadataSource

实现接口FilterInvocationSecurityMetadataSource

注:加@comppent注解,把自定义类注册成spring组件

supports返回值设成true表示支持

重写getAttributes()方法

invacation 调用 ,求助metadata 元数据

@Component

public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

//ant风格的路径匹配器

AntPathMatcher pathMatcher = new AntPathMatcher();

@Autowired

private MenuService menuService;

//supports返回值设成true表示支持

@Override

public boolean supports(Class> aClass) {

return true;

}

@Override

public Collection getAttributes(Object object) throws IllegalArgumentException {

//获取当前用户请求的url

String requestUrl=((FilterInvocation) object).getRequestUrl();

//数据库中查询出所有的路径

List

for (Menu menu : menus) {

//判断用户请求的url和数据库的url是否能匹配的上

if (pathMatcher.match(menu.getPattern(), requestUrl)) {

List roles =menu.getRoles();

String[] roleStr = new String[roles.size()];

for (int i = 0; i < roles.size(); i++) {

roleStr[i]=roles.get(i).getName();

}

//将筛选的url路径所具备的角色返回回去

return SecurityConfig.createList(roleStr);

}

}

//如果没有匹配上就返回一个默认的角色,作用好比作一个标记

return SecurityConfig.createList("ROLE_def");

}

@Override

public Collection getAllConfigAttributes() {

return null;

}

}

创建CustomAccessDecisionManager

实现AccessDecisionManager接口 access 通道

注:加@comppent注解,把自定义类注册成spring组件

将两个supports()都设置成true

重写decide()方法

@Component

public class CustomAccessDecisionManager implements AccessDecisionManager {

@Override

public void decide(Authentication authentication, Object o, Collection collection) throws AccessDeniedException, InsufficientAuthenticationException {

//configattributes里存放着CustomFilterInvocationSecurityMetadataSource过滤出来的角色

for (ConfigAttribute configAttribute : collection) {

//如果你请求的url在数据库中不具备角色

if ("ROLE_def".equals(configAttribute.getAttribute())) {

//在判断是不是匿名用户(也就是未登录)

if (authentication instanceof AnonymousAuthenticationToken) {

System.out.println(">>>>>>>>>>>>>>>>匿名用户>>>>>>>>>>>>>>");

throw new AccessDeniedException("权限不足,无法访问");

}else{

//这里面就是已经登录的其他类型用户,直接放行

System.out.println(">>>>>>>>>>>其他类型用户>>>>>>>>>>>");

return;

}

}

//如果你访问的路径在数据库中具有角色就会来到这里

//Autherntication这里面存放着登录后的用户所有信息

Collection extends GrantedAuthority> authorities = authentication.getAuthorities();

for (GrantedAuthority authority : authorities) {

System.out.println(">>>>>>>authority(账户所拥有的权限):"+authority.getAuthority());

System.out.println(">>>>qiUOsZmvE>>>configAttribute(路径需要的角色):"+configAttribute.getAttribute());

//路径需要的角色和账户所拥有的角色作比较

if (authority.getAuthority().equals(configAttribute.getAttribute())) {

System.out.println(">>>>>>>>>>>>>>>>>>进来>>>>>>>>>>>>>>>>>");

return;

}

}

}

}

@Override

public boolean supports(ConfigAttribute configAttribute) {

return true;

}

@Override

public boolean supports(Class> aClass) {

return true;

}

}

创建WebSecurityConfig配置类

WebSecurityConfig实现WebSecurityConfigurerAdapter

注入一会所需要的类

SpringSecurity5.0之后必须密码加密

将数据库查出的账户密码交给SpringSecurity去判断

配置HttpSecurity

@Configuration

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired

qiUOsZmvEprivate UserService userService;

@Autowired

private CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource;

@Autowired

private CustomAccessDecisionManager customAccessDecisionManager;

//springSecutity5.0之后必密码加密

@Bean

PasswordEncoder passwordEncoder(){

return new BCryptPasswordEncoder();

}

//将数据库查出的账户密码交给springsecurity去判断

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

auth.userDetailsService(userService);

}

//配置HttpSecurity

@Override

protected void configure(HttpSecurity http) throws Exception {

http.authorizeRequests()

.withObjectPostProcessor(new ObjectPostProcessor() {

@Override

public O postProcess(O object){

object.setSecurityMetadataSource(customFilterInvocationSecurityMetadataSource);

object.setAccessDecisionManager(customAccessDecisionManager);

return object;

}

})

.and()

.formLogin()

.permitAll()

.and()

.csrf().disable();

}

}

Controller

@RestController

public class HelloController {

@GetMapping("/hello")

public String hello(){

return "hello";

}

@GetMapping("/dba/hello")

public String dba(){

return "hello dba";

}

@GetMapping("/admin/hello")

public String admin(){

return "hello admin";

}

@GetMapping("/user/hello")

public String user(){

return "hello user";

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java十分钟精通Lambda表达式
下一篇:使用SpringSecurity设置角色和权限的注意点
相关文章

 发表评论

暂时没有评论,来抢沙发吧~