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 |