SpringSecurityJSON版本

SpringSecurity介绍

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AsjxeAoK-1672023162095)(images/1583585891579.png)]

Spring Security是基于spring的应用程序提供声明式安全保护的安全性框架,它提供了完整的安全性解决方案,能够在web请求级别和方法调用级别处理身份证验证和授权,它充分使用了依赖注入和面向切面的技术。

Spring Security 的前身是 Acegi Security,后来成为了 Spring 在安全领域的顶级项目,并正式更名到 Spring 名下,成为 Spring 全家桶中的一员,所以 Spring Security 很容易地集成到基于 Spring 的应用中来。Spring Security 在用户认证方面支持众多主流认证标准,包括但不限于 HTTP 基本认证、HTTP 表单验证、HTTP 摘要认证、OpenID 和 LDAP 等,在用户授权方面,Spring Security 不仅支持最常用的基于 URL 的 Web 请求授权,还支持基于角色的访问控制(Role-Based Access Control,RBAC)以及访问控制列表(Access Control List,ACL)等。

Spring Security 是 Spring 家族中的一个安全管理框架,Spring Security 已经发展了多年了,但是使用的并不多,安全管理这个领域,一直是 Shiro 的天下。相对于 Shiro,在 SSM/SSH 中整合 Spring Security 都是比较麻烦的操作,所以,Spring Security 虽然功能比 Shiro 强大,但是使用反而没有 Shiro 多,Shiro 虽然功能没有 Spring Security 多,但是对于大部分项目而言,Shiro 也够用了。

SpringSecurity主要是从两个方面解决安全性问题:

  1. web请求级别:使用servlet过滤器保护web请求并限制URL级别的访问

  2. **方法调用级别:**使用Spring AOP保护方法调用,确保具有适当权限的用户才能调用方法.

权限相关概念

主体(principal)
使用系统的用户或设备或从其他系统远程登录的用户等等。

认证(authentication)
权限管理系统确认一个主体的身份,允许主体进入系统。

授权(authorization)
将操作系统的“权力”“授予”“主体”,这样主体就具备了操作系统中特定功能的能力。

SpringSecurity主要功能

  • 认证就是确定主体的过程,当未认证的主体访问系统资源的时候,系统会对主体的身份进行验证,确定该主体是否有合法的身份,不合法的主体将被应用拒绝访问,这一点也很容易理解,比如某电商网站,未登录的用户是无法访问敏感数据资源的,比如订单信息。
  • 授权是在主体认证结束后,判断该认证主体是否有权限去访问某些资源,没有权限的访问将被系统拒绝,比如某电商网站的登录用户去查看其它用户的订单信息,很明显,系统会拒绝这样的无理要求。
  • 攻击防护:防止攻击伪造

环境搭建

POM

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

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

Controller

@Controller
public class UserController {

    @RequestMapping(value = "/hello")
    @ResponseBody
    public String hello(){
        System.out.println("UserController.hello");
        return "Hello Sprign Security";
    }
}

访问

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G1h39Uvl-1672023162096)(images/1583592152841.png)]

Spring Boot 项目引入了 Spring Security 以后,自动装配了 Spring Security 的环境,Spring Security 的默认配置是要求经过了 HTTP Basic 认证成功后才可以访问到 URL 对应的资源,且默认的用户名是 user,密码是自动随机生成一串 UUID 字符串,输出到了控制台日志里,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EDny5Fxb-1672023162097)(images/1583592227948.png)]

身份认证的方式

配置文件
spring:
  security:
    user:
      name: admin
      password: 123
自定义实现类(常用)

通过UserDetailsService来查询用户的密码,最后把用户封装成一个user返回给SpringSecurity。

MyUserDetailsService

Spring Security中,用户的登录操作都是通过 UserDetailsService完成的,它是一个接口,该接口中只有一个loadUserByUsername(),在用户登录的时候SpringSecurity就会调用这个方法,该方法返回一个UserDetails对象,这个对象就代表了当前认证的主体,需要从数据库中根据用户名查询,从而返回出去,SpringSecurity会把该方法的返回值放到Session中,如果验证失败这个出现异常会抛出一个UsernameNotFoundException。

