1、认证
2、授权

1、设置登录的用户名和密码
第一种方式:同故宫配置文件
第二种方式:通过配置类
第三种方式:自定义编写实现类

通过配置文件

  1. spring.security.user.name=admin
  2. spring.security.user.password=admin

通过配置类

  1. @Configuration
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  3. @Override
  4. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  5. BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
  6. String password = passwordEncoder.encode("123");
  7. auth.inMemoryAuthentication()
  8. .withUser("lucy")
  9. .password(password).roles("admin");
  10. }
  11. @Bean
  12. public PasswordEncoder passwordEncoder(){
  13. return new BCryptPasswordEncoder() ;
  14. }
  15. }

自定义编写实现类

第一步 创建配置类,设置使用哪个 userDetailsService 实现类
第二步 编写实现类,返回User对象,有用户名 密码 操作权限

  1. @Configuration
  2. public class SecurityConfigTest extends WebSecurityConfigurerAdapter {
  3. @Autowired
  4. private UserDetailsService userDetailsService;
  5. @Override
  6. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  7. auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
  8. }
  9. @Bean
  10. public PasswordEncoder passwordEncoder(){
  11. return new BCryptPasswordEncoder() ;
  12. }
  13. }
  14. @Service("userDetailsService")
  15. public class MyUserDetailsService implements UserDetailsService {
  16. @Override
  17. public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
  18. List<GrantedAuthority> role = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
  19. return new User(
  20. "marry",
  21. new BCryptPasswordEncoder().encode("1234"),
  22. role
  23. );
  24. }
  25. }

查询数据库完成用户认证

整合MyBatisPlus完成数据库操作

第一步 引入相关依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>com.baomidou</groupId>
  4. <artifactId>mybatis-plus-boot-starter</artifactId>
  5. <version>3.0.5</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>mysql</groupId>
  9. <artifactId>mysql-connector-java</artifactId>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-security</artifactId>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.springframework.boot</groupId>
  17. <artifactId>spring-boot-starter-web</artifactId>
  18. </dependency>
  19. <dependency>
  20. <groupId>org.projectlombok</groupId>
  21. <artifactId>lombok</artifactId>
  22. <optional>true</optional>
  23. </dependency>
  24. </dependencies>

第二步 创建数据库和数据表 User
image.png
第三步 创建对应的实体类

  1. /**
  2. * 用户权限表
  3. * @TableName tbl_user
  4. */
  5. @TableName(value ="tbl_user")
  6. @Data
  7. @ToString
  8. public class User implements Serializable {
  9. /**
  10. * 用户id
  11. */
  12. @TableId(value = "id", type = IdType.AUTO)
  13. private Integer id;
  14. /**
  15. * 用户名
  16. */
  17. @TableField(value = "username")
  18. private String username;
  19. /**
  20. * 密码
  21. */
  22. @TableField(value = "password")
  23. private String password;
  24. @TableField(exist = false)
  25. private static final long serialVersionUID = 1L;
  26. }

第四步 整合MP ,创建接口 继承MP的接口
image.png

第五步 在 MyUserDetailsService 用mapper方法查询数据库进行用户认证

  1. @Service("userDetailsService")
  2. public class MyUserDetailsService implements UserDetailsService {
  3. @Autowired
  4. private UserMapper userMapper;
  5. @Override
  6. public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
  7. // 调用方法查询数据库,根据用户名查询数据库
  8. QueryWrapper<com.atguigu.security.bean.User> wrapper = new QueryWrapper<>();
  9. wrapper.eq("username",userName);
  10. com.atguigu.security.bean.User user = userMapper.selectOne(wrapper);
  11. /**
  12. * 用户名不存在
  13. */
  14. if(user == null){
  15. throw new UsernameNotFoundException("用户名不存在");
  16. }
  17. List<GrantedAuthority> role =
  18. AuthorityUtils.commaSeparatedStringToAuthorityList("role");
  19. return new User(
  20. user.getUsername(),
  21. new BCryptPasswordEncoder().encode(user.getPassword()),
  22. role
  23. );
  24. }
  25. }

自定义设置登录页面,不需要认证可以访问

1、在配置类中实现相关的配置

  1. * 自定义登录页
  2. * @param http
  3. * @throws Exception
  4. */
  5. @Override
  6. protected void configure(HttpSecurity http) throws Exception {
  7. http.formLogin()
  8. .loginPage("/login.html")//登陆页面设置
  9. .loginProcessingUrl("/user/login")//登录访问路径
  10. .defaultSuccessUrl("/test/index").permitAll()//登陆成功跳转的路径
  11. .and().authorizeRequests()
  12. .antMatchers("/","/text/hello","/user/login").permitAll()//设置那些路径可以直接访问不需要认证
  13. .anyRequest().authenticated()
  14. .and().csrf().disable();//关闭csrf防护
  15. }

2、创建相关页面

  1. <form action="/user/login" method="post">
  2. 用户名:<input type="text" name="username" /><br>
  3. 密码:<input type="password" name="password"/><br>
  4. <input type="submit" value="登录">
  5. </form>

