eyb:SpringSecurity的使用(四)


目录:

(1)secured注解进行角色控制

(2)PreAuthorize注解 PostAutothorize

(3)RememberME功能

(4)在Thymeleaf中获取属性值

(5)Thymeleaf中进行权限的判断 

(6)退出登录

 (7)SpringSecurity中的csrf


 

(1)secured注解进行角色控制

原来的权限判断是在SecurityConfig配置类中判断的,现在可以使用注解来判断

 

 主启动类:加上注解开启SpringSecurity权限注解,因为SpringSecurity的权限注解默认是关闭的

package com.xxxx.springsecuritydemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;

@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SpringsecuritydemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringsecuritydemoApplication.class, args);
    }

}

package com.xxxx.springsecuritydemo.service;

import org.springframework.beans.factory.annotation.Autowired;
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.password.PasswordEncoder;
import org.springframework.stereotype.Service;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private PasswordEncoder pw;

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

        //1.查询数据库判断用户名是否存在,如果不存在就会抛出UsernameNotFoundException异常

        //这里进行模拟,用户名为admin
        if (!"admin".equals(username)) {
            throw new UsernameNotFoundException("用户名不存在");
        }
        //2.//如果存在,把查询出来的密码(注册时已经经过加密) 进行解析,或者直接把密码放到构造方法

        String password=pw.encode("123");
        return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normall,ROLE_abc,/main.html"));
    }
}

 

LoginController:方法上加注解要和 上面的角色相对应:这里ROLE_  是不能少的

package com.xxxx.springsecuritydemo.controller;

import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class LoginController {

    /*@RequestMapping("login")
    public String login(){
        System.out.println("执行登录方法");
        return "redirect:main.html";
    }*/

    //页面登录成功跳转
    @Secured("ROLE_abc") //角色注解
    @RequestMapping("toMain")
    public String toMain(){
        return "redirect:main.html";
    }

    //跳转登录失败页面
    @RequestMapping("toError")
    public String toError(){
        return "redirect:error.html";
    }

    @GetMapping("demo")
    @ResponseBody
    public String demo(){
        return "demo";
    }
}

配置类的角色判断权限是注释掉的,不使用配置类来进行权限判断,使用注解方式

package com.xxxx.springsecuritydemo.config;

import com.xxxx.springsecuritydemo.handle.MyAccessDeniedHandler;
import com.xxxx.springsecuritydemo.handle.MyAuthenticationFailureHandler;
import com.xxxx.springsecuritydemo.handle.MyAuthenticationSucessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //引用403处理这个类
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    //自定义登录页面,不使用自带的
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //表单提交
        http.formLogin()
                //和Login中input的属性相对应
                .usernameParameter("username1")
                .passwordParameter("password1")
                //当发现是 /login是认为是登录,必须和表单提交的地址一样,去执行UserDetailsServiceImpl登录逻辑
                .loginProcessingUrl("/login")
                //自定义登录页面
                .loginPage("/login.html")
                //登录成功之后跳转页面,必须是Post请求
                .successForwardUrl("/toMain")
                //登录成功后的处理器,不能和sucessForwardUrl共存
                //.successHandler(new MyAuthenticationSucessHandler("/main.html"))

                //登录失败跳转页面,Post请求
                .failureForwardUrl("/toError");
                //登录失败后的处理器,不能和failureForwardUrl共存
                //.failureHandler(new MyAuthenticationFailureHandler("/error.html"));

        //授权认证 相当于拦截器一样
        http.authorizeRequests()
                //error.html不需要被认证
                .antMatchers("/error.html").permitAll()
                //login.html不需要被认证
                .antMatchers("/login.html").permitAll()
                //resources目录下的静态资源
                .antMatchers("/static/js/**", "/static/css/**", "/static/images/**").permitAll()

                //regexMatchers放行的使用
                //.regexMatchers(".+[.]png").permitAll()
                //.regexMatchers(HttpMethod.GET,"/demo").permitAll()

                //.mvcMatchers("/demo").servletPath("/xxxx").permitAll()
                //如果不习惯mvcMatchers还可以用antMatchers设置等效
                .antMatchers("/xxxx/demo").permitAll()
                //任何目录下的png图片
                //.antMatchers("/**/*.png").permitAll()


                //判断用户是否有admin权限
                //.antMatchers("/main1.html").hasAuthority("admin")
                //可以设置这个页面,多个权限去访问
                //.antMatchers("/main1.html").hasAnyAuthority("admin","normall")

                //角色判断
                //.antMatchers("/main1.html").hasRole("abc")
                //判断有多个角色权限
                //.antMatchers("/main1.html").hasAnyRole("abc,abC")

                //IP地址判断
                //.antMatchers("/main1.html").hasIpAddress("127.0.0.1")

                //所有请求都必须被认证,必须登录之后能被访问
                .anyRequest().authenticated();
                //自定义访问权限
                //.anyRequest().access("@myServiceImpl.hasPermission(request,authentication)");

        //关闭csrf防护
        http.csrf().disable();


        //异常处理
        http.exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler);
    }

    //创建PasswordEncoder实例
    @Bean
    public PasswordEncoder getPw(){
        return new BCryptPasswordEncoder();
    }
}

 

 如果角色写的是abc:

