springsecurity复习

springsecurity

新建springboot项目

1.导入依赖

 <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.20version>
        dependency>
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <version>3.0.5version>
        dependency>
        <dependency>
            <groupId>org.thymeleafgroupId>
            <artifactId>thymeleaf-spring5artifactId>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>
        <dependency>
            <groupId>org.thymeleaf.extrasgroupId>
            <artifactId>thymeleaf-extras-java8timeartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
        dependency>


    dependencies>

2.application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/textnode?serverTimeZone=UTC&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

3. entity层

//和数据库字段一样
@Data
@TableName("tian")
public class UserLogin {
    @TableId(type = IdType.AUTO)
    private int id;

    private String name;

    private String password;
}

4.dao层

@Mapper
@Repository
public interface UserMapper extends BaseMapper<UserLogin> {
}

5.service层

public interface UserService extends IService<UserLogin> {
}



@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserLogin> implements UserService {
}

6.controller层

package com.example.springsecuritydemo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Controller
public class LoginController {
//    @RequestMapping("/login")
//    public String login(){
//        return "redirect:main.html";
//    }

    @RequestMapping("/toMain")
    public String toMain(){
        return "redirect:main.html";
    }

    @RequestMapping("/toError")
    public String toError(){
        return "redirect:error.html";
    }
}

config

package com.example.springsecuritydemo.config;

import com.example.springsecuritydemo.handle.MyAuthenticationFailHandle;
import com.example.springsecuritydemo.handle.MyAuthenticationSuccessHandle;
import com.example.springsecuritydemo.service.UserDetailServiceImpl;
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.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 {

    @Autowired
    private UserDetailServiceImpl userDetailService;
/*
    // 没有加此段代码 数据库密码如果是明文,UserDetailServiceImpl传入的明文密码登录不进去,加了就可以或者 UserDetailServiceImpl传入的密码是经过加密返回User对象就可以登录成功
    
   @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService).passwordEncoder(getPw()); //注释掉原本从内存中加载用户的代码。 }
    }
*/
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
//         .usernameParameter("username123")//自定义入参和前端的name属性一样
//         .passwordParameter("password123")//自定义入参
                .loginPage("/login.html") //自定义登录页面
                .loginProcessingUrl("/login")//必须和表单提交的接口一样,回去执行自定义登录逻辑
//        .successForwardUrl("/toMain")//登录成功后跳转的页面 POST请求
                //前后端分离 跳转不归我们管 编写handle.MyAuthenticationSuccessHandle
                .successHandler(new MyAuthenticationSuccessHandle("http://www.baidu.com"))
//        .failureForwardUrl("/toError") //登录失败后跳转的页面 POST请求
                .failureHandler(new MyAuthenticationFailHandle("/error.html"))//自定义登陆失败处理器
        ;

        //授权
        http.authorizeRequests()
            	//放行 不用登录
                .antMatchers("/login.html").permitAll()
            //放行 不用登录
                .antMatchers("/error.html").permitAll()
                //拦截所有请求
                .anyRequest().authenticated();

        //防止网站攻击
        http.csrf().disable();//登录失败可能存在的原因

    }

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

}

UserDetailServiceImpl

package com.example.springsecuritydemo.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.springsecuritydemo.entity.UserLogin;
import com.example.springsecuritydemo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

@Service
public class UserDetailServiceImpl implements UserDetailsService{
//    @Autowired
//    UserService service;
    @Autowired
    UserMapper mapper;
    @Autowired
    PasswordEncoder passwordEncoder;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper<UserLogin> wrapper = new QueryWrapper<>();
wrapper.eq("name",username);
        UserLogin one = mapper.selectOne(wrapper);
        if(one==null){
            throw new UsernameNotFoundException("用户名不存在");

        }
//        String password = passwordEncoder.encode(one.getPassword()); //加密后传入
//        System.out.println(password);
        return new User(username,one.getPassword(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));

    }

}

handle/MyAuthenticationFailHandle

package com.example.springsecuritydemo.handle;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyAuthenticationFailHandle implements AuthenticationFailureHandler {
    private String url;

    public MyAuthenticationFailHandle(String url) {
        this.url = url;
    }


    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        response.sendRedirect(url);
    }
}

