IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> springboot集成安全框架springsecurity -> 正文阅读

[Java知识库]springboot集成安全框架springsecurity

注意,在配置过滤器时 每个权限/角色配置操作前面都要写上请求路径
如: .anyRequest() 请求路径
.authenticated()//都需要认证操作 是权限/角色操作

在这里插入图片描述

三种用户认证方式(设置用户名密码的)

第一种:通过配置文件(非查库)

应用添加security依赖后,在application配置文件中写入spring.security.user.name和spring.security.user.password即可,若注入成功 控制台不会报security框架自动生成的初始密码

# 应用名称
spring.application.name=spring-security-smalldemo
# 应用服务 WEB 访问端口
server.port=8080
#设置用户名密码方式一 配置文件
spring.security.user.name=lql
spring.security.user.password=mima

第二种 通过配置类(非查库)

在配置类中编写如下即可

package com.li.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**  设置用户名密码的第二种方式 配置类
 * @author liql
 * @date 2021/9/21
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        //密码需要加密 不然报 Encoded password does not look like BCrypt 错误
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = passwordEncoder.encode("123456");
        //角色不能不设置,不然报错
        auth.inMemoryAuthentication().withUser("lql").password(password).roles("");

    }

    //不注入PasswordEncoder 会报下面的错误
    //java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

第三种 通过实现 UserDetailsService接口设置用户名密码(可查库)

分别定义一个配置类和接口实例类即可,
用户名密码查库操作可定义在该实例中只需要替换返回对象User中的参数为数据库查到的即可。

配置类

package com.li.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**  设置用户名密码的第三种方式 通过实现 userDetailsService 接口
 * @author liql
 * @date 2021/9/21
 */
@Configuration
public class SecurityConfig2 extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

       auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());

    }

    //不注入PasswordEncoder 会报下面的错误
    //java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

用户名密码写死

package com.li.config;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 配置第三种用户密码的方式的实现类  UserDetailsService接口是security框架的
 * @author liql
 * @date 2021/9/21
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //设置权限
        List<GrantedAuthority> authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList("roles");

        //第三个参数为设置权限,不能为空。
        return new User("lql", new BCryptPasswordEncoder().encode("123"), authorityList);
    }
}

通过查库获取用户名对应的密码

参数 username为登录界面输入的用户名,把查库拿到的密码传入到返回值中,security底层会自动将查库的密码与登录界面输入的密码做校验

package com.li.config;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 配置第三种用户密码的方式的实现类  UserDetailsService接口是security框架的
 * @author liql
 * @date 2021/9/21
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
    //定义一个安全类集合模拟数据库
    private static ConcurrentHashMap<String,String> mydb=new ConcurrentHashMap();
    static {
        mydb.put("lql", "111");
        mydb.put("xiaohong", "123");
    }

    /**
     *
     * @param username  该参数为登录界面输入的用户名
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //设置权限
        List<GrantedAuthority> authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList("roles");

        //模拟通过数据库查密码
        String password=mydb.get(username);
        // if(查库没查到){
        //    throw new UsernameNotFoundException("用户名不存在")
        //  }

        //把数据库查到的密码传入进去 security框架底层会帮我们自动做校验 第三个参数为设置权限,不能为空。
        return new User(username, new BCryptPasswordEncoder().encode(password), authorityList);
    }
}

自定义设置登录页面

在原先的配置类中重写 void: configure(HttpSecurity http) 方法

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
    }

重写后

   @Override
    protected void configure(HttpSecurity http) throws Exception {
       http.formLogin().loginPage("/login.html") //登录界面
               .loginProcessingUrl("/user/login") //用户密码需要提交到的路径 该路径由security管理 不需要我们定义
               .defaultSuccessUrl("/test/index")//登录成功后跳转到的页面
               .permitAll()// 无条件允许访问 不校验权限
                .and()
               .authorizeRequests()//后面写认证配置
               .anyRequest() //任何请求
               .authenticated()//都需要认证操作
//               .antMatchers("/","/test/hello").permitAll()  //设置哪些无条件允许访问 但必须先认证然后不校验权限  
               .and()
               .csrf().disable();//关闭csrf防护 关闭跨域保护
    }

添加依赖和配置
spring.thymeleaf.prefix=classpath:/static

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

login.html
页面 username password 参数名是固定的,因为在UsernamePasswordAuthenticationFilter过滤器中明确定义了
在这里插入图片描述

<!DOCTYPE html>
<!-- 需要添加
<html  xmlns:th="http://www.thymeleaf.org">
这样在后面的th标签就不会报错
 -->
<html  xmlns:th="http://www.thymeleaf.org">
<head lang="en">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>xx</title>
</head>
<body>


<h1>表单提交</h1>
<!-- 表单提交用户信息,注意字段的设置,直接是*{} -->
<form action="/user/login"  method="post">
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    <input type="text" name="username" />
    <input type="text" name="password" />
    <input type="submit" />
</form>
</body>
</html>

登录成功跳转页面

    @GetMapping("/index")
    @ResponseBody
    public String index(){

        return "登录成功";
    }

基于权限进行控制

给用户授权

在UserDetailsService的实例类里进行授权

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //设置权限
        List<GrantedAuthority> authorityList =
                AuthorityUtils
                 //该方法   commaSeparatedStringToAuthorityList 技能设置权限又能设置角色,设置角色时加前缀 ROLE_XXX , 多个权限和角色中间用逗号隔开
                .commaSeparatedStringToAuthorityList("perm_hello1,perm_hello2");

        //模拟通过数据库查密码
        String password=mydb.get(username);
        // if(查库没查到){
        //    throw new UsernameNotFoundException("用户名不存在")
        //  }
        //把数据库查到的密码传入进去 security框架底层会帮我们自动做校验 第三个参数为设置权限和角色,不能为空。
        return new User(username, new BCryptPasswordEncoder().encode(password), authorityList);
    }

设置访问路径的权限

在配置类里

    @Override
    protected void configure(HttpSecurity http) throws Exception {
 /*      http.formLogin().loginPage("/login.html") //登录界面
               .loginProcessingUrl("/user/login") //用户密码需要提交到的路径 该路径由security管理 不需要我们定义
               .defaultSuccessUrl("/test/index")//登录成功后跳转到的页面
               .permitAll()// 无条件允许访问 但必须先认证然后不校验权限
                .and()
               .authorizeRequests()//后面写认证配置
               .anyRequest() //任何请求
               .authenticated()//都需要认证操作
//               .antMatchers("/","/test/hello").permitAll()  //设置哪些路径可以不用认证就能访问
               .and()
               .csrf().disable();//关闭csrf防护 关闭跨域保护*/

        http.formLogin().loginPage("/login.html") //登录界面
                .loginProcessingUrl("/user/login") //用户密码需要提交到的路径 该路径由security管理 不需要我们定义
                .defaultSuccessUrl("/test/index")//登录成功后跳转到的页面
                .permitAll()// 无条件允许访问 但必须先认证然后不校验权限
                .and()
                .authorizeRequests()
                .antMatchers("/test/hello")
                .hasAnyAuthority("perm_hello")//满足该权限 ,只能写单个权限
                .antMatchers("/test/hello2")
                //满足下面权限的一个即可放行
                .hasAnyAuthority("perm_hello,perm_hello2")
                .anyRequest() //任何请求
                .authenticated()//都需要认证操作
                .and()
                .csrf().disable();//关闭csrf防护 关闭跨域保护;
    }

