SpringSecurity Web权限方案实现全过程

 更新时间:2024年01月31日 09:48:33   作者:zoeil  
Spring Security是一个功能强大且高度可定制的身份验证和授权框架,专门用于保护Java应用程序的Web集成,下面这篇文章主要给大家介绍了关于SpringSecurity Web权限方案实现的相关资料,需要的朋友可以参考下

一、设置登录系统的账号、密码

方式一,配置文件application.properties

spring.security.user.name=lucy
spring.security.user.password=123

方式二,编写配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String password = bCryptPasswordEncoder.encode("123");
        auth.inMemoryAuthentication().withUser("zhangsan").password(password).roles("admin");
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

方式三,通过类实现接口UserDetailService

@Service
public class userDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException 
        List<GrantedAuthority> list = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
        return new User("zhangsan", new BCryptPasswordEncoder().encode("123"), list);
    }
}

二、数据库查询用户名密码

引入依赖

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>

建表sql

create table users(
    id bigint primary key auto_increment,
    username varchar(20) unique not null,
    password varchar(100)
);

数据源配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/demo?serverTimezone= GMT%2B8
    username: root
    password: 123456

实体类users

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Users {
    private Integer id;
    private String username;
    private String password;
}

mapper

@Mapper
public interface UserMapper extends BaseMapper<Users> {
}

修改userDetailService

@Service
public class userDetailsService implements UserDetailsService {

    @Autowired
    UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        // 使用mapper查询数据库
        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", s);
        Users users = userMapper.selectOne(queryWrapper);
        if (users == null) {
            throw new UsernameNotFoundException("用户名不存在!");
        }

        List<GrantedAuthority> list = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
        return new User(users.getUsername(), new BCryptPasswordEncoder().encode(users.getPassword()), list);

    }
}

修改SecurityConfigTest 

@Configuration
public class SecurityConfigTest extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

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

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

三、自定义登录页面

在配置类SpringSecurity中重写configure方法

    @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防护
    }

再编写登录页面

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

    <form action="/user/login" method="post">
        用户名:<input type="text" name="username"/>
        <br/>
        密码:<input type="password" name="password"/><br/>
        <input type="submit" value="login"/>
    </form>
</body>
</html>

controlller

@RestController
@RequestMapping("/test")
public class HelloController {

    @GetMapping("/hello")
    public String test() {
        return "hello, security";
    }
    @GetMapping("/index")
    public String index() {
        return "hello, index";
    }
}

启动项目后使用的登录页面就是我们编写的 了

四、基于角色或权限进行访问控制

(一)hasAuthority 方法

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

设置访问/test/index需要admin角色

给用户添加admin角色 

 修改角色为别的,不是admin后访问被禁止

(二)hasAnyAuthority 方法

如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回 true.

(三)hasRole 方法

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

如果当前主体具有指定的角色,则返回 true 。

底层源码:

 给用户添加角色需要加上前缀ROLE_

修改配置文件:

注意配置文件中不需要添加” ROLE_ “,因为上述的底层代码会自动添加与之进行匹配。

(四)hasAnyRole

表示用户具备任何一个条件都可以访问。

给用户添加角色:

修改配置文件:

五、自定义403页面 

在配置类中配置

编写unauth页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>没有访问权限</h1>
</body>
</html>

 跳转成功

六、注解使用

(一)@Secured

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

使用注解先要开启注解功能!

@EnableGlobalMethodSecurity(securedEnabled=true)

@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled=true)
    public class DemosecurityApplication {
    public static void main(String[] args) {
         SpringApplication.run(DemosecurityApplication.class, args);
    }
}

 controller

    @GetMapping("/update")
    @Secured({"ROLE_admin"})
    public String update() {
        return "hello, update";
    }

(二)@PreAuthorize

先开启注解功能:

@EnableGlobalMethodSecurity (prePostEnabled = true )

@PreAuthorize:注解适合进入方法前的权限验证, @PreAuthorize 可以将登录用户的 roles/permissions 参数传到方法中。

    @GetMapping("/update")
    @PreAuthorize("hasAnyAuthority('admin')")
    public String update() {
        return "hello, update";
    }

(三)@PostAuthorize

先开启注解功能:

@EnableGlobalMethodSecurity (prePostEnabled = true )

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

@RequestMapping("/testPostAuthorize")
@ResponseBody
@PostAuthorize("hasAnyAuthority('admin')")
public String preAuthorize(){
     System.out.println("test--PostAuthorize");
     return "PostAuthorize";
}

(四)@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;
}

(五)@PostFilter

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

表达式中的 filterObject 引用的是方法返回值 List 中的某一个元素

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

七、基于数据库的记住我

使用spring security记住登录的用户原理

创建表

CREATE TABLE `persistent_logins` (
 `username` varchar(64) NOT NULL,
 `series` varchar(64) NOT NULL,
 `token` varchar(64) NOT NULL,
 `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP,
 PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

配置文件编写数据库的配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/demo?serverTimezone= GMT%2B8
    username: root
    password: 123456

配置类

默认 2 周时间。但是可以通过设置状态有效时间,即使项目重新启动下次也可以正常登录。

页面添加记住我复选框,此处: name 属性值必须为  remember-me. 不能改为其他值

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

    <form action="/user/login" method="post">
        用户名:<input type="text" name="username"/>
        <br/>
        密码:<input type="password" name="password"/><br/>
        <input type="checkbox" name="remember-me"/>60s内免登录<br/>
        <input type="submit" value="login"/>
    </form>
</body>
</html>

八、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 方法进行防护。

总结

到此这篇关于SpringSecurity Web权限方案实现的文章就介绍到这了,更多相关SpringSecurity Web权限内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Java分布式系统中一致性哈希算法

    详解Java分布式系统中一致性哈希算法

    这篇文章主要介绍了Java分布式系统中一致性哈希算法,对算法感兴趣的同学,可以参考下
    2021-04-04
  • MyBatis框架搭建与代码解读分析

    MyBatis框架搭建与代码解读分析

    MyBatis是一个灵活的持久层框架,适合与数据库交互,支持自定义SQL和高级映射,这篇文章给大家介绍MyBatis框架搭建与代码解读,感兴趣的朋友跟随小编一起看看吧
    2024-08-08
  • java同步开篇入门简单介绍

    java同步开篇入门简单介绍

    java中的CountDownLatch、Semaphore、CyclicBarrier这些类又不属于锁,它们和锁又有很多共同点,都是为了协同多线程的执行,都是一种同步器,所以这里就借用同步来取名字了,也就是“同步系列”的来源。下面小编来简单介绍下
    2019-05-05
  • Spring项目中使用Junit单元测试并配置数据源的操作

    Spring项目中使用Junit单元测试并配置数据源的操作

    这篇文章主要介绍了Spring项目中使用Junit单元测试并配置数据源的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Fluent MyBatis实现动态SQL

    Fluent MyBatis实现动态SQL

    MyBatis 令人喜欢的一大特性就是动态 SQL。本文主要介绍了Fluent MyBatis实现动态SQL,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • Java多维数组详解

    Java多维数组详解

    大家好,本篇文章主要讲的是Java多维数组详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • Java类的加载时机

    Java类的加载时机

    这篇文章介绍了Java类的加载时机,文中通过示例代码介绍的非常详细。对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-12-12
  • java使用链表实现约瑟夫环

    java使用链表实现约瑟夫环

    这篇文章主要为大家详细介绍了java使用链表实现约瑟夫环,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • java基于netty NIO的简单聊天室的实现

    java基于netty NIO的简单聊天室的实现

    这篇文章主要介绍了java基于netty NIO的简单聊天室的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • SpringBoot集成Devtools实现热更新

    SpringBoot集成Devtools实现热更新

    DevTools是开发者工具集,主要用于简化开发过程中的热部署问题,热部署是指在开发过程中,当代码发生变化时,无需手动重启应用,系统能够自动检测并重新加载修改后的代码,本文给大家介绍了SpringBoot集成Devtools实现热更新,需要的朋友可以参考下
    2024-08-08

最新评论