**第一种方式:**通过配置文件
spring.security.user.name=atguigu spring.security.user.password=atguigu
这时控制台不再打印密码;
**第二种方式:**通过配置类
在config包下新建SecurityConfig配置类:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String password = passwordEncoder.encode("123");
auth.inMemoryAuthentication().withUser("lucy").password(password).roles("admin");
}
}
这时访问输入用户名密码只会停留在登录页面,IDEA控制台报错。
在配置类中添加:
@Bean
PasswordEncoder password() {
return new BCryptPasswordEncoder();
}
**第三种方式:**自定义编写实现类(常用)
新建一个SecurityConfigTest配置类:
@Configuration
public class SecurityConfigTest 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();
}
}
在service包下新建MyUserDetailsService类实现UserDetailsService接口;
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
List auths =
AuthorityUtils.commaSeparatedStringToAuthorityList("role");
return new User("marry", new BCryptPasswordEncoder().encode("123"),auths);
}
}
测试:
总结:
通过查询数据库完成认证:
引入依赖:
com.baomidou
mybatis-plus-boot-starter
3.0.5
mysql
mysql-connector-java
org.projectlombok
lombok
application.properties添加数据库配置:
#mysql数据库连接 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/demo?serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=root
在entity包下新建Users类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
private Integer id;
private String username;
private String password;
}
在mapper包下新建UsersMapper接口:
@Repository public interface UsersMapper extends baseMapper{ }
更改service包下MyUserDetailsService中的代码:
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UsersMapper usersMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//调用usersMapper方法,根据用户名查询数据库
QueryWrapper wrapper = new QueryWrapper();
// where username=?
wrapper.eq("username",username);
Users users = usersMapper.selectOne(wrapper);
//判断
if(users == null) {//数据库没有用户名,认证失败
throw new UsernameNotFoundException("用户名不存在!");
}
List auths =
AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_sale");
//从查询数据库返回users对象,得到用户名和密码,返回
return new User(users.getUsername(),
new BCryptPasswordEncoder().encode(users.getPassword()),auths);
}
}
在配置类或者启动类添加:
@MapperScan("com.atguigu.securitydemo1.mapper")
@EnableGlobalMethodSecurity(securedEnabled=true,prePostEnabled = true)
总结:
自定义用户登录页面:
在config包下SecurityConfigTest类中添加如下代码:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() //自定义自己编写的登录页面
.loginPage("/login.html") //登录页面设置
.loginProcessingUrl("/user/login") //登录访问路径
.defaultSuccessUrl("/test/index").permitAll() //登录成功之后,跳转路径
.and().authorizeRequests()
.antMatchers("/","/test/hello","/user/login").permitAll() //设置哪些路径可以直接访问,不需要认证
.anyRequest().authenticated()
.and().csrf().disable();//关闭csrf保护
}
在resources包下static目录下新建login.html:
Title
注意:name和password的值必须写成username,password,否则SpringSecurity识别不了;
controller添加如下配置:
@GetMapping("index")
public String index() {
return "hello index";
}
访问localhost:8111/test/hello 可以直接访问;
访问localhost:8111/test/index:
总结:
基于角色或权限进行访问控制:
修改config包下SecurityConfigTest类中代码:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() //自定义自己编写的登录页面
.loginPage("/login.html") //登录页面设置
.loginProcessingUrl("/user/login") //登录访问路径
.defaultSuccessUrl("/test/index").permitAll() //登录成功之后,跳转路径
.and().authorizeRequests()
.antMatchers("/","/test/hello","/user/login").permitAll() //设置哪些路径可以直接访问,不需要认证
//当前登录用户,只有具有admins权限才可以访问这个路径
//1 hasAuthority方法
.antMatchers("/test/index").hasAuthority("admins")
.anyRequest().authenticated()
.and().csrf().disable();//关闭csrf保护
}
权限不匹配时出现如下页面,表示没有访问权限:
权限改为admins:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() //自定义自己编写的登录页面
.loginPage("/login.html") //登录页面设置
.loginProcessingUrl("/user/login") //登录访问路径
.defaultSuccessUrl("/test/index").permitAll() //登录成功之后,跳转路径
.and().authorizeRequests()
.antMatchers("/","/test/hello","/user/login").permitAll() //设置哪些路径可以直接访问,不需要认证
//当前登录用户,只有具有admins权限才可以访问这个路径
//1 hasAuthority方法
//.antMatchers("/test/index").hasAuthority("admins")
//2 hasAnyAuthority方法
//.antMatchers("/test/index").hasAnyAuthority("admins,manager")
//3 hasRole方法 ROLE_sale
.antMatchers("/test/index").hasRole("sale")
.anyRequest().authenticated()
.and().csrf().disable();//关闭csrf保护
}
自定义403页面:
static下新建unauth.html页面:
Title
没有访问权限!
注解使用:
用户注销:
config包下修改SecurityConfigTest类:
@Override
protected void configure(HttpSecurity http) throws Exception {
//退出
http.logout().logoutUrl("/logout").
logoutSuccessUrl("/test/hello").permitAll();
//配置没有权限访问跳转自定义页面
http.exceptionHandling().accessDeniedPage("/unauth.html");
http.formLogin() //自定义自己编写的登录页面
.loginPage("/login.html") //登录页面设置
.loginProcessingUrl("/user/login") //登录访问路径
.defaultSuccessUrl("/success.html").permitAll() //登录成功之后,跳转路径
.failureUrl("/unauth.html")
.and().authorizeRequests()
.antMatchers("/","/test/hello","/user/login").permitAll() //设置哪些路径可以直接访问,不需要认证
//当前登录用户,只有具有admins权限才可以访问这个路径
//1 hasAuthority方法
//.antMatchers("/test/index").hasAuthority("admins")
//2 hasAnyAuthority方法
//.antMatchers("/test/index").hasAnyAuthority("admins,manager")
//3 hasRole方法 ROLE_sale
.antMatchers("/test/index").hasRole("sale")
.anyRequest().authenticated()
.and().csrf().disable();//关闭csrf保护
}
新建success.html页面:
Title
登录成功!
退出
输入用户名密码登录时:
点击退出时:
自动登录(原理分析):
自动登录(功能实现):
login.html:
Title
此处:name 属性值必须为 remember-me.不能改为其他值
config包下SecurityConfigTest类中修改:
@Override
protected void configure(HttpSecurity http) throws Exception {
//退出
http.logout().logoutUrl("/logout").
logoutSuccessUrl("/test/hello").permitAll();
//配置没有权限访问跳转自定义页面
http.exceptionHandling().accessDeniedPage("/unauth.html");
http.formLogin() //自定义自己编写的登录页面
.loginPage("/login.html") //登录页面设置
.loginProcessingUrl("/user/login") //登录访问路径
.defaultSuccessUrl("/success.html").permitAll() //登录成功之后,跳转路径
.failureUrl("/unauth.html")
.and().authorizeRequests()
.antMatchers("/","/test/hello","/user/login").permitAll() //设置哪些路径可以直接访问,不需要认证
//当前登录用户,只有具有admins权限才可以访问这个路径
//1 hasAuthority方法
//.antMatchers("/test/index").hasAuthority("admins")
//2 hasAnyAuthority方法
//.antMatchers("/test/index").hasAnyAuthority("admins,manager")
//3 hasRole方法 ROLE_sale
.antMatchers("/test/index").hasRole("sale")
.anyRequest().authenticated()
.and().rememberMe().tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(600)//设置有效时长,单位秒
.userDetailsService(userDetailsService)
.and().csrf().disable();//关闭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 方法进行防护。
第一步:
配置类开启:
//关闭csrf保护功能 //http.csrf().disable();
第二步:页面中添加隐藏项。
Spring Security 实现 CSRF 的原理:
- 生成 csrfToken 保存到 HttpSession 或者 cookie 中。
- 请求到来时,从请求中提取 csrfToken,和保存的 csrfToken 做比较,进而判断当
前请求是否合法。主要通过 CsrfFilter 过滤器来完成。