handle/MyAuthenticationSuccessHandle

package com.example.springsecuritydemo.handle;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyAuthenticationSuccessHandle implements AuthenticationSuccessHandler {
    private String url;

    public MyAuthenticationSuccessHandle(String url) {
        this.url = url;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.sendRedirect(url);

    }
}

前端static/login.html

DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<form action="/login" method="post">

    用户名 : <input type="text" name="username">
    
    密码 : <input type="password" name="password">
    <input type="submit" value="登录">
form>
body>
html>

error.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
登陆失败
<a href="/login.html">跳到登陆页面a>
body>
html>

main.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登录成功
</body>
</html>

授权

anyRequest()

注意要放在最后面 是按顺序的 ,放最前面其他放行的请求都会被拦截

     //授权
        http.authorizeRequests()
            	//放行 不用登录
                .antMatchers("/login.html").permitAll()
            //放行 不用登录
                .antMatchers("/error.html").permitAll()
                //拦截所有请求
                .anyRequest().authenticated();

antMatchers()

放行 静态资源

? 匹配一个字符
* 匹配0个或多个字符
** 匹配0个或多个目录
    
//例
.antMatchers("/css/**","/js/**","/images/**").permitAll()
.antMatchers("/**/*.png").permitAll()

regexMatchers()

//正则匹配
.regexMatchers(".+[.]png").permitAll()
//还有一个参数控制请求方法的 必须post才放行
.regexMatchers(HttpMethod.POST,"/demo").permitAll()

mvcMatchers()

//整个项目加前缀访问路径
//只在mvcMatchers里面有servletPath方法
.mvcMatchers("/demo").servletPath("/xxxx").permitAll()
    等价于
.antMatchers("/xxxx/demo").permitAll()  

控制的permitAll()还有其他的控制方法

springsecurity复习_第1张图片

基于权限判断

//严格区分大小写
.antMatchers("/main1.html").hasAuthority("admin").permitAll()
    
    
//只要有一个权限就可以访问
 .antMatchers("/main1.html").hasAnyAuthority("admin","admiN").permitAll()   

