11.2(security)web操作

用户认证

我们在进行认证的时候需要输入账号和密码。如何自定义呢

  1. 配置文件
  2. 配置类
  3. 自定义配置类

配置文件

spring:
  security:
    user:
      name: wsl
      password: 123123 

在这里插入图片描述

配置类

@Configuration
public class configsecurity extends WebSecurityConfigurerAdapter {


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        这里表示设置用户名和密码
//        auth.inMemoryAuthentication().withUser("wsl").password("123").roles("admin");

//        通过密码编码器
        BCryptPasswordEncoder Password = new BCryptPasswordEncoder();
        String encode = password().encode("123");
        System.out.println("密码是:"+encode);
        auth.inMemoryAuthentication().withUser("wsl").password(encode).roles("admin");

    }

    @Bean
    PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }

}

在这里插入图片描述

自定义配置类

我们在实际中应该是通过数据库中读取账号密码的

首先这里我们需要进行数据库操作。就需要数据库和搭建Mybtis-plus。

当然也可以使用其他数据库访问框架

环境搭建

数据库和数据库访问层

数据库
CREATE DATABASE securityTest

CREATE TABLE users 
(id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(255) ,
`password` VARCHAR(255))


INSERT INTO users (username,`password`) VALUES
 ('wsl','123'),
 ('wsm','321')
搭建数据访问层

导入依赖

 <dependencies>

        <!--引入SpringBoot的 web starter依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--引入SpringBoot的   security  starter依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!--数据库需要的jar文件-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>



        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.12</version>
        </dependency>


    </dependencies>
yaml
server:
  port: 8888


spring:
  datasource:
    username: root
    password: ok
    url: jdbc:mysql://localhost:3306/securityTest?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
    driver-class-name: com.mysql.jdbc.Driver

#Mybatis-Plus的配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    # 配置在控制台打印 sql语句
  # 配置自定义sql语句的 *mapper.xml 文件位置
  mapper-locations: classpath:**/mapper/**.xml

实体类

使用lombok,生成get、set

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Component("users")
public class Users {


  @TableId(type = IdType.AUTO)
  private long id;
  private String username;
  private String password;

}

数据访问层

@Mapper
public interface UsersDao extends BaseMapper<Users> {

}

自定义配置类访问数据库

下面开始进行自定义密码的配置类

前面的配置类中指定用户名密码。从而达到登陆的作用。

下面就开始进行改造前面的配置类

修改配置类
@Configuration
public class configsecurity extends WebSecurityConfigurerAdapter {


//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        这里表示设置用户名和密码
        auth.inMemoryAuthentication().withUser("wsl").password("123").roles("admin");
        通过密码编码器
//        BCryptPasswordEncoder Password = new BCryptPasswordEncoder();
//        String encode = password().encode("123");
//        System.out.println("密码是:"+encode);
//        auth.inMemoryAuthentication().withUser("wsl").password(encode).roles("admin");
//
//    }

    @Bean
    PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }

//    这里通过Spring的自定装配引入
//    该类表示的就是用户信息服务   待会会进行编写
//    认证先通过该类获取用户 账号和密码。在传给现在的这个类
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(password());
    }

}

UserDetailsServuce配置类
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {


    @Resource
    private UsersDao usersDao;

    @Override
//    这个方法中存在参数 该参数表示获取认证时候登录的 账号
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//        通过用户名获取用户
        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", s);
        Users users = usersDao.selectOne(queryWrapper);

//        如果没有获取用户就返回异常
        if (users == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }
//        获取用户就将账号密码带入  传入出去
        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
        return new User(users.getUsername(), new BCryptPasswordEncoder().encode(users.getPassword()), auths);
    }
}

目录结构

在这里插入图片描述

测试

在这里插入图片描述

自定义登录页面

上面我们通过配置类,可以进行指定认证的账号和密码

那么下面我们要去指定认证的页面。和相关的配置

环境

首先我们现在操作的都属于web部分

所以我们引入boot-start-web

   <!--引入SpringBoot的 web starter依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

默认页面就可以放入templates目录中了

配置类

 @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        // 配置认证
        httpSecurity.formLogin()
                .loginPage("/index") // 配置哪个 url 为登录页面
                .loginProcessingUrl("/login") // 设置哪个是登录的 url。
                .successForwardUrl("/success") // 登录成功之后跳转到哪个 url
                .failureForwardUrl("/fail");// 登录失败之后跳转到哪个 url

        httpSecurity.authorizeRequests()
                .antMatchers("/layui/**","/index") //表示配置请求路径
                .permitAll() // 指定 URL 无需保护。
                .anyRequest() // 其他请求
                .authenticated(); //需要认证
// 关闭 csrf
        httpSecurity.csrf().disable();
    }

控制器类

@Controller
public class HelloController {

    @RequestMapping("show")
    public String show(){
        return "show";
    }


    @RequestMapping("index")
    public String index(){
        return "index";
    }

    @RequestMapping("success")
    @ResponseBody
    public String successSecurity(){
        return "success";
    }
    @RequestMapping("fail")
    @ResponseBody
    public String failSecurity(){
        return "fail";
    }

    @RequestMapping("layui")
    @ResponseBody
    public String layuiSecurity(){
        return "layui";
    }
    @RequestMapping("other")
    @ResponseBody
    public String otherSecurity(){
        return "other";
    }


}

页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="/login" method="post" >

    <!--这里的name属性一定要是这两个 因为在SpringSecurity底层就是指定之两个 name属性 -->
    账号: <input type="text" name="username" >
    密码: <input type="password" name="password" >

    <button type="submit" >登录</button>
</form>

</body>
</html>

页面提交方式必须为 post 请求

所以上面的页面不能使用,用户名,密码必须为 username,password

在这里插入图片描述

结果

访问不需要认证的页面

在这里插入图片描述

访问需要认证的页面

在这里插入图片描述

会进行跳转到你设置的登录页面url

注意观察URL

在这里插入图片描述

认证之后可以访问

在这里插入图片描述

登录成功

url显示是login。却发现结果是指定的成功url 结果 页面

在这里插入图片描述

登录失败

url显示是login。却发现结果是指定的 失败 url 结果 页面

在这里插入图片描述

发现基本上都是HttpSecurity的API

HttpSecurity

img

方法说明
openidLogin()用于基于 OpenId 的验证
headers()将安全标头添加到响应
cors()配置跨域资源共享 ( CORS )
sessionManagement()允许配置会话管理
portMapper()允许配置一个PortMapper(HttpSecurity#(getSharedObject(class))),其他提供SecurityConfigurer的对象使用 PortMapper 从 HTTP 重定向到 HTTPS 或者从 HTTPS 重定向到 HTTP。默认情况下,Spring Security使用一个PortMapperImpl映射 HTTP 端口8080到 HTTPS 端口8443,HTTP 端口80到 HTTPS 端口443
jee()配置基于容器的预认证。 在这种情况下,认证由Servlet容器管理
x509()配置基于x509的认证
rememberMe允许配置“记住我”的验证
authorizeRequests()允许基于使用HttpServletRequest限制访问
requestCache()允许配置请求缓存
exceptionHandling()允许配置错误处理
securityContext()在HttpServletRequests之间的SecurityContextHolder上设置SecurityContext的管理。 当使用WebSecurityConfigurerAdapter时,这将自动应用
servletApi()将HttpServletRequest方法与在其上找到的值集成到SecurityContext中。 当使用WebSecurityConfigurerAdapter时,这将自动应用
csrf()添加 CSRF 支持,使用WebSecurityConfigurerAdapter时,默认启用
logout()添加退出登录支持。当使用WebSecurityConfigurerAdapter时,这将自动应用。默认情况是,访问URL”/ logout”,使HTTP Session无效来清除用户,清除已配置的任何#rememberMe()身份验证,清除SecurityContextHolder,然后重定向到”/login?success”
anonymous()允许配置匿名用户的表示方法。 当与WebSecurityConfigurerAdapter结合使用时,这将自动应用。 默认情况下,匿名用户将使用org.springframework.security.authentication.AnonymousAuthenticationToken表示,并包含角色 “ROLE_ANONYMOUS”
formLogin()指定支持基于表单的身份验证。如果未指定FormLoginConfigurer#loginPage(String),则将生成默认登录页面
oauth2Login()根据外部OAuth 2.0或OpenID Connect 1.0提供程序配置身份验证
requiresChannel()配置通道安全。为了使该配置有用,必须提供至少一个到所需信道的映射
httpBasic()配置 Http Basic 验证
addFilterAt()在指定的Filter类的位置添加过滤器

用户授权

security主要的两个概念,认证和权限。

认证:表示在进行访问页面前。进行一个登录操作

权限:表示你登录之后你可以进行哪些操作

主要就是在于几个方法的使用

hasAuthority

表示当前的主题具有指定的权限,才能进行访问否存就给出false

示例展示

在这里插入图片描述

 //                这里指定的路径URL表示需要权限
                .antMatchers("/hasAuthorityTest")
//                这里设定权限为admin
                .hasAuthority("admin")

403异常

这里经过认证之后发现出现了403异常

是因为我们没有访问的权限。怎么才能有权限呢

在这里插入图片描述

在这里插入图片描述

在前面我们指定密码的Service类中设置过权限。

//        这里指定权限的
        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");

改变权限查看结果

在这里插入图片描述

HasAnyAuthority

上面的权限,一个请求只能设置一个权限。

该方法表示可以设置多个权限。满足任意一个权限

如何添加多个

在这里插入图片描述

HasRole

通过前面发现如果不能满足授权,在访问的时候将会出现403异常

403:权限不够

那么Role和前面有啥区别呢

对比源码

role的权限会在authority的前面追加字符 ROLE_

Authority
private static String hasAuthority(String authority) {
        return "hasAuthority('" + authority + "')";
    }
role
private static String hasRole(String role) {
        Assert.notNull(role, "role cannot be null");
        if (role.startsWith("ROLE_")) {
            throw new IllegalArgumentException("role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'");
        } else {
            return "hasRole('ROLE_" + role + "')";
        }
    }

操作

配置类

在这里插入图片描述

 //                这里指定的路径URL表示需要权限
                .antMatchers("/hasAuthorityTest")
                                这里设定权限为  admin  但是会在源码中转换为  ROLE_admin
                .hasRole("admin")
service层
 这里指定权限的
        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_admin");

结果于上面一致

自定义403页面

403错误页面:表示因为没有权限不能进行访问

在这里插入图片描述

配置

配置类
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
//        指定当出现403的时候进行的页面跳转 URL
        httpSecurity.exceptionHandling().accessDeniedPage("/unauth");
控制器
 @GetMapping("/unauth")
    public String accessDenyPage(){
        return "unauth";
    }

html
这里自己写吧!

在这里插入图片描述

注解使用

在学习Spring的时候我们就接触了很多注解。当然Security也存在很多注解可以使用

@Secured

判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“。

启动类开启
@EnableGlobalMethodSecurity(securedEnabled=true)
控制器

控制器中指定该URL需要指定的 角色访问

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

@PreAuthorize

与hasAuthorized方法差不多。在URL前进行权限限制

启动类
@EnableGlobalMethodSecurity(prePostEnabled = true)
控制器
@RequestMapping("/preAuthorize")
@ResponseBody
//@PreAuthorize("hasRole('ROLE_管理员')")
@PreAuthorize("hasAnyAuthority('menu:system')")
public String preAuthorize(){
 System.out.println("preAuthorize");
return "preAuthorize";
}

@PostAuthorize

@PostAuthorize 注解使用并不多,在方法执行后再进行权限验证,适合验证带有返回值 的权限.

可以在控制器方法中填入打印语句。没有被授权后,打印语句却执行了

启动类
@EnableGlobalMethodSecurity(prePostEnabled = true)
控制器
@RequestMapping("/testPostAuthorize")
@ResponseBody
@PostAuthorize("hasAnyAuthority('menu:system')")
public String preAuthorize(){
 System.out.println("test--PostAuthorize");
return "PostAuthorize";
}

@PostFilter

权限验证之后对数据进行过滤 留下用户名是 admin1 的数据

@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;
}

@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;
}

用户注销

当我们的认证做完登录之后,在想去注销。如何操作呢

//        表示当进入该URL的时候就退出登录  。退出成功进入 /index请求
        httpSecurity.logout().logoutUrl("/logout").logoutSuccessUrl("/index").permitAll();

List getAllUser(){
ArrayList list = new ArrayList<>();
list.add(new UserInfo(1l,“admin1”,“6666”));
list.add(new UserInfo(2l,“admin2”,“888”));
return list;
}


### @PreFilter

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



**这些都可以通过打印语句进行验证**

```java
@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;
}

用户注销

当我们的认证做完登录之后,在想去注销。如何操作呢

//        表示当进入该URL的时候就退出登录  。退出成功进入 /index请求
        httpSecurity.logout().logoutUrl("/logout").logoutSuccessUrl("/index").permitAll();
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值