springSecurity授權方式有三種,分別是配置授權,注解授權,標簽授權
這里使用 注解授權
配置類
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; //配置開啟注解式授權 @EnableGlobalMethodSecurity(prePostEnabled = true) @EnableWebSecurity @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private BzAdminServiceImpl bzAdminService; /** * Authentication 認證的意思 * 在shiro和SpringSecurity中 所有以Authen開頭的單詞都和認證業務有關系 * * 定義數據源 定義要不要使用數據庫的數據 或者使用假數據 */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(bzAdminService).passwordEncoder(bCryptPasswordEncoder());
// 內存測試數據
// auth.inMemoryAuthentication().withUser("lisi") // .password("{noop}123456") // .authorities("ROLE_admin","banner:delete","admin:delete") // .and() // .withUser("zhangsan") // .password("{noop}123456") // .authorities("ROLE_superadmin","banner:delete","category:select") // ;
} @Bean public BCryptPasswordEncoder bCryptPasswordEncoder(){ return new BCryptPasswordEncoder(); } /** * HttpSecurity 配置攔截規則 跳轉 和 自定義登錄頁面 * */ @Override protected void configure(HttpSecurity http) throws Exception { /** * authorizition 授權 * 在shiro和SpringSecurity中 所有以Author開頭的單詞都和授權業務有關系 * authorizeRequests 配置攔截規則 * antMatchers 配置路徑 * permitAll 不攔截 */ http.authorizeRequests() // 配置不攔截
.antMatchers("/admin/**", "/img/**", "/css/**", "/js/**", "/ztree/**", "/login.jsp", "/login", "/layui/**") .permitAll() //.antMatchers("/pmsCategory/getZtreeCategory").hasAnyRole("ADMIN") // .antMatchers("/pmsCategory/getZtreeCategory").hasAuthority("category:select") // 攔截所有 配置一般不會使用/** 而是獨立配置 // anyRequest 代表所有路徑
.anyRequest() .authenticated(); //formLogin() 代表表單登錄
http.formLogin() // loginPage 自定義登錄頁面
.loginPage("/login.jsp") //successForwardUrl 登錄成功后的地址
.successForwardUrl("/admin/successForwardUrl") // failureForwardUrl 登錄失敗后的地址
.failureForwardUrl("/error.jsp") //loginProcessingUrl 定義登錄方法的地址 /login就是SpringSecurity中的認證方法
.loginProcessingUrl("/login") .and() .csrf() .disable() ; // html iframe標簽引用二級頁面 會被默認攔截 // 可以配置不攔截
http.headers().frameOptions().disable(); } }
業務類
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import java.util.List; import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @Service public class BzAdminServiceImpl implements BzAdminService, UserDetailsService { @Autowired private BzAdminMapper bzAdminMapper; @Autowired private HttpServletRequest request; @Autowired private BzRoleService bzRoleService; //該方法是springSecurity 預留的查詢數據庫方法,需要我們自己寫實現 //形參是 用戶名 @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { String oldCode =(String) request.getSession().getAttribute("oldCode"); String code = request.getParameter("code"); if (!oldCode.equalsIgnoreCase(code)){ threadLocal.set("驗證碼錯誤"); throw new UsernameNotFoundException("驗證碼錯誤"); } BzAdmin username = getOne(new QueryWrapper<BzAdmin>().eq("username", s)); if (username==null){ throw new UsernameNotFoundException(s+"不存在"); } //權限 Set<String> permissionsByUsername = bzRoleService.getPermissionsByUsername(s); permissionsByUsername.remove("null"); List<GrantedAuthority> list1 = permissionsByUsername.stream() .filter(new Predicate<String>() { @Override public boolean test(String s) { return s!=null; } }) .map((Function<String, GrantedAuthority>) permissions -> { SimpleGrantedAuthority simpleGrantedAuthority = null; if (permissions!=null){ simpleGrantedAuthority = new SimpleGrantedAuthority(permissions); } return simpleGrantedAuthority; }).collect(Collectors.toList()); // 角色 Set<String> rolesByUsername = bzRoleService.getRolesByUsername(s); List<GrantedAuthority> list = rolesByUsername.stream().map(new Function<String, GrantedAuthority>() { @Override public GrantedAuthority apply(String role) { return new SimpleGrantedAuthority("ROLE_" + role); } }).collect(Collectors.toList()); list.addAll(list1); //放入權限 角色 集合 username.setAuthorityList(list); return username; } }
實體類
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableLogic; import lombok.Data; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; import javax.validation.constraints.Size; import java.io.Serializable; import java.util.Collection; import java.util.List; @Data public class BzAdmin implements Serializable, UserDetails { @TableId(value = "id",type = IdType.AUTO) private Integer id; private String username; private String password; private String mima; @TableLogic(value = "0",delval = "1") private Integer status = 0; //封裝角色信息和授權信息 必須是GrantedAuthority接口的實現類 @TableField(exist = false) private List<GrantedAuthority> authorityList; //封裝授權信息 @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorityList; } //賬號失效 @Override public boolean isAccountNonExpired() { return true; } //賬戶鎖定 @Override public boolean isAccountNonLocked() { return true; } //憑證信息失效 @Override public boolean isCredentialsNonExpired() { return true; } //賬號可用性 @Override public boolean isEnabled() { return true; } }
測試
在需要權限的方法上添加注解
@PreAuthorize("hasAnyRole('vip')") //校檢角色
@PreAuthorize("hasAuthority('admin:select')") //校檢權限
常見的權限字符串的寫法
權限字符串的規則是:“資源類型:操作(增刪改查):資源實例(id)
| 權限的漢語描述 | 權限字符串 資源類型:操作:實例 |
| 展示輪播圖 | banner:select |
| 展示id為10的輪播圖 | banner:show:10 |
| 刪除輪播圖 | banner:delete |
| 刪除商品 | product:delete |