会报500: 

 

 

 (2)PreAuthorize注解 PostAutothorize

 主启动类添加注解:prePostEnabled

package com.xxxx.springsecuritydemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;

@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class SpringsecuritydemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringsecuritydemoApplication.class, args);
    }

}

LoginControiller:注释掉@Secured注解,使用@PreAuthorize 进行角色判断

package com.xxxx.springsecuritydemo.controller;

import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class LoginController {

    /*@RequestMapping("login")
    public String login(){
        System.out.println("执行登录方法");
        return "redirect:main.html";
    }*/

    //页面登录成功跳转
    //@Secured("ROLE_abc") //角色注解
    @PreAuthorize("hasRole('abc')") //PreAuthorize参数是权限表达式 hasRole('ROLE_abc')允许ROLE_开头,配置类不允许,区分大小写
    @RequestMapping("toMain")
    public String toMain(){
        return "redirect:main.html";
    }

    //跳转登录失败页面
    @RequestMapping("toError")
    public String toError(){
        return "redirect:error.html";
    }

    @GetMapping("demo")
    @ResponseBody
    public String demo(){
        return "demo";
    }
}

这个注解是在方法或类执行之前判断权限

 

 (3)RememberME功能

 配置文件:application.properties

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url= jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456

#若出现循环依赖加上没有出现不用
#spring.main.allow-circular-references=true

配置类:SecurityConfig:

 

 

 

package com.xxxx.springsecuritydemo.config;

import com.xxxx.springsecuritydemo.handle.MyAccessDeniedHandler;
import com.xxxx.springsecuritydemo.handle.MyAuthenticationFailureHandler;
import com.xxxx.springsecuritydemo.handle.MyAuthenticationSucessHandler;
import com.xxxx.springsecuritydemo.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //引用403处理这个类
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;



    //自定义登录页面,不使用自带的
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //表单提交
        http.formLogin()
                //和Login中input的属性相对应
                .usernameParameter("username1")
                .passwordParameter("password1")
                //当发现是 /login是认为是登录,必须和表单提交的地址一样,去执行UserDetailsServiceImpl登录逻辑
                .loginProcessingUrl("/login")
                //自定义登录页面
                .loginPage("/login.html")
                //登录成功之后跳转页面,必须是Post请求
                .successForwardUrl("/toMain")
                //登录成功后的处理器,不能和sucessForwardUrl共存
                //.successHandler(new MyAuthenticationSucessHandler("/main.html"))

                //登录失败跳转页面,Post请求
                .failureForwardUrl("/toError");
                //登录失败后的处理器,不能和failureForwardUrl共存
                //.failureHandler(new MyAuthenticationFailureHandler("/error.html"));

        //授权认证 相当于拦截器一样
        http.authorizeRequests()
                //error.html不需要被认证
                .antMatchers("/error.html").permitAll()
                //login.html不需要被认证
                .antMatchers("/login.html").permitAll()
                //resources目录下的静态资源
                .antMatchers("/static/js/**", "/static/css/**", "/static/images/**").permitAll()

                //regexMatchers放行的使用
                //.regexMatchers(".+[.]png").permitAll()
                //.regexMatchers(HttpMethod.GET,"/demo").permitAll()

                //.mvcMatchers("/demo").servletPath("/xxxx").permitAll()
                //如果不习惯mvcMatchers还可以用antMatchers设置等效
                .antMatchers("/xxxx/demo").permitAll()
                //任何目录下的png图片
                //.antMatchers("/**/*.png").permitAll()


                //判断用户是否有admin权限
                //.antMatchers("/main1.html").hasAuthority("admin")
                //可以设置这个页面,多个权限去访问
                //.antMatchers("/main1.html").hasAnyAuthority("admin","normall")

                //角色判断
                //.antMatchers("/main1.html").hasRole("abc")
                //判断有多个角色权限
                //.antMatchers("/main1.html").hasAnyRole("abc,abC")

                //IP地址判断
                //.antMatchers("/main1.html").hasIpAddress("127.0.0.1")

                //所有请求都必须被认证,必须登录之后能被访问
                .anyRequest().authenticated();
                //自定义访问权限
                //.anyRequest().access("@myServiceImpl.hasPermission(request,authentication)");

        //关闭csrf防护
        http.csrf().disable();


        //异常处理
        http.exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler);


        //记住我
        http.rememberMe()
                //失效时间,单位秒
                .tokenValiditySeconds(60)
                //可以更改login.html中的remember-me
                //.rememberMeParameter("remember1")
                //自定义登录逻辑
                .userDetailsService(userDetailsService)
                //持久层对象
                .tokenRepository(persistentTokenRepository);
    }


    //创建PasswordEncoder实例
    @Bean
    public PasswordEncoder getPw(){
        return new BCryptPasswordEncoder();
    }


    //连接对象
    @Bean
    public PersistentTokenRepository getPersistentTokenResposity(){
        JdbcTokenRepositoryImpl jdbcTokenRepository=new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //自动建表 第一个启动自动建表 第二次启动注释掉
       // jdbcTokenRepository.setCreateTableOnStartup(true);

        return jdbcTokenRepository;

    }
}

Login.html:添加checkbox按钮

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   <form action="/login" method="post">
       用户名:<input type="text" name="username1"/><br>
       密码:<input type="text" name="password1"/><br>
       记住我:<input type="checkbox" name="remember-me" value="true"><br>
       <input type="submit" value="登录"/>
   </form>
</body>
</html>

启动主启动类:会帮助我们生成一张表

 

 

 点击登录之后:

关闭浏览器输入:main.html就可以进来了,不用在进行登录,这就是记住我的功能

 

 他默认的失效时间为两周,我们可以自定义失效时间

 

(4)在Thymeleaf中获取属性值

什么是Thymeleaf?

Thymeleaf是一个现代服务器端Java模板引擎,适用于Web和独立环境,能够处理HTML,XML,JavaScript,CSS甚至纯文本。

Thymeleaf的主要目标是提供一种优雅且高度可维护的模板创建方式。为实现这一目标,它以自然模板的概念为基础,将其逻辑注入模板文件,其方式不会影响模板被用作设计原型。这改善了设计沟通,缩小了设计和开发团队之间的差距。

Thymeleaf也从一开始就设计了Web标准-特别是HTML5-允许您创建完全验证的模板,如果您需要的话。

 

 

 

 demo.html:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登录账号:<span sec:authentication="name"></span><br>
登录账号:<span sec:authentication="principal.username"></span><br>
凭证:<span sec:authentication="credentials"></span><br>
权限和角色:<span sec:authentication="authorities"></span><br>
客户端地址:<span sec:authentication="details.remoteAddress"></span><br>
sessionId:<span sec:authentication="details.sessionId"></span><br>
</body>
</html>

LoginController:加入访问demo的方法:

package com.xxxx.springsecuritydemo.controller;

import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class LoginController {

    /*@RequestMapping("login")
    public String login(){
        System.out.println("执行登录方法");
        return "redirect:main.html";
    }*/

    //页面登录成功跳转
    //@Secured("ROLE_abc") //角色注解
    @PreAuthorize("hasRole('abc')") //PreAuthorize参数是权限表达式 hasRole('ROLE_abc')允许ROLE_开头,配置类不允许,区分大小写
    @RequestMapping("toMain")
    public String toMain(){
        return "redirect:main.html";
    }

    //跳转登录失败页面
    @RequestMapping("toError")
    public String toError(){
        return "redirect:error.html";
    }

    //Thymeleaf页面跳转
    @RequestMapping("demo")
    public String demo(){
        return "demo";
    }
}

运行项目:

 

在访问demo: 

 

(5)Thymeleaf中进行权限的判断 

Thymeleaf除了可以获取SpringSecurity的一些属性,还可以进行权限的判断 

在自定义逻辑类中添加权限:

package com.xxxx.springsecuritydemo.service;

import org.springframework.beans.factory.annotation.Autowired;
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.password.PasswordEncoder;
import org.springframework.stereotype.Service;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private PasswordEncoder pw;

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

        //1.查询数据库判断用户名是否存在,如果不存在就会抛出UsernameNotFoundException异常

        //这里进行模拟,用户名为admin
        if (!"admin".equals(username)) {
            throw new UsernameNotFoundException("用户名不存在");
        }
        //2.//如果存在,把查询出来的密码(注册时已经经过加密) 进行解析,或者直接把密码放到构造方法

        String password=pw.encode("123");
        return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normall,ROLE_abc," +
                "/main.html,/insert,/delete"));
    }
}

demo.htmll:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登录账号:<span sec:authentication="name"></span><br>
登录账号:<span sec:authentication="principal.username"></span><br>
凭证:<span sec:authentication="credentials"></span><br>
权限和角色:<span sec:authentication="authorities"></span><br>
客户端地址:<span sec:authentication="details.remoteAddress"></span><br>
sessionId:<span sec:authentication="details.sessionId"></span><br>


<br>
通过权限判断:
<button sec:authorize="hasAuthority('/insert')">新增</button>
<button sec:authorize="hasAuthority('/delete')">删除</button>
<button sec:authorize="hasAuthority('/update')">修改</button>
<button sec:authorize="hasAuthority('/select')">查看</button>
<br>
通过角色判断:
<button sec:authorize="hasRole('abc')">新增</button>
<button sec:authorize="hasRole('abc')">删除</button>
<button sec:authorize="hasRole('abc')">修改</button>
<button sec:authorize="hasRole('abc')">查看</button>

</body>
</html>

在访问demo:

 

发现登录的用户有delete、insert权限,新增删除按钮全都显示出来

登录用户有abc角色,所以按钮全部显示 

 

实际项目中有很多种实现的方式,这只是一种,通过这种实现方式,我们可以控制,那些按钮被哪些权限,哪些角色可以去使用,这就是Thymeleaf通过SpringSecurity通过权限的判断

(6)退出登录

Login.html:添加a连接

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  登录成功!!!!
  <a href="/logout">退出</a>
  <a href="/main1.html">跳转</a>

</body>
</html>

 

 

点击退出:退出到登录页面后,地址栏会带一个logout的参数 

 如果不想带logout的参数需要在配置类中进行设置:

 

package com.xxxx.springsecuritydemo.config;

import com.xxxx.springsecuritydemo.handle.MyAccessDeniedHandler;
import com.xxxx.springsecuritydemo.handle.MyAuthenticationFailureHandler;
import com.xxxx.springsecuritydemo.handle.MyAuthenticationSucessHandler;
import com.xxxx.springsecuritydemo.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //引用403处理这个类
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;



    //自定义登录页面,不使用自带的
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //表单提交
        http.formLogin()
                //和Login中input的属性相对应
                .usernameParameter("username1")
                .passwordParameter("password1")
                //当发现是 /login是认为是登录,必须和表单提交的地址一样,去执行UserDetailsServiceImpl登录逻辑
                .loginProcessingUrl("/login")
                //自定义登录页面
                .loginPage("/login.html")
                //登录成功之后跳转页面,必须是Post请求
                .successForwardUrl("/toMain")
                //登录成功后的处理器,不能和sucessForwardUrl共存
                //.successHandler(new MyAuthenticationSucessHandler("/main.html"))

                //登录失败跳转页面,Post请求
                .failureForwardUrl("/toError");
                //登录失败后的处理器,不能和failureForwardUrl共存
                //.failureHandler(new MyAuthenticationFailureHandler("/error.html"));

        //授权认证 相当于拦截器一样
        http.authorizeRequests()
                //error.html不需要被认证
                .antMatchers("/error.html").permitAll()
                //login.html不需要被认证
                .antMatchers("/login.html").permitAll()
                //resources目录下的静态资源
                .antMatchers("/static/js/**", "/static/css/**", "/static/images/**").permitAll()

                //regexMatchers放行的使用
                //.regexMatchers(".+[.]png").permitAll()
                //.regexMatchers(HttpMethod.GET,"/demo").permitAll()

                //.mvcMatchers("/demo").servletPath("/xxxx").permitAll()
                //如果不习惯mvcMatchers还可以用antMatchers设置等效
                .antMatchers("/xxxx/demo").permitAll()
                //任何目录下的png图片
                //.antMatchers("/**/*.png").permitAll()


                //判断用户是否有admin权限
                //.antMatchers("/main1.html").hasAuthority("admin")
                //可以设置这个页面,多个权限去访问
                //.antMatchers("/main1.html").hasAnyAuthority("admin","normall")

                //角色判断
                //.antMatchers("/main1.html").hasRole("abc")
                //判断有多个角色权限
                //.antMatchers("/main1.html").hasAnyRole("abc,abC")

                //IP地址判断
                //.antMatchers("/main1.html").hasIpAddress("127.0.0.1")

                //所有请求都必须被认证,必须登录之后能被访问
                .anyRequest().authenticated();
                //自定义访问权限
                //.anyRequest().access("@myServiceImpl.hasPermission(request,authentication)");

        //关闭csrf防护
        http.csrf().disable();


        //异常处理
        http.exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler);


        //记住我
        http.rememberMe()
                //失效时间,单位秒
                .tokenValiditySeconds(60)
                //可以更改login.html中的remember-me
                //.rememberMeParameter("remember1")
                //自定义登录逻辑
                .userDetailsService(userDetailsService)
                //持久层对象
                .tokenRepository(persistentTokenRepository);

        //退出登录
        http.logout()
                //退出登录跳转页面
                .logoutSuccessUrl("/login.html");
    }


    //创建PasswordEncoder实例
    @Bean
    public PasswordEncoder getPw(){
        return new BCryptPasswordEncoder();
    }


    //连接对象
    @Bean
    public PersistentTokenRepository getPersistentTokenResposity(){
        JdbcTokenRepositoryImpl jdbcTokenRepository=new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //自动建表 第一个启动自动建表 第二次启动注释掉
       // jdbcTokenRepository.setCreateTableOnStartup(true);

        return jdbcTokenRepository;

    }
}

点击退出登录: 

 

 (7)SpringSecurity中的csrf

我们加了csrf的防护,但是为什么一定要关闭csrf的防护呢? 

 

使用Thymeleaf的Login:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   <form action="/login" method="post">
       <input type="hidden" th:value="${_csrf.token}" name="_csrf" th:if="${_csrf}">
       用户名:<input type="text" name="username1"/><br>
       密码:<input type="text" name="password1"/><br>
       记住我:<input type="checkbox" name="remember-me" value="true"><br>
       <input type="submit" value="登录"/>
   </form>
</body>
</html>

 配置类:更改自定义登录页面,关闭csrf,认证权限

 

 

 

package com.xxxx.springsecuritydemo.config;

