spring security中,如果权限字符以"ROLE_"开头,者可以使用@PreAuthorize("hasRole('ROLE_ADMIN')")注解匹配,其他使用@PreAuthorize("hasAuthority('user:write')")注解匹配
-
修改建表结构
CREATE TABLE `permission` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`url` varchar(255) NOT NULL COMMENT 'url',
`permission` varchar(255) NOT NULL DEFAULT '' COMMENT '权限字符',
`pmod` varchar(255) DEFAULT NULL COMMENT '模式',
`name` varchar(255) NOT NULL COMMENT '名称',
`description` varchar(255) DEFAULT NULL COMMENT '描述',
`pid` bigint(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
-
测试数据
-
实体类
public class Permission implements GrantedAuthority ,Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
private Long id;
/**
* url
*/
private String url;
/**
* name
*/
private String permission;
private String pmod;
/**
* name
*/
private String name;
/**
* description
*/
private String description;
/**
* pid
*/
private Long pid;
public Permission() {
}
public Permission(String url) {
this.url=url;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
if(!url.startsWith("/")){
url="/"+url;
}
this.url = url.trim().replaceAll(" ","");
}
public String getPermission() {
return permission;
}
public void setPermission(String permission) {
this.permission = permission;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Permission that = (Permission) o;
return url.equals(that.url);
}
@Override
public int hashCode() {
return Objects.hash(url);
}
@Override
public String toString() {
return "Permission{" +
"id=" + id +
", url='" + url + '\'' +
", name='" + name + '\'' +
", description='" + description + '\'' +
'}';
}
@Override
@JsonIgnore
public String getAuthority() {
return permission;
}
public String getPmod() {
return pmod;
}
public void setPmod(String pmod) {
this.pmod = pmod;
}
}
-
实现PermissionEvaluator接口
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
User user= (User) authentication.getPrincipal();
PathMatcher pathMatcher = new AntPathMatcher();
List<Permission> permissions = user.getPermissions();
for(Permission permission1:permissions){
if(pathMatcher.match(targetDomainObject.toString(),permission1.getUrl()) && !"".equals(permission1.getPmod())){
List<String> pmods = Arrays.asList(permission1.getPmod().trim().split(","));
List<String> perPmods = Arrays.asList(permission.toString().trim().split(","));
for(String perPmod:perPmods){
if(pmods.contains(perPmod))
return true;
}
}
}
return false;
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
return true;
}
}
-
配置
@Configuration
@EnableWebSecurity
//开启授权注解支持
//secured-annotations="enabled" :springSecurity内部的权限控制注解开关
//pre-post-annotations="enabled" :spring指定的权限控制注解开关
//jsr250-annotations="enabled" :jave jsr250注解开关
@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled = true,jsr250Enabled = true)
public class MainConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Autowired
private PermissionService permissionService;
@Autowired
private JWTConfigEntity jwtConfigEntity;
@Autowired
private CustomPermissionEvaluator customPermissionEvaluator;
private ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry;
@Bean
public DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler(){
DefaultWebSecurityExpressionHandler handler=new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(customPermissionEvaluator);
return handler;
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
// .antMatchers("/user/**").hasAnyRole("USER","ADMIN")//需要权限的url
.anyRequest().authenticated()//其他访问需要验证通过才能访问
.and()
.addFilter(new JWTLoginFilter(authenticationManager(),jwtConfigEntity))
.addFilter(new JWTVerifyFilter(authenticationManager(),jwtConfigEntity,userService,permissionService))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);//禁用session
}
/**
* 忽略拦截url或静态资源文件夹 -
* web.ignoring(): 会直接过滤该url - 将不会经过Spring Security过滤器链
* http.permitAll(): 不会绕开springsecurity验证,相当于是允许该路径通过
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.GET,
"admin/**",
"/favicon.ico",
"/*.html",
"/**/*.css",
"/**/*.js");
}
}
-
在类上使用注解
@RestController
@RequestMapping(value = "/user")
public class UserController {
@Resource
private UserService userService;
/**
* 因为在springmvc-servlet.xml中开启权限控制的注解支持,所以controller层可以进行授权
* 以下三种注解都已测试,功能正常
* @param id
* @return
*/
// @Secured({"ROLE_ADMIN"})//springSecurity内部的权限控制注解
// @RolesAllowed({"ROLE_ADMIN"}) //jsr250注解
@PreAuthorize("hasRole('ROLE_USER')")//spring指定的权限控制注解:角色
@RequestMapping("/load")
public ReturnT<User> load(int id){
return userService.load(id);
}
@PreAuthorize("hasRole('ROLE_ADMIN')")//spring指定的权限控制注解:角色
@RequestMapping("/load2")
public ReturnT<User> load2(int id){
return userService.load(id);
}
@PreAuthorize("hasAuthority('user:list')")//spring指定的权限控制注解:权限码
@RequestMapping("/load3")
public ReturnT<User> load3(int id){
return userService.load(id);
}
@PreAuthorize("hasAuthority('user:write')")//spring指定的权限控制注解:权限码
@RequestMapping("/load4")
public ReturnT<User> load4(int id){
return userService.load(id);
}
@PreAuthorize("hasPermission('/user/load5','r')")//spring指定的权限控制注解:对路径/user/load5拥有"r"权限
@RequestMapping("/load5")
public ReturnT<User> load5(int id){
return userService.load(id);
}
@PreAuthorize("hasPermission('/user/*','r')")//spring指定的权限控制注解:路径匹配,对路径/user/*拥有"r"权限
@RequestMapping("/load6")
public ReturnT<User> load6(int id){
return userService.load(id);
}
@PreAuthorize("hasPermission('/user/*','r,w')")//spring指定的权限控制注解:路径匹配,对路径/user/*拥有"r,w"权限
@RequestMapping("/load7")
public ReturnT<User> load7(int id){
return userService.load(id);
}
@PreAuthorize("hasPermission('/user/*','x,y')")//spring指定的权限控制注解:路径匹配,对路径/user/*拥有"x,y"权限
@RequestMapping("/load8")
public ReturnT<User> load8(int id){
return userService.load(id);
}
@PreAuthorize("hasPermission('targetId','targetType','r,w')")//spring指定的权限控制注解:路径匹配
@RequestMapping("/load9")
public ReturnT<User> load9(int id){
return userService.load(id);
}
}
-
依次测试:
测试用户:user
角色:ROLE_USER
权限信息: