SpringSecurity学习 -- 1 springSecurity

目录

 简介:

token和jwt的区别

1.快速入门

1.自定义用户名和密码。

自定义重定向。

2.设置权限管理

3.从路径中获取用户信息

2.SpringSecurity核心组件

SecurityContext : authentication对象的容器。

SecurityContextHolder :

Authentication:

​编辑

UserDetails: 存储用户信息的。

UserDetailsService:

AuthenticationManager

3.配置类开发

权限判断

角色判断

IP判断(我的版本废除了)

access 

4.注解开发(了解)

@secured注解(角色判断)

@PreAuthorize + @PostAuthorize注解

@RemeberMe(前后端分离后,我觉得没必要)

Thymleaf(了解)  

CSRF(了解):

总结


SpringSecurity学习 -- 1 springSecurity_第1张图片

 简介:

springSecuicty是spring的一个安全框架,主要负责处理认证授权的功能。

认证:认证当前用户是哪个用户,并具体那个用户。(是否登录)

授权:授予某个用户访问权限,并判断他到底是否有访问权限。(有无权限执行:VIP)

其他的安全感框架:apache shiro ,强大且已于上手的安全框架

授权:貌似底层就想着一个过滤器,Filter从用户的请求判断是否携带相应的请求体来做出相应的相应。

token和jwt的区别

jwt是token的一种复杂实现。

jwt:  全称 json web token 比较复杂,有头部,载荷、签名组成。载荷中,包括用户信息等,并且服务端用秘钥对Jwt进行签名。发给浏览器端,浏览器端,访问时对jwt进行解密,如果解密成功则就是验证成功。

总结 : jwt是一种更复杂的身份令牌信息。

1.快速入门

我们基于web项目做测试

SpringSecurity学习 -- 1 springSecurity_第2张图片

 1.核心依赖


		
		
			org.springframework.boot
			spring-boot-starter-security
		
		
		
			org.springframework.boot
			spring-boot-starter-web
		
     
		

	
		
			
				org.springframework.boot
				spring-boot-dependencies
				${spring-boot.version}
				pom
				import
			
		
	

2.我们建一个login.html




    
    Title


3.启动springboot项目,访问locahost:8080(你没改端口号的话)

SpringSecurity学习 -- 1 springSecurity_第3张图片

 重定向到了这个页面,同时控制台打印一串类似密码的数字。

 证明security已经成功了。

1.自定义用户名和密码。

自定义重定向。

successForwardUrl(),只能重定向到静态页面。我们点进去发现,SpringSecurity学习 -- 1 springSecurity_第4张图片

 看得出实际上,我们调用successHanler()方法,然后我们url被封装到这里面。

SpringSecurity学习 -- 1 springSecurity_第5张图片

 卧槽,发现了什么?请求转发,看来我们url就被封装在这里面,被进行请求转发。

那为什么,全url为什么不能跳转,上述构造器,有一个断言,看url,符不符合格式,否则,那个跳转对象拿到是url是null。

嗯,看来,我们就是要自定义一个类实现AuthenticationSuccessHandler接口,借鉴上述并进行重写。

限制使用。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin().and()
                .httpBasic();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.
                inMemoryAuthentication()
                .withUser("qhx2004")
                .password("{noop}123456").roles("USER");

    }
}

2.设置权限管理

@Configuration
@EnableWebSecurity
// 配置security注解
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                //  设置资源对应的访问角色权限
                .antMatchers("/user/**").hasRole("USER")
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest()
                .authenticated()
                .and()
                .formLogin().and()
                .httpBasic();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.
                inMemoryAuthentication()
                // 登录账号匹配权限
                .withUser("qhx2004").password("{noop}123456").roles("USER").and()
                .withUser("admin").password("{noop}111").roles("ADMIN", "USER");
        // PassWordEncode
    }
}

3.从路径中获取用户信息

	@RequestMapping("/info")
	@ResponseBody
	public String productInfo(){
		String currentUser = "";
		Object principl = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		if(principl instanceof UserDetails) {
			currentUser = ((UserDetails)principl).getUsername();
		}else {
			currentUser = principl.toString();
		}
		return " some product info,用户信息 is: "+currentUser;
	}

2.SpringSecurity核心组件

SecurityContext : authentication对象的容器。

SecurityContextHolder :

Authentication:

它包括这很多,诸如用户信息、证书、用户权限、用户身份之类的。看方法,几乎使我们用来获取的,看样子他是别人调用我们拿到的。

public interface Authentication extends Principal, Serializable {
 
	Collection getAuthorities();
	Object getCredentials();
	Object getDetails();
	Object getPrincipal(); // 拿去UserDetail对象的
	boolean isAuthenticated();
	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

SpringSecurity学习 -- 1 springSecurity_第6张图片

UserDetails: 存储用户信息的。

public interface UserDetails extends Serializable {

	Collection getAuthorities();
	String getPassword();
	String getUsername();
	boolean isAccountNonExpired();
	boolean isAccountNonLocked();
	boolean isCredentialsNonExpired();
	boolean isEnabled();
}

UserDetailsService:

SpringSecurity学习 -- 1 springSecurity_第7张图片

public interface UserDetailsService {
    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
public class UserDetailsServiceImpl implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        String password = "1234";
        // 1.我们来自前端的用户名,会调用数据库进行查询,如果成功!
        if ("123".equals(username)) {
            // 失败 ,抛异常
            throw new UsernameNotFoundException("用户并校验错误!");
        }
        // 成功,返回一个User(UserDetails的实现类,我们的用户信息就封装在这个对象里面)对象
        return new User(username, password, AuthorityUtils.createAuthorityList("12"));
    }
}

AuthenticationManager

public interface AuthenticationManager {
    Authentication authenticate(Authentication authentication) throws AuthenticationException;
}

用来检验你的Authentication对象是否正确的。

3.配置类开发

server:
  servlet:
    context-path: /qhx
// 给项目 + 路径前缀

 访问以下资源放行卧槽,反正,我们yml文件整,给项目加了前缀/qhx,看出来区别了。mvc就是专门加了,servletpath

  // 授权认证
        http.authorizeHttpRequests()
                // 放行路径资源
                // 一般匹配
                .antMatchers("/qhx/login.html").permitAll()
                // mvc匹配
                .mvcMatchers("/login").servletPath("qhx").permitAll()
                // 正则匹配
                .regexMatchers("/qhx/register").permitAll()
                .anyRequest().authenticated();
        // 所有请求都必须被认证,必须登录之后被访问。

内置访问方法解析,

SpringSecurity学习 -- 1 springSecurity_第8张图片

权限判断

1.测试

  return new User(username, password, AuthorityUtils.
                       // 登陆之后,我给他admin权限
                        commaSeparatedStringToAuthorityList("admin,ROLE_ADMIN"));
    }

2. 资源限定权限访问

  .antMatchers("/vip").hasAuthority("admin")
                // 放行:admin.admiN访问
                .antMatchers("/vip").hasAnyAuthority("admin", "admiN")
                .anyRequest().authenticated();

角色判断

看出来,规定资源能被什么角色访问,登录之后把相应的角色给你,在这里面,也就是说管理员同时具有管理员和普通用户访问资源的权限。

1.测试

  return new User(username, password, AuthorityUtils.
                // 这个用户能访问普通用户和管理员角色访问的资源
                        commaSeparatedStringToAuthorityList("qhx,wls,ROLE_ADMIN,ROLE_USER"));
    }

 2.资源限定角色访问

// 角色管控:限定下面这俩资源,一个管理员访问,另一个普通用户访问
                .antMatchers("/admin").hasRole("ADMIN")
                .antMatchers("/user").hasAnyRole("ADMIN", "USER")
                .anyRequest().authenticated();

IP判断(我的版本废除了)

access 

我们打开源码,发现实际上是调用同对象的access方法,同理我们也可直接用access调用。

access还支持自定方法。

public class MyServiceImpl implements MyService {
    @Override
    public boolean hasProm(HttpServletRequest request, Authentication authentication) {
        Object principal = authentication.getPrincipal(); // 拿到user对象
        if (principal instanceof UserDetails) {
            UserDetails userDetails = (UserDetails) principal; // 强转
            Collection authorities = userDetails.getAuthorities();
            return authorities.contains(new SimpleGrantedAuthority(request.getRequestURI()));

        }

        return false;
    }
}

4.注解开发(了解)

其实看出来为了迎合发展方向,为了迎合我们的配置,就是静态资源和动态一起过滤,但是呢?随着,前后端分离,但是注解开发也是趋势。

@secured注解(角色判断)

1.启动类加上 EnableGlobalMethodSecurity


@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true) // 开启注解启动角色权限(本质上,我们限制的路径资源访问权限)
public class Sspring1securityApplication {

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

}

2.动态资源加上

@RestController
public class LoginContreoller {

    @Secured("ROLE_admin") // 管理员权限能访问
    @GetMapping("/login11")
    public String login() {
        System.out.println("执行登录..");
        return "redirect:main.html";
    }

}

错误:会报500异常,AccessDeniedException(访问被拒绝错误)

@PreAuthorize + @PostAuthorize注解

一个在类和方法执行之前权限判断,一个之后判断。

好家伙之前,我们的权限判断角色控制他都能用,只要输入相应的权限表达式即可。

  //@Secured("ROLE_admin") // 管理员权限能访问
    @PreAuthorize("hasRole('admin')") // 拥有管理员角色权限才能访问

@RemeberMe(前后端分离后,我觉得没必要)

现在,我们完全不需要记住我,这个关键字,因为默认网站差不多就是一个星期之后需要登录一次,那为什么登陆之后,他怎么判断我们是同一个请求,并且怎么记住一星期呢?

1.通过token来判断的话,我们登录之后,设置一个token被浏览器携带,并在浏览器端计算机硬盘储存一个月。

2.当我们下次登录时,会将token发到服务器端API,如果查询成功,则自动登录。

Thymleaf(了解)  

:模版引擎,能将模版和数据分离,但是又能就和在一起形成特定格式(模版)的产物。

CSRF(了解):

跨域网络协议 、IP地址 、端口 中任意一个不相同,就是跨域请求。

  • http本身无状态。通过cookie来记录客服端身份。在cookie中,会存放session id来识别客户端身份。
  • 在跨域的情况下,session id 可能被第三方恶意劫持,通过这个session id向服务器端发起请求。(也就是伪造了用户身份。)
  • 底层来讲,不就是通过session,cookie来判别用户,访问不同的动态资源。

那么CSRF技术,是通过访问时,同时携带_csrf.token 会与在服务端中的token进行比较,如果成功则允许访问。

总结

SecurityConfig.java

@Configuration
@EnableWebSecurity // 启用security配置
// 自定义配置
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.
                userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }

    @Override
    // 解决静态资源拦截问题(了解)
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/asserts/**");
        web.ignoring().antMatchers("/favicon.ico");
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 1.配置登录页并允许访问(没用了),下面2个参数对应表单,最后一个跳转页面。
        http.formLogin().usernameParameter("username").passwordParameter("password").loginPage("/login");
        //2.配置登出页面
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/");
        //3.给API设置权限
        http.authorizeRequests() // 拥有很多权限
                .antMatchers("/user/**").hasRole("USER")
                .antMatchers("/admin/**").hasAnyRole("USER", "ADMIN")
                // 任何请求都需要经过认证
                .anyRequest().authenticated();
        // 4.关闭跨域保护
        http.csrf().disable();

    }

    // 密码加密
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

MyUserDetailsServiceImpl.java

@Configuration
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 查询就不可能返回boolean值
        User user = userMapper.findByUserName(username); // 1.查询数据库
        // 2.判断有无用户
        if (user == null) {
            System.out.println(username + "用户没有注册");
            throw new UsernameNotFoundException(username + "用户没有注册");
        }
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), getAuthority());
    }

    // 获取权限列表
    public List getAuthority() {

        //return Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN"));
        return AuthorityUtils.createAuthorityList("ROLE_ADMIN");
    }

}

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