SpringSecurity模板/快速开始(超详细)基于SpringBoot


文章介绍
本文只有SpringSecurity的解释,其他内容请自行配置。快速使用请直接阅读前三个代码块,前三个代码块包含后面的内容介绍。

一、依赖

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-security</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
	<!--mybatis-plus-->
	<dependency>
		<groupId>com.baomidou</groupId>
		<artifactId>mybatis-plus-boot-starter</artifactId>
		<version>3.0.5</version>
	</dependency>
	<!--mysql-->
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
	</dependency>
	<!--lombok 用来简化实体类-->
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-thymeleaf</artifactId>
	</dependency>
</dependencies>

二、在service目录下创建

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private UsersMapper usersMapper;
    @Override
    public UserDetails loadUserByUsername(String s) throws
            UsernameNotFoundException {
        QueryWrapper<Users> wrapper = new QueryWrapper();
        wrapper.eq("username",s);
        Users users = usersMapper.selectOne(wrapper);
        if(users == null) {
            throw new UsernameNotFoundException("用户名不存在!");
        }
		
		
		
        System.out.println(users);
        List<GrantedAuthority> auths =
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_admin"); // 为用户授权 ROLE_xxx 为用户授予xxx角色
        //for(Role role:roleList){  如果数据库中有角色表
		//	SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_"+role.getName());
		//	auths.add(simpleGrantedAuthority);
		//}
		//for(Menu menu:menuList){  如果数据库存中有用户对应权限
		//	SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(menu.getPermission());
		//	auths.add(simpleGrantedAuthority);
		//}
		
		return new User(users.getUsername(),
                new BCryptPasswordEncoder().encode(users.getPassword()),auths);
    }
}

三、在config目录下创建

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 注入 PasswordEncoder 类到 spring 容器中
	@Autowired
	private UserDetailsService userDetailsService;

	
	@Autowired
	private PersistentTokenRepository tokenRepository;

	@Bean
	public PasswordEncoder passwordEncoder(){
		return new BCryptPasswordEncoder();
	}
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception{
		auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
	}
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// 退出
		http.logout().logoutUrl("/logout").logoutSuccessUrl("/index").permitAll();
		// 配置认证
		http.formLogin()
			.loginPage("/index") // 配置哪个 url 为登录页面
			.loginProcessingUrl("/login") // 设置哪个是登录的 url。
			.successForwardUrl("/success") // 登录成功之后跳转到哪个 url
			.failureForwardUrl("/fail")// 登录失败之后跳转到哪个 url
			.usernameParameter("xxxname") // 设置表单提交的用户名和密码
			.passwordParameter("xxxpwd");
		http.authorizeRequests()
			.antMatchers("/layui/**","/index").permitAll() //表示配置无需验证的请求路径 // 指定 URL 无需保护。
			.anyRequest().authenticated() // 其他请求//需要认证
			//.antMatchers("/findAll").hasAuthority("admin") //当前登录用户,只有具有admin权限才可以访问这个路径(需要为用户设置权限)
			//.antMatchers("/find").hasAnyAuthority("role,admin") //当前登录用户,具有其中一项权限即可
			.antMatchers("/findAll").hasRole("admin") // 需要用户具有admin角色
			.antMatchers("/find").hasAnyRole("admin,role"); // 需要用户具有其中至少一种角色
		// 开启记住我功能
		http.rememberMe()
			.tokenRepository(tokenRepository)
			.tokenValiditySeconds(60) // 设置有效时长,单位是以秒为单位
			.userDetailsService(userDetailsService);
		// 关闭 csrf
		http.csrf().disable();

	}
}
@Configuration
public class BrowserSecurityConfig {
	@Autowired
	private DataSource dataSource;
	@Bean
	public PersistentTokenRepository persistentTokenRepository(){
		JdbcTokenRepositoryImpl jdbcTokenRepository = new 
		JdbcTokenRepositoryImpl();
		// 赋值数据源
		jdbcTokenRepository.setDataSource(dataSource);
		// 自动创建表,第一次执行会创建,以后要执行就要删除掉!
		jdbcTokenRepository.setCreateTableOnStartup(true);
		return jdbcTokenRepository;
	 }
}

四、注解使用

1.@Secured

使用注解先要开启注解功能!
@EnableGlobalMethodSecurity(securedEnabled=true)

