互联网门户网站建设,建没工程信息网,深圳福田有什么好玩的地方,模具机械设备东莞网站建设SpringBoot的安全
常用框架#xff1a;Shrio,SpringSecurity
两个功能#xff1a;
Authentication 认证Authorization 授权
权限#xff1a;
功能权限访问权限菜单权限
原来用拦截器、过滤器来做#xff0c;代码较多。现在用框架。
SpringSecurity
只要引入就可以使…SpringBoot的安全
常用框架Shrio,SpringSecurity
两个功能
Authentication 认证Authorization 授权
权限
功能权限访问权限菜单权限
原来用拦截器、过滤器来做代码较多。现在用框架。
SpringSecurity
只要引入就可以使用
可以在官网看教程
几个重要的类
WebSecurityConfigurerAdapter 自定义Security策略AuthenticationManagerBuilder 自定义认证策略EnableWebSercurity
基本操作
springboot 2.7.0前
继承WebSecurityConfigurerAdapter
重写configure(HttpSecurity http)方法——授权
使用链式编程
第一个小例子
http.authorizeRequests() //自定义权限控制.antMatchers(/).permitAll() //所有人可以访问首页.addMatchers(/vip1).hasRole(vip1); //vip1可以访问
//登录也可以使用and()拼接
http.fromLogin(); //没有权限会自动跳转到登录页面即使没有写过/login源码默认的login和login?error
重写Configure(AuthenticationManagerBuilder auth)方法——认证
2.7.0版本后WebSecurityConfigurerAdapter被弃用
上面配置好了什么权限可以做什么事情这里则用来做登录控制和权限查询操作
protected void configure(AuthenticationManagerBuilder auth){//因为反编译新版要求所有密码必须加密BCryptPasswordEncoder encoder new BCryptPasswordEncoder();//JDBC认证 例子为blog_systemauth.jdbcAuthentication().passwordEncoder(encoder).dataSource(dataSource).usersByUsernameQuery(userSQL) //通过username、password、enabled登录控制.authoritiesByUsernameQuery(authoritySQL); //通过用户名、权限在查询的第二列获取role//内存认证 例子来自狂神说课堂笔记没用数据库的例子auth.inMemoryAuthentication().passwordEncoder(encoder) .withUSer(name).password( new BCryptPasswordEncoder(123456)).roles(vip2,vip3).and() //通过and拼接其他用户.withUSer(name2).password(new BCryptPasswordEncoder(123456)).roles(vip2,vip3);//自定义认证规则接受Service参数 例子来自VBlogauth.userDetailsService(userService);
}上面的最后一种方式UserService继承UserDetailService并重写方法
Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {User user userMapper.loadUserByUsername(s);if (user null) {//避免返回null这里返回一个不含有任何值的User对象在后期的密码比对过程中一样会验证失败return new User();}//查询用户的角色信息并返回存入user中ListRole roles rolesMapper.getRolesByUid(user.getId());user.setRoles(roles); return user;}登录之后若没权限就是跳转到没权限界面了
基于方法的动态权限
将用户的权限保存在数据库中并实现动态权限控制。
在配置类上使用EnableGlobalMethodSecurity来开启它
然后在方法中使用PreAuthorize配置访问接口需要的权限
PreAuthorize(hasAuthority(pms:product:create))权限字符串自定。 再从数据库中查询出用户所拥有的权限值设置到UserDetails对象中去。 ruoyi项目使用了这种方法 缺点方法权限写死在代买里了不好维护。也可以通过过滤器、拦截器实现 Since 2.7.0 新用法
新用法非常简单无需再继承WebSecurityConfigurerAdapter只需直接声明配置类再配置一个生成SecurityFilterChainBean的方法把原来的HttpSecurity配置移动到该方法中即可。
/*** SpringSecurity 5.4.x以上新用法配置* 为避免循环依赖仅用于配置HttpSecurity* Created by macro on 2022/5/19.*/
Configuration
public class SecurityConfig {BeanSecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {//省略HttpSecurity的配置return httpSecurity.build();}}Security上下文
UsernamePasswordAuthenticationToken authentication new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);注销
前端请求/logout
http.logout();
//会请求/logout可以自定义url。默认回到/login?logout
//看源码可以清空cookies和session
http.logout().logoutUrl(/) //注销成功回首页.csrf().disable() //关闭防止csrf攻击 csrf:跨站请求攻击可能屏蔽get。模板引擎相关功能
页面定制
登录loginPage(“”)改完之后默认的login就没有了
点进去看源码
/*
.formLogin(formLogin -* formLogin* .usernameParameter( username ) //默认* .passwordParameter( password )* .loginPage( /authentication/login ) 登录路由* .failureUrl(/authentication/login?failed)* .loginProcessingUrl( /authentication/login/process ) 登陆验证页面* );
*/“记住我”功能
http.rememberMe(); //登录页会有“记住我” 保存cookie 默认14天Shiro
Apache 开源框架
三大对象
Subject 用户SecurityManager 管理用户Realm 连接数据
Subject主体代表了当前 “用户”与当前应用交互的任何东西都是 Subject如网络爬虫人等即一个抽象概念所有 Subject 都绑定到 SecurityManager与 Subject 的所有交互都会委托给 SecurityManager可以把 Subject 认为是一个门面SecurityManager 才是实际的执行者
SecurityManager安全管理器即所有与安全有关的操作都会与 SecurityManager 交互且它管理着所有 Subject可以看出它是 Shiro 的核心它负责与后边介绍的其他组件进行交互如果学习过 SpringMVC你可以把它看成 DispatcherServlet 前端控制器
Realm域Shiro 从 Realm 获取安全数据如用户、角色、权限就是说 SecurityManager 要验证用户身份那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作可以把 Realm 看成 DataSource即安全数据源。
也就是说对于我们而言最简单的一个 Shiro 应用
应用代码通过 Subject 来进行认证和授权而 Subject 又委托给 SecurityManager我们需要给 Shiro 的 SecurityManager 注入 Realm从而让 SecurityManager 能得到合法的用户及其权限进行判断。 !--shiro依赖- SSM--dependencygroupIdorg.apache.shiro/groupIdartifactIdshiro-core/artifactIdversion1.2.4/version/dependencydependencygroupIdorg.apache.shiro/groupIdartifactIdshiro-web/artifactIdversion1.2.4/version/dependencydependencygroupIdorg.apache.shiro/groupIdartifactIdshiro-spring/artifactIdversion1.2.4/version/dependencyshiro-web提供了Web集成的支持其通过一个 ShiroFilter 入口来拦截需要安全控制的 URL然后进行相应的控制
1.编写配置类
Configuration
public class ShiroConfig{//ShiroFilterFactoryBeanBeanpublic ShiroFilterFactoryBean hetShiroFilterFactoryBean(Qualifier DefaultWebSercurityManager defaultWebSercurityManager){ShiroFilterFactoryBean bean new ShiroFilterFactoryBean();//设置安全管理器bean.setSecurityManager(defaultWebSercurityManager);MapString,String filterMap new LinkedHashMap();filterMap.put(,authc)return bean;}//DefaultWebSercurityManagerBeanpublic DefaultWebSercurityManager getDefaultWebSercurityManager(Qualifier(userRealm) UserRealm userRealm){DefaultWebSercurityManager sercurityManager new DefaultWebSercurityManager();securityManager.setRealm(userRealm);return sercurityManager;}//Realm 自定义Beanpublic Realm userRealm(){return new UserRealm();}
}public UserRealm extends AuthorizingRealm{Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {// 用户名String username (String) token.getPrincipal();// 密码String password new String((char[]) token.getCredentials());Userlogin userlogin null;try {userlogin userloginService.findByName(username);} catch (Exception e) {e.printStackTrace();}if (userlogin null) {// 没有该用户名throw new UnknownAccountException();} else if (!password.equals(userlogin.getPassword())) {// 密码错误throw new IncorrectCredentialsException();}// 身份验证通过,返回一个身份信息AuthenticationInfo aInfo new SimpleAuthenticationInfo(username, password, getName());return aInfo;}
}2.登录控制
//登录表单处理RequestMapping(value /login, method {RequestMethod.POST})public String login(Userlogin userlogin) throws Exception {//Shiro实现登录UsernamePasswordToken token new UsernamePasswordToken(userlogin.getUsername(),userlogin.getPassword());Subject subject SecurityUtils.getSubject();//如果获取不到用户名就是登录失败但登录失败的话会直接抛出异常//登录subject.login(token);if (subject.hasRole(admin)) {return redirect:/admin/showStudent;} else if (subject.hasRole(teacher)) {return redirect:/teacher/showCourse;} else if (subject.hasRole(student)) {return redirect:/student/showCourse;}return /login;}