一、配置准备
1、引入相关pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
2、实现UserDetailsService,自定义赋予角色权限
//1、实现UserDetailsService接口
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
//实现了mybatis-plus的BaseMapper
@Autowired
UsersMapper usersMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//2、在其中实现方法中写入用户的验证逻辑
//权限不能为空,一般是从数据库中读
//当用通过角色判断是否可以访问该页面时则需要给角色的名前+‘ROLE_’
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin2,admin,manager,ROLE_admin");
//Users是自定义的实体类
QueryWrapper<Users> wrapper = new QueryWrapper<>();
//条件
wrapper.eq("username",username);
//从数据库中查询用户
Users users = usersMapper.selectOne(wrapper);
if(users == null){
throw new UsernameNotFoundException("用户名未找到");
}
return new User(users.getUsername(),new BCryptPasswordEncoder().encode(users.getPassword()),auths);
}
}
3、SpringSecurity基础配置
@Configuration
@ComponentScan("com.security.securitydemo.entity")
public class SecurityConfigTest extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
//1、配置数据源
@Autowired
private DataSource dataSource;
//配置PersistentTokenRepository,该类用于配置token数据的处理方式
//1、JdbcTokenRepositoryImpl 将token数据持久化(通过数据保存token)
//2、InMemoryTokenRepositoryImpl 将token数据存在内存中
@Bean
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
//配置数据源
jdbcTokenRepository.setDataSource(dataSource);
//自动生成存储token的表
//jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
}
/**
* 配置页面访问权限及登录退出页面跳转,可根据自己的情况进行配置
* @param httpSecurity
* @throws Exception
*/
public void configure(HttpSecurity httpSecurity) throws Exception {
// httpSecurity.exceptionHandling().accessDeniedPage("/403"); /* 配置没有权限访问条状自定义页面 */
//用户登录
httpSecurity.formLogin() /* 自定义自己编写的登录界面 */
.loginPage("/login") /* 登录页面设置 */
.loginProcessingUrl("/user/login") /* 登录访问路径 */
.defaultSuccessUrl("/success") /* 登陆成功后跳转路径 */
.failureForwardUrl("/fail").permitAll() /* 登陆失败跳转页面 */
//权限设置
.and().authorizeRequests() /* 指定哪些url可以访问,那些不能访问 */
.antMatchers("/test/index","/user/login").permitAll() /* 设置那些路径不需要认证可以访问 */
.antMatchers("/test/hello").hasAnyRole("admin") /* 跟具已有角色判断是否可以访问这个页面 */
// .antMatchers("/test/hello").hasRole("manager") /* 跟具已有角色判断是否可以访问这个页面 */
// .antMatchers("/test/hello").hasAnyAuthority("admin","manager") /* 只要有拥有其中一个权限即可访问这个页面 */
// .antMatchers("/test/hello").hasAuthority("admin") /* 当前用户登录只有具有admin权限才可以访问这个路径 */
.anyRequest().authenticated() /* 所有请求都可以访问 */
//token配置
.and().rememberMe().tokenRepository(persistentTokenRepository()) /* 2、设置PersistentTokenRepository */
.tokenValiditySeconds(60) /* 设置有效时长,单位秒 */
.userDetailsService(userDetailsService);
//.and().csrf().disable(); /* 关闭csrf防护 */
//用户注销
httpSecurity.logout()
.logoutUrl("/logout") /* 注销访问路劲 */
.logoutSuccessUrl("/test/index").permitAll(); /* 注销成功跳转路径 */
}
@Bean
public PasswordEncoder encoder(){
return new BCryptPasswordEncoder();
}
}
4、写好自己的登录页面及登录接口
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(){
return "login";
}
@RequestMapping("/success")
public String success(){
return "success";
}
@RequestMapping("/fail")
public String fail(){
return "fail";
}
@RequestMapping("/logout")
public String logout(){
return "login";
}
}
5、写好用于测试的接口
@Controller
@RequestMapping("/test")
@EnableGlobalMethodSecurity(securedEnabled=true,prePostEnabled=true,jsr250Enabled = true) /* 开启security注解 */
public class TestController {
/**
* @Secured 验证是否有其中一个角色,有才能调用该方法
* @return
*/
@Secured({"ROLE_manage","ROLE_admin"}) /* 只要拥有manage或admin其中一个角色就可以使用这个方法 */
@RequestMapping("testSecured")
@ResponseBody
public String testSecured(){
System.out.println("testSecured.....");
return "testSecured ok";
}
/**
* @RolesAllowed 验证是否有其中角色
* 该注解需要开启jsr250Enabled
* @return
*/
@RolesAllowed({"ROLE_manage","ROLE_admin"})
@RequestMapping("testRolesAllowed")
@ResponseBody
public String testRolesAllowed() {
System.out.println("testRolesAllowed.....");
return "testRolesAllowed ok";
}
/**
* @PreAuthorize 在方法执行前进行权限验证
* 在其中还可以使用其他的验证防范例如hasRole等
* 这里是验证当前用户是否有admin权限
* @return
*/
@RequestMapping("testPreAuthorize")
@ResponseBody
@PreAuthorize("hasAnyAuthority('admin')") /* 在方法调用之前验证是否有admin权限,没有则无法调用该方法 */
public String testPreAuthorize(){
System.out.println("PreAuthorize......");
return "PreAuthorize ok";
}
/**
* @PostAuthorize 在方法执行后再进行权限验证
* 可以使用内置的表达式returnObject表示方法的返回值
* @return
*/
@PostAuthorize("returnObject.equals('PostAuthorize ok')") /* 在方法执行后再进行权限验证,适合验证带有返回值的权限 */
@RequestMapping("testPostAuthorize")
@ResponseBody
public String testPostAuthorize(){
System.out.println("PostAuthorize......");
return "PostAuthorize ok";
}
/**
* @PostFilter 过滤返回的结果
* 这里指的是只返回username为zhangsan的内容
* @return
*/
@PreAuthorize("hasAnyAuthority('admin')")
@PostFilter("filterObject.username == 'zhansan'") /* 如果有权限满足条件则过滤响应结果 */
@ResponseBody
@RequestMapping("testPostFilter")
public List<Users> testPostFilter(){
List<Users> list = new ArrayList<>();
list.add(new Users(1,"zhansan","123"));
list.add(new Users(2,"lisi","123"));
System.out.println(list);
return list; //[{"id":1,"username":"zhansan","password":"123"}]
}
/**
* @PreFilter 过滤的是传进来的参数
* 这里指传进来Users列表中Users的id>2才能被传进来
* @param list1
* @return
*/
@RequestMapping("testPreFilter")
@PreAuthorize("hasAnyAuthority('admin')")
@PreFilter(value = "filterObject.id %2 == 0") /* 满足条件,对于参数数据进行过滤处理 */
@ResponseBody
public List<Users> testPreFilter(List<Users> list1){
List<Users> list2 = new ArrayList<>();
list2.add(new Users(10,"十","12345"));
list1.addAll(list2);
return list1;
}
}
二、注解说明
在使用springsecurity注解之前需要在类上开启springsecurity的注解
@EnableGlobalMethodSecurity(securedEnabled=true,prePostEnabled=true,jsr250Enabled = true) /* 开启security注解 */
权限均参照以上我在MyUserDetailsService中配置的权限,及以上在接口配置的注解
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin2,admin,manager,ROLE_admin");
1、@Secured
验证是否有其中的一个角色,有才能调用该接口
注意:在使用该接口前必须在 @EnableGlobalMethodSecurity 注解中添加securedEnabled=true才能使该注解生效
@Secured({"ROLE_manage","ROLE_admin"})
演示效果
2、@RolesAllowed
类似于@Secured 验证是否有其中的一个角色,有才能调用该接口
注意:该注解需要开启jsr250Enabled
@RolesAllowed({"ROLE_manage","ROLE_admin"})
演示效果
3、@PreAuthorize
注意:该注解需要开启prePostEnabled=true
在方法执行前进行权限验证,主要是配合以下的验证方法对用户进行权限验证
hasRole(“manager”)、hasAnyAuthority(“admin”,“manager”)、hasAuthority(“admin”)、hasAnyRole(“admin”)
@PreAuthorize("hasAnyAuthority('admin')")
演示效果
4、@PostAuthorize
注意:该注解需要开启prePostEnabled=true
在方法执行后对返回值进行权限验证
可以使用内置的表达式returnObject表示方法的返回值
以下演示返回值均是之前代码的返回值,这里的返回值是PostAuthorize ok
@PostAuthorize("returnObject.equals('PostAuthorize ok')")
演示效果
@PostAuthorize("returnObject.equals('PostAuthorize no')")
演示效果(该页面为自定义的403无权限提示页面)
5、@PostFilter
过滤返回的结果
filterObject是执行过滤操作的内置对象。
@PostFilter("filterObject.username == 'zhansan'") //这里指的是只返回username为zhangsan的内容
演示效果
返回全部内容如下所示
public List<Users> testPostFilter(){
List<Users> list = new ArrayList<>();
list.add(new Users(1,"zhansan","123"));
list.add(new Users(2,"lisi","123"));
System.out.println(list);
return list; //[{"id":1,"username":"zhansan","password":"123"}]
}
6、@PreFilter
过滤的是传进来的参数
filterObject是执行过滤操作的内置对象。
后续补充。。。。。