import com.xxxx.springsecuritydemo.handle.MyAccessDeniedHandler;
import com.xxxx.springsecuritydemo.handle.MyAuthenticationFailureHandler;
import com.xxxx.springsecuritydemo.handle.MyAuthenticationSucessHandler;
import com.xxxx.springsecuritydemo.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //引用403处理这个类
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;



    //自定义登录页面,不使用自带的
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //表单提交
        http.formLogin()
                //和Login中input的属性相对应
                .usernameParameter("username1")
                .passwordParameter("password1")
                //当发现是 /login是认为是登录,必须和表单提交的地址一样,去执行UserDetailsServiceImpl登录逻辑
                .loginProcessingUrl("/login")
                //自定义登录页面
                .loginPage("/showLogin")
                //登录成功之后跳转页面,必须是Post请求
                .successForwardUrl("/toMain")
                //登录成功后的处理器,不能和sucessForwardUrl共存
                //.successHandler(new MyAuthenticationSucessHandler("/main.html"))

                //登录失败跳转页面,Post请求
                .failureForwardUrl("/toError");
                //登录失败后的处理器,不能和failureForwardUrl共存
                //.failureHandler(new MyAuthenticationFailureHandler("/error.html"));

        //授权认证 相当于拦截器一样
        http.authorizeRequests()
                //error.html不需要被认证
                .antMatchers("/error.html").permitAll()
                //login.html不需要被认证
                .antMatchers("/showLogin").permitAll()
                //resources目录下的静态资源
                .antMatchers("/static/js/**", "/static/css/**", "/static/images/**").permitAll()

                //regexMatchers放行的使用
                //.regexMatchers(".+[.]png").permitAll()
                //.regexMatchers(HttpMethod.GET,"/demo").permitAll()

                //.mvcMatchers("/demo").servletPath("/xxxx").permitAll()
                //如果不习惯mvcMatchers还可以用antMatchers设置等效
                .antMatchers("/xxxx/demo").permitAll()
                //任何目录下的png图片
                //.antMatchers("/**/*.png").permitAll()


                //判断用户是否有admin权限
                //.antMatchers("/main1.html").hasAuthority("admin")
                //可以设置这个页面,多个权限去访问
                //.antMatchers("/main1.html").hasAnyAuthority("admin","normall")

                //角色判断
                //.antMatchers("/main1.html").hasRole("abc")
                //判断有多个角色权限
                //.antMatchers("/main1.html").hasAnyRole("abc,abC")

                //IP地址判断
                //.antMatchers("/main1.html").hasIpAddress("127.0.0.1")

                //所有请求都必须被认证,必须登录之后能被访问
                .anyRequest().authenticated();
                //自定义访问权限
                //.anyRequest().access("@myServiceImpl.hasPermission(request,authentication)");

        //关闭csrf防护
        //http.csrf().disable();


        //异常处理
        http.exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler);


        //记住我
        http.rememberMe()
                //失效时间,单位秒
                .tokenValiditySeconds(60)
                //可以更改login.html中的remember-me
                //.rememberMeParameter("remember1")
                //自定义登录逻辑
                .userDetailsService(userDetailsService)
                //持久层对象
                .tokenRepository(persistentTokenRepository);

        //退出登录
        http.logout()
                //退出登录跳转页面
                .logoutSuccessUrl("/login.html");
    }


    //创建PasswordEncoder实例
    @Bean
    public PasswordEncoder getPw(){
        return new BCryptPasswordEncoder();
    }


    //连接对象
    @Bean
    public PersistentTokenRepository getPersistentTokenResposity(){
        JdbcTokenRepositoryImpl jdbcTokenRepository=new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //自动建表 第一个启动自动建表 第二次启动注释掉
       // jdbcTokenRepository.setCreateTableOnStartup(true);

        return jdbcTokenRepository;

    }
}

 

 

这个csrf是服务器端自动生成的,在学习阶段我们都是关闭csrf,在正是工作中,我们都是不关闭,都是取到服务器中生成的token,访问的时候带回服务器端,服务器会判断你带回的tocken和生成的tocken是否一致,如果一致就让你访问,不一致就不让你访问

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喵俺第一专栏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值