重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
授权的方式包括web授权和方法授权,web授权是通过url拦截进行授权,方法授权是通过方法拦截进行授权,他们都会调用accessDecisionManager进行授权决策,若为web授权则拦截器为:FilterSecurityIntecepter,若为方法授权则拦截器为:MethodSecurityIntecepter,如果同时通过web授权和方法授权则先进行web授权再执行方法授权,最后决策通过,则允许访问资源,否则将禁止访问。
为新野等地区用户提供了全套网页设计制作服务,及新野网站建设行业解决方案。主营业务为成都网站制作、做网站、新野网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!
1. 准备环境
在user_dbs数据库中创建表:
角色表:
CREATE TABLE t_role (
id VARCHAR(32) NOT NULL,
role_name VARCHAR(255) DEFAULT NULL,
description VARCHAR(255) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
STATUS CHAR(1) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY unique_role_name (role_name)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO t_role(id,role_name,description,create_time,update_time,STATUS) VALUES ('1','管理员',NULL,NULL,NULL,'');
用户角色表:
CREATE TABLE `t_user_role` (
`user_id` VARCHAR(32) NOT NULL,
`role_id` VARCHAR(32) NOT NULL,
`create_time` DATETIME DEFAULT NULL,
`creator` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`user_id`,`role_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `t_user_role`(`user_id`,`role_id`,`create_time`,`creator`) VALUES
('1','1',NULL,NULL);
权限表:
CREATE TABLE `t_permission` (
`id` VARCHAR(32) NOT NULL,
`code` VARCHAR(32) NOT NULL COMMENT '权限标识符',
`description` VARCHAR(64) DEFAULT NULL COMMENT '描述',
`url` VARCHAR(128) DEFAULT NULL COMMENT '请求地址',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `t_permission`(`id`,`code`,`description`,`url`) VALUES ('1','p1','测试资源
1','/r/r1'),('2','p3','测试资源2','/r/r2');
角色权限关系表:
CREATE TABLE `t_role_permission` (
`role_id` VARCHAR(32) NOT NULL,
`permission_id` VARCHAR(32) NOT NULL,
PRIMARY KEY (`role_id`,`permission_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `t_role_permission`(`role_id`,`permission_id`) VALUES ('1','1'),('1','2');
2. 修改UserDetailService
(1) 修改dao接口
ListfindPermissionsByUserId(String userId) { String sql = + + + + ; List list = .query(sql, Object[]{userId}, BeanPropertyRowMapper<>(PermissionDto.)); List permissions = ArrayList<>(); list.iterator().forEachRemaining(c-> .add(c.getCode())); permissions; }
(2)修改UserDetailService
SpringDataUserDetailsService UserDetailsService { UserDao ; UserDetails loadUserByUsername(String username) UsernameNotFoundException { System..println(+username); UserDto user = .getUserByUsername(username); (user == ){ ; } Listpermissions = .findPermissionsByUserId(user.getId()); String[] perarray = String[permissions.size()]; permissions.toArray(perarray); UserDetails userDetails = User.(user.getFullname()).password(user.getPassword()).authorities(perarray).build(); userDetails; } }
在前面的例子中我们完成了认证拦截,并对/r/**下的资源进行简单的保护,我们还可以通过给http.authorizeRequests()添加多个节点来进行灵活的授权控制
.authorizeRequests() () .antMatchers().hasAuthority() () .antMatchers().hasAuthority() () .antMatchers().access() () .antMatchers().authenticated() () .anyRequest().permitAll() () .and() .formLogin()
(1)http.authorizeRequests()方法有多个子节点,每个macher按照他们的声明顺序执行
(2)指定”/r/r1”url拥有p1权限能够访问
(5)指定除了r1,r2,r3之外”/r/**”资源通过身份认证就可以访问
(6)其它的资源不做保护,可以任意访问
注意:规则的顺序,更具体的规则应该先写
例如:
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/admin/login").permitAll()
第一条规则中已经规定以/admin开始的url需要具备ADMIN的角色才能访问,即使第二条规则中/admin/login这个url可以被访问在访问/admin/login时也需要具备ADMIN的角色,因为它在前面,第二条规则被忽略。
因此登录页面的规则应该放在前面
.antMatchers("/admin/login").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
保护URL常用的方法有:
Authenticated()保护URL,需要用户登录
PermitAll()指定URL无需保护,一般用于静态资源文件
hasRole(String role)限制单个角色访问,角色将被增加”ROLE_”,所以”ADMIN”将和”ROLE_ADMIN”比较
hasAuthority(String authority)限制单个权限访问
hasAnyRole(String Roles…)允许多个角色访问
hasAnyyAuthority(String …Authorities)允许多个权限访问
access(String attribute)可以创建复杂的限制
hasIpAddress(String ipAddressExpression)限制ip地址或子网
方法授权:
从Spring Security2.0版开始支持服务层方法授权。
我们可以在任何@Configuration实例上使用@EnableGlobalMethodSecurity来启用基于注解的安全性,以下将启用Spring Security的@Secured注释
@Configuration @EnableGlobalMethodSecurity(securedEnabled = ) WebSecurityConfig WebSecurityConfigurerAdapter {
…
}
然后向方法(类或接口)添加注解就会限制对该方法的访问。
例如:
BankService { @Secured() Account readAccount(Long id); @Secured() Account[] findAccounts(); @Secured() Account post(Account account, amount); }
以上配置表明readAccount和findAccounts方法可以匿名访问
Post方法需要有TELLER角色才能访问
启用prePost注解
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = ) WebSecurityConfig WebSecurityConfigurerAdapter {
…
}
例如:
BankService { @PreAuthorize() Account readAccount(Long id); @PreAuthorize() Account[] findAccounts(); @PreAuthorize() Account post(Account account, amount); }
以上配置表明readAccount和findAccounts可以匿名访问
Post方法需要同时拥有p_transfer和p_read_account权限才能访问