3、页面跳转

  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4. @GetMapping(value = "/hello")
  5. public String add(){
  6. return "hello 权限";
  7. }
  8. @GetMapping(value = "/index")
  9. public String index(){
  10. return "hello index";
  11. }
  12. }

3.4 基于角色或者权限进行访问

第一个方法: hasAuthority 方法

如果当前的主体具有指定的权限 则返回 true 否则返回 false

1、在配置类设置当前访问的路径有哪些权限
image.png
2、在 UserDetailsService 设置权限
image.png
没有访问权限
image.png

第二个方法: hasAnyAuthority 方法

如果当前主体有任何提供的权限(给定的作为一个都好分隔符的字符串列表)的话,返回 true
image.png
image.png

第三个方法 :hasRole 方法

如果用户具备给定角色就允许访问,否则出现403
image.png
image.png

第四个方法 :hasAnyRole 方法

只针对多个角色 中间用逗号隔开,具备一个就可以访问
image.png
image.png

3.5 自定义403没有权限访问的页面

  1. // 配置自定义没有权限访问显示403页面
  2. http.exceptionHandling().accessDeniedPage("/unauth.html");

3.6 注解使用

认证授权注解使用

3.6.1 @Secured

  • 判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_”
  • 需要先开启注解功能

用户具有某个角色,可以访问方法
1、启动类上开启注解操作

  1. @EnableGlobalMethodSecurity(securedEnabled = true)
  2. public class Securitydemo1Application {

2、在 controller 方法上面使用注解,设置角色

  1. @GetMapping("/update")
  2. @Secured(value = {"ROLE_sale","ROLE_manager"})
  3. public String update(){
  4. return "hello update";
  5. }

3、在 UserDetailsService 设置用户的角色

  1. List<GrantedAuthority> role =
  2. AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_sale");

3.6.2 @PreAuthorize

  • 开启注解功能:
    • image.png
  • 进入方法前的权限验证,可以将登录用户的 roles/permissions 参数传到方法中

image.png

3.6.3 @PostAuthorize

在方法执行之后进行验证
开启注解功能
image.png

3.6.4 @PostFilter @PreFilter

@PostFilter ——-> 对数据继续宁过滤
@PreFilter ———> 对传入方法的数据进行过滤

  1. @GetMapping("/getall")
  2. @PostFilter("filterObject.username == 'admin1'")
  3. public List<User> getAll(){
  4. List<User> list = new ArrayList<>();
  5. list.add(new User(null,"admin1","123"));
  6. list.add(new User(null,"admin2","456"));
  7. System.out.println(list);
  8. return list;
  9. }

3.7 用户注销

1、在配置类添加退出的配置
2、测试

  • 修改配置类,登陆成功之后跳转到成功页面
    • image.png
  • 在成功页面添加超链接,设置推出路径
    • image.png
  • 登陆成功,在成功页面点击退出,访问其他controller

3.8 基于数据库实现自动登录

1、cookie技术
2、安全框架机制实现自动登录

1、实现原理

第一步:
image.png
第二步:再次访问
获取cookie信息,拿着cookie信息到数据库机型比对,如果查询到对应信息,认证成功,可以登录

详细原理
image.png

2、案例实现

1.创建数据库表格
JdbcTokenRepositoryImpl默认会帮我们创建,其源码sql如下

  1. create table persistent_logins (
  2. username varchar(64) not null,
  3. series varchar(64) primary key,
  4. token varchar(64) not null,
  5. last_used timestamp not null)

2.配置类
注入数据源,配置操作数据库对象

  1. // 注入数据源
  2. @Autowired
  3. private DataSource dataSource;
  4. @Bean
  5. public PersistentTokenRepository persistentTokenRepository(){
  6. JdbcTokenRepositoryImpl jdbcToken = new JdbcTokenRepositoryImpl();
  7. jdbcToken.setDataSource(dataSource);
  8. //jdbcToken.setCreateTableOnStartup(true);
  9. return jdbcToken;
  10. }
  11. .and().rememberMe().tokenRepository(persistentTokenRepository())
  12. .tokenValiditySeconds(60) //设置自动登录有效时长 单位秒
  13. .userDetailsService(userDetailsService)

3.在登录页面添加复选框

  1. <form action="/user/login" method="post">
  2. 用户名:<input type="text" name="username" /><br>
  3. 密码:<input type="password" name="password"/><br>
  4. <input type="checkbox" name="remember-me"><br>
  5. <input type="submit" value="登录">
  6. </form>

3.9 CSRF

跨站请求伪造

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

从Spring Security4.0之后默认开启,它会针对PATCH,POST,PUT,DELETE方法进行保护

实现原理
认证成功后生成csrfToken保存到HttpSession或者Cookie中。每次请求都会带着这个Token 值,利用这个Token值和session中的token值做比较,一样则允许访问
[

](https://blog.csdn.net/qq_38224285/article/details/109288164)