赞
踩
Web安全方面的两个主要区域“用户认证(Authentication)”,“用户授权(Authorization)”
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/show")
public String show(){
return "hello security";
}
}
当什么都不配置的时候SpringSecurity的账号密码是自动生成的,实际开发中需要去数据库中查询,我们要通过自定义逻辑控制认证逻辑!
需要自定义逻辑时,只需要实现UserDetailsService接口即可
UserDetailsService接口用来查数据库
用法:
* 创建类继承UsernamePasswordAuthenticationFilter,重写attemptAuthentication、successfulAuthentication、unsuccessfulAuthentication三个方法
* 创建类实现UserDetailsService,编写查询数据过程,返回User对象,这个User对象是安全框架提供的对象
数据加密接口,用于返回User对象里面密码加密
spring:
security:
user:
name: username
password: password
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 加密 BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); String encodePwd = bCryptPasswordEncoder.encode("123123"); auth.inMemoryAuthentication().withUser("zzl").password(encodePwd).roles("admin"); } // 加密过程中需要用到PasswordEncoder对象 @Bean PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
第一步 创建配置类,设置使用哪一个userDetailsService实现类
@Configuration
public class SecurityConfig3 extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
@Bean
PasswordEncoder password(){
return new BCryptPasswordEncoder();
}
}
第二部 编写实现类,返回User对象,User对象有用户名密码和操作权限
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
Collection<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
return new User("zzl",new BCryptPasswordEncoder().encode("000000"),auths);
}
}
1、整合Mybatis-plus 完成数据库操作
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
2、创建数据库,数据库表
create DATABASE securityDemo;
use securityDemo;
create table users(
id int primary key,
username varchar(30) not null,
password varchar(30) not null
);
insert into users values(1,'zzl','zzl'),(2,'lll','lll');
select * from users;
3、创建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
private int id;
private String username;
private String password;
}
4、整合Mybatis-plus,创建接口,继承BaseMapper接口
public interface UsersMapper extends BaseMapper<Users> {
}
5、在MyUserDetailsService调用Mapper里的方法查询数据库进行用户认证
@Service("userDetailsService") public class MyUserDetailsService implements UserDetailsService { @Autowired private UsersMapper usersMapper; @Override public UserDetails loadUserByUsername(String username ) throws UsernameNotFoundException { QueryWrapper<Users> wrapper= new QueryWrapper<>(); wrapper.eq("username",username); Users user = usersMapper.selectOne(wrapper); if(user == null){ throw new UsernameNotFoundException("用户名不存在!"); } Collection<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role"); return new User(user.getUsername(),new BCryptPasswordEncoder().encode(user.getPassword()),auths); } }
6、在启动类上加入@MapperScan注解
在sercurity配置类中重写**configure(HttpSecurity http)**方法
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().loginPage("/login.html") // 自定义登录页面
.loginProcessingUrl("/user/login")//登录页面的数据提交的URL
.defaultSuccessUrl("/test/index").permitAll()//登录成功之后,跳转路径
.and().authorizeRequests()
.antMatchers("/","/user/login","/test/show").permitAll()//设置哪些路径可以直接访问
.anyRequest().authenticated()
.and().csrf().disable();//关闭csrf防护
}
如果当前主体有指定的权限,则返回true否则返回false
测试
在sercurity配置类中配置指定路径的访问权限
protected void configure(HttpSecurity http) throws Exception {
...
.antMatchers("/test/index").hasAuthority("admins")//给指定的路径设置指定的权限
...
}
如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回true
protected void configure(HttpSecurity http) throws Exception {
...
.antMatchers("/test/index").hasAnyAuthority("admins","manager")//给指定的路径设置指定的权限
...
}
如果当前主体具备指定角色,则返回true
protected void configure(HttpSecurity http) throws Exception {
...
.antMatchers("/test/index").hasRole("sale")//给指定的路径设置指定的角色
...
}
注意在业务层给用户添加角色时,必须以’ROLE_'开头
Collection<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_sale");
如果当前主体具备指定的任意角色,则返回true
protected void configure(HttpSecurity http) throws Exception {
...
.antMatchers("/test/index").hasAnyRole("sale","role")//给指定的路径设置指定的角色
...
}
在sercurity配置类中配置指定路径的访问权限
protected void configure(HttpSecurity http) throws Exception {
//设置没有访问权限的错误页面
http.exceptionHandling().accessDeniedPage("/unauth.html");
}
判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀ROLE_
需要先开启使用注解的功能
@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecuritydemoApplication {
public static void main(String[] args) {
SpringApplication.run(SecuritydemoApplication.class, args);
}
}
在指定的方法添加注解
@Secured({"ROLE_sale2"})
@GetMapping("/index")
public String index(){
return "hello index";
}
需要先开启使用注解的功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
@PreAuthorize注解适合进入方法前的权限认证
@PreAuthorize可以将登陆用户的roles/permissions参数传到方法中
需要先开启使用注解的功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
@PostAuthorize注解使用的并不多,在方法执行后在进行权限验证,适合验证带有返回值的权限
在配置类中添加退出映射地址
protected void configure(HttpSecurity http) throws Exception {
...
//用户注销的地址,注销成功后访问的地址
http.logout().logoutUrl("/user/logout").logoutSuccessUrl("/test/index").permitAll();
...
}
cookie技术是将数据存储到客户端,不安全
创建表
security可以自动创建
//手动创建
create table persistent_logins (
username varchar(64) not null,
series varchar(64) primary key,
token varchar(64) not null,
last_used timestamp not null
);
在security配置类中添加数据源,配置操作数据库对象
// 注入数据源
@Autowired
private DataSource dataSource;
@Bean
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
// 自动创建表
// jdbcTokenRepository.setCreateTableOnStartup(true);
jdbcTokenRepository.setDataSource(dataSource);
return jdbcTokenRepository;
}
配置自动登录
@Override
protected void configure(HttpSecurity http) throws Exception {
...
.and().rememberMe().tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(60)//设置有效时长
.userDetailsService(userDetailsService)
...
}
在登录界面添加复选框
<form method="post" action="/user/login">
用户名:<input type="text" name="username"/>
密码:<input type="text" name="password"/>
<input type="checkbox" name="remember-me"/>自动登录
<input type="submit" name="login"/>
</form>
跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。