基于角色访问

给用户设置角色

与设置权限的地方相同 ,在实例类中 设置权限的地方增加 ROLE_xxx 即可
加“ROLE_”前缀的原因是,在配置过滤器时 如写个角色为 “admin” 但是在底层会校验“ROLE_admin”;
在这里插入图片描述

  List<GrantedAuthority> authorityList =
                AuthorityUtils
                 //该方法   commaSeparatedStringToAuthorityList 技能设置权限又能设置角色,设置角色时加前缀 ROLE_XXX , 多个权限和角色中间用逗号隔开
                        //ROLE_admin 给用户设置 admin角色
                .commaSeparatedStringToAuthorityList("perm_hello1,perm_hello2,ROLE_admin");

给路径设置角色

与设置路径的地方相同 在配置类中
增加

.antMatchers("/test/hello2")
                //满足下面角色的一个即可放行
                .hasRole("admin")
                 .antMatchers("/test/hello3")
                //满足其中的一个角色即可放行
                .hasAnyRole("admin,admin2")
 @Override
    protected void configure(HttpSecurity http) throws Exception {
 /*      http.formLogin().loginPage("/login.html") //登录界面
               .loginProcessingUrl("/user/login") //用户密码需要提交到的路径 该路径由security管理 不需要我们定义
               .defaultSuccessUrl("/test/index")//登录成功后跳转到的页面
               .permitAll()// 无条件允许访问 但必须先认证然后不校验权限
                .and()
               .authorizeRequests()//后面写认证配置
               .anyRequest() //任何请求
               .authenticated()//都需要认证操作
//               .antMatchers("/","/test/hello").permitAll()  //设置哪些路径可以不用认证就能访问
               .and()
               .csrf().disable();//关闭csrf防护 关闭跨域保护*/

        http.formLogin().loginPage("/login.html") //登录界面
                .loginProcessingUrl("/user/login") //用户密码需要提交到的路径 该路径由security管理 不需要我们定义
                .defaultSuccessUrl("/test/index")//登录成功后跳转到的页面
                .permitAll()// 无条件允许访问 但必须先认证然后不校验权限
                .and()
                .authorizeRequests()
                .antMatchers("/test/hello")
                .hasAnyAuthority("perm_hello")//满足该权限 ,只能写单个权限
                .antMatchers("/test/hello2")
                //满足下面权限的一个即可放行
                .hasAnyAuthority("perm_hello,perm_hello2")
                .antMatchers("/test/hello2")
                //满足下面角色的一个即可放行
                .hasRole("admin")
                 .antMatchers("/test/hello3")
                //满足其中的一个角色即可放行
                .hasAnyRole("admin,admin2")
                .anyRequest() //任何请求
                .authenticated()//都需要认证操作
                .and()
                .csrf().disable();//关闭csrf防护 关闭跨域保护;
    }

自定义无权限时的返回页面

依然在配置过滤器的方法中加入 即可 页面
在这里插入图片描述

  //设置无权限时返回的页面
        http.exceptionHandling().accessDeniedPage("/test/unauthen");
   @GetMapping("/unauthen")
    @ResponseBody
    public String unauthen(){
        return "无权访问";
    }

退出登录

在配置类中加上如下配置即可
在这里插入图片描述

 //配置退出
        http.logout()
                .logoutUrl("/logout") //输入该url表示退出
                .logoutSuccessUrl("/test/logout")//成功退出后跳转的页面
                .permitAll();

基于注解配置

自动登录

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-22 14:31:58  更:2021-09-22 14:32:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:43:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码