栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringSecurity

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringSecurity

零、SpringSecurity

SpringSecurity是一个强大且高度可定制的身份验证和访问控制框架。

一、写一个案例

1.构建项目引入web和security依赖

2.写一个登陆的controller

@Controller
public class SerurityController {
    @RequestMapping("/mlogin")
    public String login(){
        System.out.println("执行了登陆功能");
        return "redirect:main.html";
    }
}

3.静态页面

4.直接启动访问项目ip端口,发现这并不是我们的login

5.使用默认用户名密码登陆

发现这才是熟悉的页面

6.访问接口进入断点

二、自定义认证 a.UserDetailsService

要想使用springsecurity本质就是自定义一下认证逻辑,代码角度就是实现一个接口。

可以看见该接口里面有一个接口

public interface UserDetailsService {

	
     // username是前端传过来的
	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

}

返回值UserDetails也是一个接口

public interface UserDetails extends Serializable

实际返回中应该是该接口的实现类

public class User implements UserDetails, CredentialsContainer

b.PasswordEncoder
//密码的加密和比较的方法
String encode(CharSequence rawPassword);
boolean matches(CharSequence rawPassword, String encodedPassword);

实现类

只能加密不能解密

public class BCryptPasswordEncoder implements PasswordEncoder 

Demo

    @Test
    void passwordEncoderDemo() {
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode("123456");
        System.out.println("加密后:"+encode);
        boolean matches = passwordEncoder.matches("123456",encode);
        System.out.println("是否匹配:"+matches);
    }

c.自定义逻辑的实现

注:在自定义逻辑前,SpringSerurity要求IOC容器内必须有一个密码解析器,所以需要先配置密码解析器。

@Configuration
public class PasswordEncoderConfig {
    @Bean
    public PasswordEncoder getPasswordEncoder(){
        return  new BCryptPasswordEncoder();
    }
}

接着实现UserDetailsServices

package com.example.springseruitydemo.service;

import org.springframework.beans.factory.annotation.Autowired;
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.password.PasswordEncoder;
import java.util.List;


public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Override
    public UserDetails loadUserByUsername(String myusername) throws UsernameNotFoundException {
        //1.查询数据库,不存在则抛出用户不存在异常
        if (!"admin".equals(myusername)){
            throw new UsernameNotFoundException("用户不存在");//1.模拟根据用户名从数据库中查询数据
        }
        //2.把查询出的密码(已加密)进行解析,或者直接吗密码放入构造方法
        String encode = passwordEncoder.encode("123456");//2.模拟数据库中的密码
        List authorityList = AuthorityUtils.createAuthorityList("admin", "normal");//3.模拟数据库中的权限
        return new User(myusername,encode,authorityList);
    }
}

可以看见现在登陆已使用自定义登陆逻辑

d.自定义登陆页面

现在访问其他页面都会进行认证校验,跳转到登陆页面

@Configuration
public class PasswordEncoderConfig extends WebSecurityConfigurerAdapter {
     //表单提交
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //自定义登陆页面
        http.formLogin()
                //1发现是这个请求地址的时候走拦截逻辑
                //1.1controller可以不写,post请求即可,这里就相当于一个
                .loginProcessingUrl("/mlogin")
                //2指定登陆的页面
                .loginPage("/login_page/login.html")
                //3页面跳转必须是post
                .successForwardUrl("/toMain")
                //4登陆失败也是一个post请求
                .failureForwardUrl("/toError");

        //授权认证拦截
        http.authorizeHttpRequests()
                //1不能拦截登陆页面和登陆失败页面
                .antMatchers(
                        "/login_page/login.html",
                        "/error.html")
                .permitAll()
                //2.拦截所有请求
                .anyRequest().authenticated();

        //关闭csrf防火墙
        http.csrf().disable();
    }

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

e.自定义登陆参数

现在回顾之前的配置流程,拦截请求->页面发送请求->框架拦截校验,其中页面拦截的资源路径我们不用写controller 只需要和前端约定即可,这个是由我们来自定义的。但是post请求方式和两个参数username和password则有框架约定写死,该如何自定义呢?

public class UsernamePasswordAuthenticationFilter 

看到这里就明白了只需要设置一下就可以了,另外需要和前端请求页面参数一致。

d.自定义校验结果处理

现在流行的是前后端分离开发,所以由后端来进行跳转成功失败页面是不合理的,所以要自定义一下登陆结果的处理。其实就是研究一下这两个方法。

先看成功

	public FormLoginConfigurer successForwardUrl(String forwardUrl) {
		successHandler(new ForwardAuthenticationSuccessHandler(forwardUrl));
		return this;
	}
	public ForwardAuthenticationSuccessHandler(String forwardUrl) {
		Assert.isTrue(UrlUtils.isValidRedirectUrl(forwardUrl), () -> "'" + forwardUrl + "' is not a valid forward URL");
		this.forwardUrl = forwardUrl;
	}

自定义步骤

1.继承AuthenticationSuccessHandler

2.重写方法onAuthenticationSuccess

public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    private  String successUrl;

    public MyAuthenticationSuccessHandler(String successUrl) {
        this.successUrl = successUrl;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        User user = (User)authentication.getPrincipal();
        response.sendRedirect(successUrl);
    }
}

3.注释.successForwardUrl

4.指定处理器.successHandler(new MyAuthenticationSuccessHandler(“http://www.baidu.com”))

失败处理器同理

三、参数详解 a.anyRequest()

拦截除permitAll()的所有请求

b.antMatchers

支持通配符

?:匹配一个字符

*:匹配0个或多个字符

**:匹配零个或多个目录

**案例:**放行静态资源

配置放行的静态资源

c.regexMathcers

使用正则表达式来放行

regexMathcers(“正则表达式”).permitAll()

注:

所有的认证匹配方法均有两个参数的重载方法,可以用于请求方式的校验。

当我们把controller换成post请求时候,返回请求方式不允许。


现在再去访问,则拦截。因为浏览器发送的是 get请求 和放行的不一致

四、权限访问

案例:会员,VIP

.antMatchers("/main2.html").hasAuthority("admin")//验证是否有该权限
.antMatchers("/main2.html").hasAnyAuthority("admin","abb")//验证是否有多个权限

该权限和自定义登陆时候返回的保持一致,否则会报错

注:但是这里需要注意的是:hasAnyAuthority(“admin”,“abb”)当用户有一个权限负荷要求的时候,便认为有权限来进行操作。

五、角色判断

只需要在自定义登陆逻辑中返回User即可,而且角色和权限放在一起,但是需要按照规则写,ROLE_开头

同样的可以配置角色权限限制

.antMatchers("/main2.html").hasRole("worker")

当然你可以配置多个角色有该权限操作

 .antMatchers("/main2.html").hasAnyRole("worker")
六、IP限制

目前没有在版本中找到

七、自定义未授权

1.继承AccessDeniedHandler,重写控制方法

@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.sendRedirect("/403.html");
    }
}

2.配置HttpSecurity未授权处理bean

 //自定义403处理
http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);

八、基于access的认证

前面无论是基于权限还是基于角色都是通过access方法来实现认证的。
待补充。。。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/581945.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号