判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“。
例如:在控制器方法上添加注解

	// 测试注解:
	@RequestMapping("testSecured")
	@ResponseBody
	@Secured({"ROLE_normal","ROLE_admin"})
	public String helloUser() {
		return "hello,user";
	}

2.@PreAuthorize

先开启注解功能:
@EnableGlobalMethodSecurity(prePostEnabled = true)
@PreAuthorize:注解适合进入方法前的权限验证, @PreAuthorize 可以将登录用
户的 roles/permissions 参数传到方法中。
例如:

	@RequestMapping("/preAuthorize")
	@ResponseBody
	//@PreAuthorize("hasRole('ROLE_管理员')")
	@PreAuthorize("hasAnyAuthority('admin')")
	public String preAuthorize(){
		System.out.println("preAuthorize");
		return "preAuthorize";
	}	

3.@PostAuthorize

先开启注解功能:
@EnableGlobalMethodSecurity(prePostEnabled = true)
@PostAuthorize 注解使用并不多,在方法执行后再进行权限验证,适合验证带有返回值的权限.
例如:

	@RequestMapping("/testPostAuthorize")
	@ResponseBody
	@PostAuthorize("hasAnyAuthority('menu:system')")
	public String preAuthorize(){
		System.out.println("test--PostAuthorize");
		return "PostAuthorize";
	}

4.@PostFilter

@PostFilter :权限验证之后对数据进行过滤 留下用户名是 admin1 的数据
表达式中的 filterObject 引用的是方法返回值 List 中的某一个元素
例如:

	@RequestMapping("getAll")
	@PreAuthorize("hasRole('ROLE_管理员')")
	@PostFilter("filterObject.username == 'admin1'")
	@ResponseBody
	public List<UserInfo> getAllUser(){
		ArrayList<UserInfo> list = new ArrayList<>();
		list.add(new UserInfo(1l,"admin1","6666"));
		list.add(new UserInfo(2l,"admin2","888"));
		return list;
	}

5.@PreFilter

@PreFilter: 进入控制器之前对数据进行过滤
例如:

	@RequestMapping("getTestPreFilter")
	@PreAuthorize("hasRole('ROLE_管理员')")
	@PreFilter(value = "filterObject.id%2==0")
	@ResponseBody
	public List<UserInfo> getTestPreFilter(@RequestBody List<UserInfo> 
	list){
		list.forEach(t-> {
		System.out.println(t.getId()+"\t"+t.getUsername());
		});
		return list;
	}

五、基于数据库的记住我

1.创建表

CREATE TABLE `persistent_logins` (
 `username` varchar(64) NOT NULL,
 `series` varchar(64) NOT NULL,
 `token` varchar(64) NOT NULL,
 `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP,
 PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2.编写配置类

在config中创建配置类

@Configuration
public class BrowserSecurityConfig {
	@Autowired
	private DataSource dataSource;
	@Bean
	public PersistentTokenRepository persistentTokenRepository(){
		JdbcTokenRepositoryImpl jdbcTokenRepository = new 
		JdbcTokenRepositoryImpl();
		// 赋值数据源
		jdbcTokenRepository.setDataSource(dataSource);
		// 自动创建表,第一次执行会创建,以后要执行就要删除掉!
		jdbcTokenRepository.setCreateTableOnStartup(true);
		return jdbcTokenRepository;
	 }
}

3.修改安全配置类

在上述 public class SecurityConfig extends WebSecurityConfigurerAdapter类中

	@Autowired
	private UsersServiceImpl usersService;
	@Autowired
	private PersistentTokenRepository tokenRepository;
	// 开启记住我功能
	http.rememberMe()
	 .tokenRepository(tokenRepository)
	 .userDetailsService(usersService)
	 .tokenValiditySeconds(60)// 设置有效时长,单位是以秒为单位

4.页面添加记住我复选框

记住我:<input type="checkbox"name="remember-me"title=“记住密码”/>

此处:name 属性值必须位 remember-me.不能改为其他值
CSRF

1.CSRF 理解

跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click
attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。
这利用了 web 中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
从 Spring Security 4.0 开始,默认情况下会启用 CSRF 保护,以防止 CSRF 攻击应用程序,Spring Security CSRF 会针对 PATCH,POST,PUT 和 DELETE 方法进行防护。

2.使用

在登录页面添加一个隐藏域:

	<input type="hidden"th:if="${_csrf}!=null"th:value="${_csrf.token}"name="_csrf"/>

在SecurityConfig中关闭安全配置的类中的 csrf

	// http.csrf().disable();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

炎丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值