目录
简介:
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(了解):
总结
springSecuicty是spring的一个安全框架,主要负责处理认证和授权的功能。
认证:认证当前用户是哪个用户,并具体那个用户。(是否登录)
授权:授予某个用户访问权限,并判断他到底是否有访问权限。(有无权限执行:VIP)
其他的安全感框架:apache shiro ,强大且已于上手的安全框架。
授权:貌似底层就想着一个过滤器,Filter从用户的请求判断是否携带相应的请求体来做出相应的相应。
jwt是token的一种复杂实现。
jwt: 全称 json web token 比较复杂,有头部,载荷、签名组成。载荷中,包括用户信息等,并且服务端用秘钥对Jwt进行签名。发给浏览器端,浏览器端,访问时对jwt进行解密,如果解密成功则就是验证成功。
总结 : jwt是一种更复杂的身份令牌信息。
我们基于web项目做测试
1.核心依赖
<dependencies><!-- spring-security依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- web依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>
2.我们建一个login.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action=""><input type="text" placeholder="用户名"><input type="text" placeholder="密码">
</form></body>
</html>
3.启动springboot项目,访问locahost:8080(你没改端口号的话)
重定向到了这个页面,同时控制台打印一串类似密码的数字。
证明security已经成功了。
successForwardUrl(),只能重定向到静态页面。我们点进去发现,
看得出实际上,我们调用successHanler()方法,然后我们url被封装到这里面。
卧槽,发现了什么?请求转发,看来我们url就被封装在这里面,被进行请求转发。
那为什么,全url为什么不能跳转,上述构造器,有一个断言,看url,符不符合格式,否则,那个跳转对象拿到是url是null。
嗯,看来,我们就是要自定义一个类实现AuthenticationSuccessHandler接口,借鉴上述并进行重写。
限制使用。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("qhx2004").password("{noop}123456").roles("USER");}
}
@Configuration
@EnableWebSecurity
// 配置security注解
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()// 设置资源对应的访问角色权限.antMatchers("/user/**").hasRole("USER").antMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated().and().formLogin().and().httpBasic();}@Overrideprotected 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}
}
@RequestMapping("/info")@ResponseBodypublic String productInfo(){String currentUser = "";Object principl = Context().getAuthentication().getPrincipal();if(principl instanceof UserDetails) {currentUser = ((UserDetails)principl).getUsername();}else {currentUser = String();}return " some product info,用户信息 is: "+currentUser;}
它包括这很多,诸如用户信息、证书、用户权限、用户身份之类的。看方法,几乎使我们用来获取的,看样子他是别人调用我们拿到的。
public interface Authentication extends Principal, Serializable {Collection<? extends GrantedAuthority> getAuthorities();Object getCredentials();Object getDetails();Object getPrincipal(); // 拿去UserDetail对象的boolean isAuthenticated();void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
public interface UserDetails extends Serializable {Collection<? extends GrantedAuthority> getAuthorities();String getPassword();String getUsername();boolean isAccountNonExpired();boolean isAccountNonLocked();boolean isCredentialsNonExpired();boolean isEnabled();
}
public interface UserDetailsService {UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
public class UserDetailsServiceImpl implements UserDetailsService {@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {String password = "1234";// 1.我们来自前端的用户名,会调用数据库进行查询,如果成功!if ("123".equals(username)) {// 失败 ,抛异常throw new UsernameNotFoundException("用户并校验错误!");}// 成功,返回一个User(UserDetails的实现类,我们的用户信息就封装在这个对象里面)对象return new User(username, password, ateAuthorityList("12"));}
}
public interface AuthenticationManager {Authentication authenticate(Authentication authentication) throws AuthenticationException;
}
用来检验你的Authentication对象是否正确的。
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();// 所有请求都必须被认证,必须登录之后被访问。
内置访问方法解析,
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();
我们打开源码,发现实际上是调用同对象的access方法,同理我们也可直接用access调用。
access还支持自定方法。
public class MyServiceImpl implements MyService {@Overridepublic boolean hasProm(HttpServletRequest request, Authentication authentication) {Object principal = Principal(); // 拿到user对象if (principal instanceof UserDetails) {UserDetails userDetails = (UserDetails) principal; // 强转Collection<? extends GrantedAuthority> authorities = Authorities();ains(new RequestURI()));}return false;}
}
其实看出来为了迎合发展方向,为了迎合我们的配置,就是静态资源和动态一起过滤,但是呢?随着,前后端分离,但是注解开发也是趋势。
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(访问被拒绝错误)
一个在类和方法执行之前权限判断,一个之后判断。
好家伙之前,我们的权限判断和角色控制他都能用,只要输入相应的权限表达式即可。
//@Secured("ROLE_admin") // 管理员权限能访问@PreAuthorize("hasRole('admin')") // 拥有管理员角色权限才能访问
现在,我们完全不需要记住我,这个关键字,因为默认网站差不多就是一个星期之后需要登录一次,那为什么登陆之后,他怎么判断我们是同一个请求,并且怎么记住一星期呢?
1.通过token来判断的话,我们登录之后,设置一个token被浏览器携带,并在浏览器端计算机硬盘储存一个月。
2.当我们下次登录时,会将token发到服务器端API,如果查询成功,则自动登录。
:模版引擎,能将模版和数据分离,但是又能就和在一起形成特定格式(模版)的产物。
跨域:网络协议 、IP地址 、端口 中任意一个不相同,就是跨域请求。
那么CSRF技术,是通过访问时,同时携带_ken 会与在服务端中的token进行比较,如果成功则允许访问。
SecurityConfig.java
@Configuration
@EnableWebSecurity // 启用security配置
// 自定义配置
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected 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");}@Overrideprotected 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();}// 密码加密@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}
MyUserDetailsServiceImpl.java
@Configuration
public class MyUserDetailService implements UserDetailsService {@Autowiredprivate UserMapper userMapper;@Overridepublic 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.userdetails.Username(), Password(), getAuthority());}// 获取权限列表public List getAuthority() {//return Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN"));ateAuthorityList("ROLE_ADMIN");}}
本文发布于:2024-01-27 17:03:33,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17063462271539.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |