spring security角色(role)和权限(authorities)的区别

实验一:只授予权限

实现配置类

只授予一个权限,关键代码:

.authorities("mng_user");

url需要mng_user权限才能访问,关键代码:

.antMatchers("/user/**").hasAuthority("mng_user")

完整代码如下:

package top.malaoshi.stdsecurity.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig2 extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//      将用户名、密码放入内存中
        auth.inMemoryAuthentication()
//                .passwordEncoder(NoOpPasswordEncoder.getInstance())//密码为明文
                .withUser("admin")//用户名
                .password("{noop}123456")//{noop}表示密码为明文,与上面是同一个含义
//                .roles("ADMIN");//admin角色,角色一般全大写
                .authorities("mng_user");//管理user权限,权限一般小写
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**","/js/**","/img/**");//绕开所有的filter,直接跳过验证
    }

    //    安全拦截机制
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()//禁用csrf
//                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
//                .and()

                .authorizeRequests()//url权限配置
//                .antMatchers("/index.html").permitAll() // 匹配这些路径可以所有人访问
//                .antMatchers("/user/**").hasRole("ADMIN")
                .antMatchers("/user/**").hasAuthority("mng_user")
                .anyRequest().authenticated()
                .and()

                //login部分
                .formLogin()
                .loginPage("/login.html")//指定登录页面。所有url前面必须写/,否则报错 'xxx' is not a valid forward URL
                .loginProcessingUrl("/login")//security提供的处理登录url,默认是/login
//                .successForwardUrl("/index.html")//登录成功后跳转的页面,需要额外处理才能使用,否则页面会提示错误
                .defaultSuccessUrl("/index.html")//登录成功后重定向的页面
                .failureUrl("/login_fails.html")//登录失败跳转的页面
//                .failureForwardUrl("/login_fails.html")//登录失败不会转发
                .permitAll()//让login部分的url可以任意访问
//
//                //logout部分
                .and()
                .logout()
                .logoutSuccessUrl("/login.html")//退出成功访问的页面
                .invalidateHttpSession(true)//清空session
                .permitAll();//让logout部分的url可以任意访问

    }

}

实现Controller

package top.malaoshi.stdsecurity.controller;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping(value = "/user")
    public String getUser(){
        User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        System.out.println(user);
        return "success";
    }
}

测试

登录后访问Controller,打印结果如下:

org.springframework.security.core.userdetails.User@586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: mng_user

通过Granted Authorities: mng_user可以看出有mng_user权限

实验二:只授予角色

实现配置类

只授予ADMIN角色,关键代码:

.roles("ADMIN")//admin角色,角色一般全大写

url只有ADMIN角色才能访问,关键代码:

.antMatchers("/user/**").hasRole("ADMIN")

完整代码:

package top.malaoshi.stdsecurity.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig2 extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//      将用户名、密码放入内存中
        auth.inMemoryAuthentication()
//                .passwordEncoder(NoOpPasswordEncoder.getInstance())//密码为明文
                .withUser("admin")//用户名
                .password("{noop}123456")//{noop}表示密码为明文,与上面是同一个含义
                .roles("ADMIN");//admin角色,角色一般全大写
                //.authorities("mng_user");//管理user权限,权限一般小写
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**","/js/**","/img/**");//绕开所有的filter,直接跳过验证
    }

    //    安全拦截机制
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()//禁用csrf
//                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
//                .and()

                .authorizeRequests()//url权限配置
//                .antMatchers("/index.html").permitAll() // 匹配这些路径可以所有人访问
                .antMatchers("/user/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()

                //login部分
                .formLogin()
                .loginPage("/login.html")//指定登录页面。所有url前面必须写/,否则报错 'xxx' is not a valid forward URL
                .loginProcessingUrl("/login")//security提供的处理登录url,默认是/login
//                .successForwardUrl("/index.html")//登录成功后跳转的页面,需要额外处理才能使用,否则页面会提示错误
                .defaultSuccessUrl("/index.html")//登录成功后重定向的页面
//                .failureForwardUrl("/login_fails.html")//登录失败跳转的页面
                .permitAll()//让login部分的url可以任意访问
//
//                //logout部分
                .and()
                .logout()
                .logoutSuccessUrl("/login.html")//退出成功访问的页面
                .invalidateHttpSession(true)//清空session
                .permitAll();//让logout部分的url可以任意访问

    }

}

实现Controller

同上,不变

测试

登录后访问Controller,打印结果如下:

org.springframework.security.core.userdetails.User@586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN

没有角色ADMIN,只有权限Granted Authorities: ROLE_ADMIN,说明在spring security中,授予的角色,是在前面加上前缀ROLE_,然后放入到 权限 中

原因

执行.roles("ADMIN");,调用了org.springframework.security.core.userdetails.User类的下面方法:

public User.UserBuilder roles(String... roles) {
            List<GrantedAuthority> authorities = new ArrayList(roles.length);
            String[] var3 = roles;
            int var4 = roles.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                String role = var3[var5];
                Assert.isTrue(!role.startsWith("ROLE_"), () -> {
                    return role + " cannot start with ROLE_ (it is automatically added)";
                });
                authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
            }

            return this.authorities((Collection)authorities);
        }

通过authorities.add(new SimpleGrantedAuthority("ROLE_" + role));可以看出加上了前缀ROLE_

结论

在spring security中,只有权限,没有角色,所谓的角色,是在前面加上前缀ROLE_,然后放入到 权限 中

判断角色时:.hasRole("ADMIN"),前面不需要加ROLE_

总结

在开发中,如果有角色和权限概念,推荐调用.authorities("mng_user","ROLE_ADMIN");,角色全大写,有前缀:ROLE_

千万不要调用下面代码:

.roles("ADMIN")//admin角色,角色一般全大写
.authorities("mng_user");//管理user权限,权限一般小写

后一行代码会覆盖前一行,详见:
https://www.malaoshi.top/show_1EF60Rbhbjun.html


原文出处:/show_1EF60RQYLTKO.html