解決Spring Security的權(quán)限配置不生效問(wèn)題
Spring Security權(quán)限配置不生效
在集成Spring Security做接口權(quán)限配置時(shí),在給用戶配置的權(quán)限后,還是一直顯示“無(wú)權(quán)限”或者"權(quán)限不足"。
1、不生效的例子
接口
@RequestMapping("/admin")
@ResponseBody
@PreAuthorize("hasRole('ADMIN')")
public String printAdmin() {
return "如果你看見(jiàn)這句話,說(shuō)明你有ROLE_ADMIN角色";
}
@RequestMapping("/user")
@ResponseBody
@PreAuthorize("hasRole('USER')")
public String printUser() {
return "如果你看見(jiàn)這句話,說(shuō)明你有ROLE_USER角色";
}
SecurityConfig
.and()
.authorizeRequests()
.antMatchers("/user").hasAnyRole("USER")
.antMatchers("/admin").hasAnyRole("ADMIN")
.anyRequest().authenticated() //必須授權(quán)才能范圍
用戶攜帶權(quán)限

2、解決辦法
經(jīng)測(cè)試,只有用戶攜帶權(quán)限的字段為 “ROLE_” + 接口/配置 中的權(quán)限字段,才能控制生效,舉例:
將上面的用戶攜帶權(quán)限改為

Spring Security動(dòng)態(tài)配置權(quán)限
導(dǎo)入依賴
<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>
相關(guān)配置
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
實(shí)體類User,Role,Menu
這里要實(shí)現(xiàn)UserDetails接口,這個(gè)接口好比一個(gè)規(guī)范。防止開(kāi)發(fā)者定義的密碼變量名各不相同,從而導(dǎo)致springSecurity不知道哪個(gè)方法是你的密碼
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;
...
}創(chuàng)建UserMapper類&&UserMapper.xml
和MenuMapper類&&MenuMapperxml
UserMapper
@Mapper
public 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
@Mapper
public 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>

創(chuàng)建UserService MenuService
創(chuàng)建UserService實(shí)現(xiàn)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;
? ? }
}創(chuàng)建MenuService
@Service
public class MenuService {
? ? @Autowired
? ? private MenuMapper menuMapper;
? ? public List<Menu> getMenus() {return menuMapper.getMenus();}
}創(chuàng)建CustomFilterInvocationSecurityMetadataSource
實(shí)現(xiàn)接口FilterInvocationSecurityMetadataSource
注:加@comppent注解,把自定義類注冊(cè)成spring組件
supports返回值設(shè)成true表示支持
重寫getAttributes()方法
invacation調(diào)用 ,求助metadata元數(shù)據(jù)
@Component
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
? ? //ant風(fēng)格的路徑匹配器
? ? AntPathMatcher pathMatcher = new AntPathMatcher();
? ? @Autowired
? ? private MenuService menuService;
?? ??? ?//supports返回值設(shè)成true表示支持
? ? @Override
? ? public boolean supports(Class<?> aClass) {
? ? ? ? return true;
? ? }
? ? @Override
? ? public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
? ? ? ? //獲取當(dāng)前用戶請(qǐng)求的url
? ? ? ? String requestUrl=((FilterInvocation) object).getRequestUrl();
? ? ? ? //數(shù)據(jù)庫(kù)中查詢出所有的路徑
? ? ? ? List<Menu> menus ?=menuService.getMenus();
? ? ? ? for (Menu menu : menus) {
? ? ? ? ? ? //判斷用戶請(qǐng)求的url和數(shù)據(jù)庫(kù)的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);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? //如果沒(méi)有匹配上就返回一個(gè)默認(rèn)的角色,作用好比作一個(gè)標(biāo)記
? ? ? ? return SecurityConfig.createList("ROLE_def");
? ? }
? ? @Override
? ? public Collection<ConfigAttribute> getAllConfigAttributes() {
? ? ? ? return null;
? ? }
}創(chuàng)建CustomAccessDecisionManager
實(shí)現(xiàn)AccessDecisionManager接口 access 通道
注:加@comppent注解,把自定義類注冊(cè)成spring組件
將兩個(gè)supports()都設(shè)置成true
重寫decide()方法
@Component
public class CustomAccessDecisionManager implements AccessDecisionManager {
? ? @Override
? ? public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
? ? ? ? //configattributes里存放著CustomFilterInvocationSecurityMetadataSource過(guò)濾出來(lái)的角色
? ? ? ? for (ConfigAttribute configAttribute : collection) {
? ? ? ? ? ? //如果你請(qǐng)求的url在數(shù)據(jù)庫(kù)中不具備角色
? ? ? ? ? ? if ("ROLE_def".equals(configAttribute.getAttribute())) {
? ? ? ? ? ? ? ? //在判斷是不是匿名用戶(也就是未登錄)
? ? ? ? ? ? ? ? if (authentication instanceof AnonymousAuthenticationToken) {
? ? ? ? ? ? ? ? ? ? System.out.println(">>>>>>>>>>>>>>>>匿名用戶>>>>>>>>>>>>>>");
? ? ? ? ? ? ? ? ? ? throw new AccessDeniedException("權(quán)限不足,無(wú)法訪問(wèn)");
? ? ? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? ? ? //這里面就是已經(jīng)登錄的其他類型用戶,直接放行
? ? ? ? ? ? ? ? ? ? System.out.println(">>>>>>>>>>>其他類型用戶>>>>>>>>>>>");
? ? ? ? ? ? ? ? ? ? return;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? //如果你訪問(wèn)的路徑在數(shù)據(jù)庫(kù)中具有角色就會(huì)來(lái)到這里
? ? ? ? ? ? //Autherntication這里面存放著登錄后的用戶所有信息
? ? ? ? ? ? Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
? ? ? ? ? ? for (GrantedAuthority authority : authorities) {
? ? ? ? ? ? ? ? System.out.println(">>>>>>>authority(賬戶所擁有的權(quán)限):"+authority.getAuthority());
? ? ? ? ? ? ? ? System.out.println(">>>>>>>configAttribute(路徑需要的角色):"+configAttribute.getAttribute());
? ? ? ? ? ? ? ? //路徑需要的角色和賬戶所擁有的角色作比較
? ? ? ? ? ? ? ? if (authority.getAuthority().equals(configAttribute.getAttribute())) {
? ? ? ? ? ? ? ? ? ? System.out.println(">>>>>>>>>>>>>>>>>>進(jìn)來(lái)>>>>>>>>>>>>>>>>>");
? ? ? ? ? ? ? ? ? ? return;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? @Override
? ? public boolean supports(ConfigAttribute configAttribute) {
? ? ? ? return true;
? ? }
? ? @Override
? ? public boolean supports(Class<?> aClass) {
? ? ? ? return true;
? ? }
}創(chuàng)建WebSecurityConfig配置類
WebSecurityConfig實(shí)現(xiàn)WebSecurityConfigurerAdapter
注入一會(huì)所需要的類
SpringSecurity5.0之后必須密碼加密
將數(shù)據(jù)庫(kù)查出的賬戶密碼交給SpringSecurity去判斷
配置HttpSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
? ? @Autowired
? ? private UserService userService;
? ? @Autowired
? ? private CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource;
? ? @Autowired
? ? private CustomAccessDecisionManager customAccessDecisionManager;
? ? //springSecutity5.0之后必密碼加密
? ? @Bean
? ? PasswordEncoder passwordEncoder(){
? ? ? ? return new BCryptPasswordEncoder();
? ? }
? ? //將數(shù)據(jù)庫(kù)查出的賬戶密碼交給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
@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";
? ? }
}

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- 詳解Spring Security 中的四種權(quán)限控制方式
- java中自定義Spring Security權(quán)限控制管理示例(實(shí)戰(zhàn)篇)
- spring security動(dòng)態(tài)配置url權(quán)限的2種實(shí)現(xiàn)方法
- SpringSecurity動(dòng)態(tài)加載用戶角色權(quán)限實(shí)現(xiàn)登錄及鑒權(quán)功能
- Spring security實(shí)現(xiàn)登陸和權(quán)限角色控制
- SpringBoot整合Security實(shí)現(xiàn)權(quán)限控制框架(案例詳解)
- Spring security實(shí)現(xiàn)權(quán)限管理示例
- SpringBoot2.0 整合 SpringSecurity 框架實(shí)現(xiàn)用戶權(quán)限安全管理方法
- Spring Security動(dòng)態(tài)權(quán)限的實(shí)現(xiàn)方法詳解
- 基于Spring Security的動(dòng)態(tài)權(quán)限系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)
相關(guān)文章
SpringBoot中的@CacheEvict 注解的實(shí)現(xiàn)
本文主要介紹了SpringBoot中的@CacheEvict注解的實(shí)現(xiàn),@CacheEvict 注解用于清空緩存,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03
淺談Java回收對(duì)象的標(biāo)記和對(duì)象的二次標(biāo)記過(guò)程
這篇文章主要介紹了淺談Java回收對(duì)象的標(biāo)記和對(duì)象的二次標(biāo)記過(guò)程的相關(guān)內(nèi)容,小編覺(jué)得還是挺不錯(cuò)的,這里給大家分享一下,需要的朋友可以參考。2017-10-10
springMVC中基于token防止表單重復(fù)提交方法
本篇文章主要介紹了springMVC中基于token防止表單重復(fù)提交方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07
關(guān)于Springboot在新增和修改下上傳圖片并顯示的問(wèn)題
這篇文章主要介紹了關(guān)于Springboot在新增和修改下上傳圖片并顯示的問(wèn)題及解決方法,在這里 springboot中已經(jīng)內(nèi)嵌了上傳圖片的依賴包,因此不需要再添加額外依賴,具體實(shí)現(xiàn)代碼跟隨小編一起看看吧2021-04-04
Kotlin傳遞可變長(zhǎng)參數(shù)給Java可變參數(shù)實(shí)例代碼
這篇文章主要介紹了Kotlin傳遞可變長(zhǎng)參數(shù)給Java可變參數(shù)實(shí)例代碼,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
java定時(shí)任務(wù)Timer和TimerTask使用詳解
這篇文章主要為大家詳細(xì)介紹了java定時(shí)任務(wù)Timer和TimerTask使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02