@Configuration
public class MyUserDetailsService implements UserDetailsService {
   

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    /**
     * 根据用户名查询密码
     * @param username 表单输入的用户名
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
   
        System.out.println("s = [" + s + "]");

        // 在这里可以根据用户名从数据库中查询密码
        // User user = baseMapper.getUserByUsername(username);
        //if(user == null){
   
        	// 如果用户名不存在直接抛出异常
          	 // throw new UsernameNotFoundException("用户名不存在");
        //}
        
        // 密码加密
        String password = passwordEncoder.encode("123");

        // 权限
        List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("admin");

        // 返回user(用户名,密码,权限)
        return new User("点toString",password,authorities);//SpringSecurity会返回值放到Session中
    }
}
SpringSecurityConfig

在SpringSecurityConfig中设置使用UserDetailsService来加载用户的密码。

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
   

    @Autowired
    private UserDetailsService userDetailsService;

    // spring security 官方推荐的是使用bcrypt加密方
    // SpringSecurity在对表单密码加密的时候需要用到这个bean,所以这里需要给它创建。如果不创建会登录会报错。
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
   
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
   
        auth
                .userDetailsService(userDetailsService) // 自定义实现类完成密码的设置
                .passwordEncoder(passwordEncoder()); // 设置密码加密算法
    }
}

自定义JSON登录

UsernamePasswordAuthenticationFilter是AbstractAuthenticationProcessingFilter针对使用用户名和密码进行身份验证而定制化的一个过滤器。其添加是在调用http.formLogin()时作用,默认的登录请求pattern为"/login",并且为POST请求。当我们登录的时候,也就是匹配到loginProcessingUrl,这个过滤器就会委托认证管理器authenticationManager来验证登录。

1、定义登录拦截器

@Component
public class LoginFilter extends UsernamePasswordAuthenticationFilter {
   

    public LoginFilter() {
   
        // 默认登录使用post提交
        this.setPostOnly(false);
        // 默认登录的urlloign
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/userLogin","GET"));
    }

    @Autowired
    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
   
        super.setAuthenticationManager(authenticationManager);
    }

    // 登录成功调用
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
   
        Object principal = authResult.getPrincipal();
        Collection<? extends GrantedAuthority> authorities = authResult.getAuthorities();
        // 登录成功后把权限放入到本次会话
        SecurityContextHolder.getContext().setAuthentication(authResult);
        ResponceUtils.out(response, R.ok().put("msg","登录成功").put("token","000"));
    }

    // 登录失败调用
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
   
        ResponceUtils.out(response, R.ok().put("msg","用户名获密码错误"));
    }
}

2、配置登录拦截器

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
   

    @Autowired
    private LoginFilter loginFilter;

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

    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
   
        return super.authenticationManager();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
   
        http
            .exceptionHandling()
                .and().addFilter(loginFilter); // 加入登录拦截器
    }
}

用户注销

            http.formLogin() 
                .loginPage("/toLogin")
                .loginProcessingUrl("/login") 
                .defaultSuccessUrl("/toSuccess")
                .usernameParameter("name") 
                .passwordParameter("pw")  
                
			.and()
                .logout() // 添加注销处理
                .logoutUrl("/toLogout") // 注销地址
                .logoutSuccessUrl("http://www.baidu.com") // 注销成功后调整的地址
                    //退出处理器,可以写匿名内部类
                .addLogoutHandler(new LogoutHandler() {
    
                    @Override
                    public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
   
                    }
                })
                   
                // 设置该方法会覆盖logoutSuccessUrl()方法
                // 退出成功处理器
                .logoutSuccessHandler(new LogoutSuccessHandler() {
    
                    @Override
                    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
   
                    }
                }).and().csrf().disable();

权限控制

​ SpringSecurity中可以通过角色和权限进行权限的控制,主体登录成功对访问的资源进行判断是否有这个权限,如果有就执行,否则就会跳转到没有权限访问的页面。

​ Spring Security 中对于权限控制默认已经提供了很多了 , 其中有四种时常用的权限控制方式。

  • 表达式控制 URL 路径权限
  • 使用过滤注解
  • 动态权限

给用户设置角色和权限

在SpringSecurity中角色和权限并没有分开,而是都统一的封装到了一个 List中。其中通过ROLE_来区分该权限是角色还是权限。

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
   
        System.out.println
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值