概述
通过下面实验说明问题
实现配置类
同时授予角色和权限,关键代码:
.roles("ADMIN")//admin角色,角色一般全大写
.authorities("mng_user");//管理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
同上
测试
登录后访问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
原因
执行下面代码时,
.roles("ADMIN")//admin角色,角色一般全大写
.authorities("mng_user");//管理user权限,权限一般小写
后一句的权限把前一句的角色覆盖了
.roles("ADMIN")源码
调用.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);
}
然后调用了下面方法,
public User.UserBuilder authorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = new ArrayList(authorities);
return this;
}
注意: 创建ArrayList并赋给成员变量authorities
.authorities("mng_user")源码
最终调用下面源码:
public User.UserBuilder authorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = new ArrayList(authorities);
return this;
}
和上面是同一个方法,创建ArrayList并赋给成员变量authorities
结论
所以调用下面方法时,后一行代码会覆盖前一行代码
.roles("ADMIN")//admin角色,角色一般全大写
.authorities("mng_user");//管理user权限,权限一般小写
总结
在开发中,如果有角色和权限概念,推荐调用.authorities("mng_user","ROLE_ADMIN");,将角色全大写,有前缀:ROLE_
千万不要调用下面代码:
.roles("ADMIN")//admin角色,角色一般全大写
.authorities("mng_user");//管理user权限,权限一般小写
后一行代码会覆盖前一行