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 |