iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >如何解决Spring Security的权限配置不生效问题
  • 113
分享到

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

2023-06-29 11:06:07 113人浏览 薄情痞子
摘要

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

这篇文章主要介绍如何解决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()方法

  • invacation 调用 ,求助

  • metadata 元数据

@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的权限配置不生效问题”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网精选频道!

--结束END--

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

本文链接: https://www.lsjlt.com/news/324616.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++ 生态系统中流行库和框架的贡献指南
    作为 c++++ 开发人员,通过遵循以下步骤即可为流行库和框架做出贡献:选择一个项目并熟悉其代码库。在 issue 跟踪器中寻找适合初学者的问题。创建一个新分支,实现修复并添加测试。提交...
    99+
    2024-05-15
    框架 c++ 流行库 git
  • C++ 生态系统中流行库和框架的社区支持情况
    c++++生态系统中流行库和框架的社区支持情况:boost:活跃的社区提供广泛的文档、教程和讨论区,确保持续的维护和更新。qt:庞大的社区提供丰富的文档、示例和论坛,积极参与开发和维护。...
    99+
    2024-05-15
    生态系统 社区支持 c++ overflow 标准库
  • c++中if elseif使用规则
    c++ 中 if-else if 语句的使用规则为:语法:if (条件1) { // 执行代码块 1} else if (条件 2) { // 执行代码块 2}// ...else ...
    99+
    2024-05-15
    c++
  • c++中的继承怎么写
    继承是一种允许类从现有类派生并访问其成员的强大机制。在 c++ 中,继承类型包括:单继承:一个子类从一个基类继承。多继承:一个子类从多个基类继承。层次继承:多个子类从同一个基类继承。多层...
    99+
    2024-05-15
    c++
  • c++中如何使用类和对象掌握目标
    在 c++ 中创建类和对象:使用 class 关键字定义类,包含数据成员和方法。使用对象名称和类名称创建对象。访问权限包括:公有、受保护和私有。数据成员是类的变量,每个对象拥有自己的副本...
    99+
    2024-05-15
    c++
  • c++中优先级是什么意思
    c++ 中的优先级规则:优先级高的操作符先执行,相同优先级的从左到右执行,括号可改变执行顺序。操作符优先级表包含从最高到最低的优先级列表,其中赋值运算符具有最低优先级。通过了解优先级,可...
    99+
    2024-05-15
    c++
  • c++中a+是什么意思
    c++ 中的 a+ 运算符表示自增运算符,用于将变量递增 1 并将结果存储在同一变量中。语法为 a++,用法包括循环和计数器。它可与后置递增运算符 ++a 交换使用,后者在表达式求值后递...
    99+
    2024-05-15
    c++
  • c++中a.b什么意思
    c++kquote>“a.b”表示对象“a”的成员“b”,用于访问对象成员,可用“对象名.成员名”的语法。它还可以用于访问嵌套成员,如“对象名.嵌套成员名.成员名”的语法。 c++...
    99+
    2024-05-15
    c++
  • C++ 并发编程库的优缺点
    c++++ 提供了多种并发编程库,满足不同场景下的需求。线程库 (std::thread) 易于使用但开销大;异步库 (std::async) 可异步执行任务,但 api 复杂;协程库 ...
    99+
    2024-05-15
    c++ 并发编程
  • 如何在 Golang 中备份数据库?
    在 golang 中备份数据库对于保护数据至关重要。可以使用标准库中的 database/sql 包,或第三方包如 github.com/go-sql-driver/mysql。具体步骤...
    99+
    2024-05-15
    golang 数据库备份 mysql git 标准库
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作