文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2023-06-29 11:45

关注

这篇文章主要介绍如何解决Spring Security的权限配置不生效问题,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

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() //必须授权才能范围

用户携带权限

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

2、解决办法

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

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

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

Spring Security动态配置权限

导入依赖

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-security</artifactId></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId></dependency><dependency>    <groupId>org.mybatis.spring.boot</groupId>    <artifactId>mybatis-spring-boot-starter</artifactId>    <version>2.1.3</version></dependency><dependency>    <groupId>com.alibaba</groupId>    <artifactId>druid-spring-boot-starter</artifactId>    <version>1.1.22</version></dependency><dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <scope>runtime</scope>    <version>5.1.46</version></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-test</artifactId>    <scope>test</scope>    <exclusions>        <exclusion>            <groupId>org.junit.vintage</groupId>            <artifactId>junit-vintage-engine</artifactId>        </exclusion>    </exclusions></dependency><dependency>    <groupId>org.springframework.security</groupId>    <artifactId>spring-security-test</artifactId>    <scope>test</scope></dependency>

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

相关配置

application.properties

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/javaboy?useUnicode=true&characterEncoding=utf8&serverTimezone=UTCspring.datasource.username=rootspring.datasource.password=rootspring.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<Role> roleList;    @Override    public Collection<? extends GrantedAuthority> getAuthorities() {        List<SimpleGrantedAuthority> 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<Role> getRoleList() {        return roleList;    }    public void setRoleList(List<Role> 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<Role> roles;...}

创建UserMapper类&&UserMapper.xml

和MenuMapper类&&MenuMapperxml

UserMapper

@Mapperpublic interface UserMapper {    User getUserByName(String name);    List<Role> getRoleById(Integer id);}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.qwl.mysecuritydy.mapper.UserMapper">    <select id="getUserByName" resultType="com.qwl.mysecuritydy.bean.User">        select * from user where username= #{name}    </select>    <select id="getRoleById" resultType="com.qwl.mysecuritydy.bean.Role">        select * from role where id in (select rid from user_role where uid = #{uid})    </select></mapper>

MenuMapper

@Mapperpublic interface MenuMapper {    List<Menu> getMenus();}

MemuMapper.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.qwl.mysecuritydy.mapper.MenuMapper">    <resultMap id="menus_map" type="com.qwl.mysecuritydy.bean.Menu">        <id property="id" column="id"/>        <result property="pattern" column="pattern"/>        <collection property="roles" ofType="com.qwl.mysecuritydy.bean.Role">            <id property="id" column="rid"/>            <result property="name" column="rname"/>            <result property="nameZh" column="rnameZh"/>        </collection>    </resultMap>    <select id="getMenus" resultMap="menus_map">        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    </select></mapper>

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

创建UserService MenuService

创建UserService实现UserServiceDetails接口

@Servicepublic 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

@Servicepublic class MenuService {    @Autowired    private MenuMapper menuMapper;    public List<Menu> getMenus() {return menuMapper.getMenus();}}

创建CustomFilterInvocationSecurityMetadataSource

实现接口FilterInvocationSecurityMetadataSource

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

supports返回值设成true表示支持

重写getAttributes()方法

@Componentpublic 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<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {        //获取当前用户请求的url        String requestUrl=((FilterInvocation) object).getRequestUrl();        //数据库中查询出所有的路径        List<Menu> menus  =menuService.getMenus();        for (Menu menu : menus) {            //判断用户请求的url和数据库的url是否能匹配的上            if (pathMatcher.match(menu.getPattern(), requestUrl)) {                List<Role> 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<ConfigAttribute> getAllConfigAttributes() {        return null;    }}

创建CustomAccessDecisionManager

实现AccessDecisionManager接口 access 通道

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

将两个supports()都设置成true

重写decide()方法

@Componentpublic class CustomAccessDecisionManager implements AccessDecisionManager {    @Override    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> 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(">>>>>>>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

@Configurationpublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {    @Autowired    private 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<FilterSecurityInterceptor>() {                    @Override                    public <O extends FilterSecurityInterceptor> O postProcess(O object){                        object.setSecurityMetadataSource(customFilterInvocationSecurityMetadataSource);                        object.setAccessDecisionManager(customAccessDecisionManager);                        return object;                    }                })                .and()                .formLogin()                .permitAll()                .and()                .csrf().disable();    }}

Controller 

@RestControllerpublic 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";    }}

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

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

以上是“如何解决Spring Security的权限配置不生效问题”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网行业资讯频道!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