基于角色判断

    //给用户加角色 必须是 ROLE_ 开头
   return new User(username,one.getPassword(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_abc"));

//严格区分大小写
.antMatchers("/main1.html").hasRole("abc").permitAll()
    
    
//只要有一个角色就可以访问
 .antMatchers("/main1.html").hasAnyRole("abc","ABC").permitAll()

基于ip判断

.antMatchers("/main1.html").hasIpAddress("127.0.0.1").permitAll()

自定义403处理方案

定义配置类

springsecurity复习_第2张图片

使用

springsecurity复习_第3张图片

基于Access的访问控制

  • 前面的控制方法都是基于Access
//写法
.antMatchers("/main1.html").access("permitAll")
    
.antMatchers("/main1.html").access("hasRole('admin')")

自定义Access方法

编写接口及其实现类

springsecurity复习_第4张图片

使用

在这里插入图片描述

启动访问main.html 报错 没有 跳转的路径 的权限

添加访问权限

在这里插入图片描述

启动访问 成功~

用户授权的注解使用

@Secured

表示用户具有某个角色,可以访问方法

1.启动类开启注解

springsecurity复习_第5张图片

2.使用

  • 区分大小写

springsecurity复习_第6张图片

@PreAuthorize

在进入方法之前做验证,看是否有权限进入

区分大小写 可以 加前缀ROLE_

springsecurity复习_第7张图片

@PostAuthorize

方法执行之后校验 没什么大用

RememberMe

1.导入依赖

基于springjdbc的 但springjdbc很少用 用mybatis+mysql

2.编写mysql连接配置

3.使用 配置类增加配置
springsecurity复习_第8张图片

springsecurity复习_第9张图片

springsecurity复习_第10张图片

4.前端加上记住我

在这里插入图片描述

thymeleaf中spring security的使用

1.导入依赖

springsecurity复习_第11张图片

2.前端页面

springsecurity复习_第12张图片

3.现象

springsecurity复习_第13张图片

设置用户角色和权限

springsecurity复习_第14张图片

退出登录

直接在前端写上退出链接
<a href="/logout">退出a>

但地址栏会有lougout,不想看见怎么办?
配置类配置
//退出
http.logout() 
    //自定义退出  前端的退出请求也得是这个  最好就用默认的
    //.logoutUrl("/user/logout")
    .logoutUrl("/logout")
    //退出成功后跳转的页面
    .logoutSuccessUrl("/login.html")

CRSF

跨站请求伪造

跨域: 网络协议 ip地址 端口中任何一个不相同就是跨域请求

在这里插入图片描述

此时就登陆不成功

解决

springsecurity复习_第15张图片

Oauth2认证

springsecurity复习_第16张图片

第三方认证技术方案最主要是解决认证协议的通用标准问题,因为要实现跨系统认证,各系统之间要遵循一定的接口协议。

springsecurity复习_第17张图片

环境搭建

1.新建springboot工程

2.导入依赖 注意springboot版本


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.3.11.RELEASEversion>
        <relativePath/> 
    parent>
    <groupId>com.tiangroupId>
    <artifactId>springsecurityoauth2artifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>springsecurityoauth2name>
    <description>Demo project for Spring Bootdescription>
    <properties>
        <java.version>1.8java.version>
        <spring-cloud.version>Greenwich.SR2spring-cloud.version>
    properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-oauth2artifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-securityartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>${spring-cloud.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>

            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-surefire-pluginartifactId>
                <version>2.22.2version>
                <configuration>
                    <skipTests>trueskipTests>
                configuration>
            plugin>
        plugins>
    build>

project>

3.pojo/user

package com.tian.springsecurityoauth2.pojo;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;

public class User implements UserDetails {
    private String username;
    private String password;
    private List<GrantedAuthority> authorities;

    public User(String username, String password, List<GrantedAuthority> authorities) {
        this.username = username;
        this.password = password;
        this.authorities = authorities;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

4.service/UserService

package com.tian.springsecurityoauth2.service;

import com.tian.springsecurityoauth2.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
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 UserService implements UserDetailsService {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        String password = passwordEncoder.encode("123456");

        return new User(username,password,AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}

5.controller/UserController

@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/getCurrent")
    public Object getCurrent(Authentication authentication){
        return authentication.getPrincipal();
    }
}

6.config/SecurityConfig

package com.tian.springsecurityoauth2.config;

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

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/oauth/**","/login/**",
                        "/logout/**")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                .permitAll()
                .and()
                .csrf().disable();
    }

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

7.config/AuthorzationServerConfig

package com.tian.springsecurityoauth2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;

@Configuration
@EnableAuthorizationServer
public class AuthorzationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //客户端ID
                .withClient("client")
                //密钥
                .secret(passwordEncoder.encode("112233"))
                //重定向地址
                .redirectUris("http://www.baidu.com")
                //授权范围
                .scopes("all")
                //授权类型 - authorization_code 授权码模式
                .authorizedGrantTypes("authorization_code");
    }
}

8.config/ResourceServerConfig

package com.tian.springsecurityoauth2.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
               .anyRequest()
                .authenticated()
                .and().requestMatchers()
                .antMatchers("/user/**")
        ;
    }
}

启动访问

http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all

返回到springsecurity自定义的登录页面

输入 admin 123456 跳到这个页面 点击允许 跳转到百度

springsecurity复习_第18张图片

注意百度地址栏有个授权码

springsecurity复习_第19张图片

拿着返回的token请求资源

springsecurity复习_第20张图片

实际上token不会存在内存,我们这边用redis存储

redis存储token

1.添加依赖

springsecurity复习_第21张图片

2.配置文件

在这里插入图片描述

3.配置类

springsecurity复习_第22张图片

4.使用

在这里插入图片描述

springsecurity复习_第23张图片

JWT

是一个标准

JJWT

是JWT的实现

1.创建springboot项目

2.导入依赖

springsecurity复习_第24张图片

3.启动类

4.测试

springsecurity复习_第25张图片

5.现象

在这里插入图片描述

解析token

springsecurity复习_第26张图片

现象

在这里插入图片描述

JWT过期校验

springsecurity复习_第27张图片

自定义claims

springsecurity复习_第28张图片

获取

在这里插入图片描述

你可能感兴趣的:(springboot,java,spring,boot)