您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

OAuth网络安全登录认证(二)

时间:2021-05-07 11:12:51  来源:今日头条  作者:开发架构狮rain

本文开始讲springsecurity框架登录认证授权的一些知识点。为什么没有说shiro这个框架,主要是现在大部分的主流项目中,特别是前后端分离的项目中权限框架一般都用的是springsecurity,比较适合,然后还有一点,就是一些开源框架(比如最新版本的工作流引擎activiti7)跟springsecurity的整合,促使我对这个springsecurity进一步加深了解。还有一个前提,就是本文是完全基于前后端分离的基础上写作,未分离项目可以做借鉴。

按照正常的思维,一个权限框架要解决的问题是:登录以及还有登录之后的访问。这个需要怎么实现,其实就是一串过滤器跟拦截器。用户没有登录,进行拦截;用户登录之后,带着证书登陆,拦截器先判断是否有证书,然后再判断证书是否合法,有一个不满足,都进行拦截。springsecurity这个框架其实本身封装的就是一连串的过滤器跟拦截器。这里借鉴一下网上的一张原理图片:

OAuth网络安全登录认证(二)

 

 

首先,我们先说登录。官方术语叫认证Authentication。主要是通过AuthenticationManager接口进行认证。(本文主要将通过用户名密码进行认证,其他认证方式后续文章会有说明。)AuthenticationManager的默认实现是ProviderManager,它又委托AuthenticationProvider实例来实现认证,我们通常用到的认证方式就是通过DaoAuthenticationProvider来认证的。(上边这几句话有点难以理解,实在不理解的话直接跳过,总之就是通过下边这个接口进行认证的,然后登录接口调用这个接口进行认证。)

public interface AuthenticationManager {
  Authentication authenticate(Authentication authentication)throws AuthenticationException;
}
// 用户登录认证
Authentication authentication = null;
try {
  // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername(这个实现类后边会有说明,这里主要讲登陆逻辑)
  authentication = authenticationManager
    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
}catch (Exception e){
  if (e instanceof BadCredentialsException) {
    //抛出登录异常
    throw new UserPasswordNotMatchException();
  }else{
    //抛出自定义异常
    throw new CustomException(e.getMessage());
  }
}

接下来,我们要把这套登录整合到我们的系统,需要用到我们自己的用户角色权限表。springsecurity中默认使用UserDetailsService来获取用户权限信息,我们需要自己实现这个接口,然后注入到认证接口中。

public class UserDetailsServiceImpl implements UserDetailsService{
    private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
    @Autowired
    private ISysUserService userService;
    @Autowired
    private SysPermissionService permissionService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
    {
        SysUser user = userService.selectUserByUserName(username);//查询用户信息
        if (StringUtils.isNull(user)){
            throw new UsernameNotFoundException("登录用户:" + username + " 不存在");
        }else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
            throw new BaseException("对不起,您的账号:" + username + " 已被删除");
        }else if (UserStatus.DISABLE.getCode().equals(user.getStatus())){
            throw new BaseException("对不起,您的账号:" + username + " 已停用");
        }
      	//讲用户信息跟权限信息统一封装到UserDetails
        new UserDetails(user, permissionService.getMenuPermission(user));
    }
}
public class SecurityConfig extends WebSecurityConfigurerAdapter{
   /**
     * 身份认证接口
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
      	//注入身份认证接口,通过bCryptPasswordEncoder密码加密认证
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }
    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

其次,登录认证都说完了,我们开始说过滤拦截,通过继承自
WebSecurityConfigurerAdapter,对Spring Security自定义配置添加过滤器,下边我们直接在代码里做注释说明:

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
    @Autowired
    private UserDetailsService userDetailsService;//自定义用户认证逻辑
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;//认证失败处理类
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;//退出处理类
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;//token认证过滤器
    @Autowired
    private CorsFilter corsFilter;//跨域过滤器
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception{
        httpSecurity
                // CSRF禁用,因为不使用session
                .csrf().disable()
                // 认证失败处理类
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 过滤请求
                .authorizeRequests()
                // 对于登录login 验证码captchaImage 允许匿名访问
                .antMatchers("/login", "/captchaImage").anonymous()
                .antMatchers(HttpMethod.GET,"/*.html","/**/*.html", "/**/*.css", "/**/*.js").permitAll()
                .antMatchers("/processDefinition/**").permitAll()
                .antMatchers("/activitiHistory/**").permitAll()
                .antMatchers("/profile/**").anonymous()
                .antMatchers("/common/download**").anonymous()
                .antMatchers("/common/download/resource**").anonymous()
                .antMatchers("/swagger-ui.html").anonymous()
                .antMatchers("/swagger-resources/**").anonymous()
                .antMatchers("/webjars/**").anonymous()
                .antMatchers("/*/api-docs").anonymous()
                .antMatchers("/druid/**").anonymous()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and().headers().frameOptions().disable();
        httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
        // 添加JWT filter
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        // 添加CORS filter
        httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
        httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
    }
}

最后,我们对
JwtAuthenticationTokenFilter过滤器做主要说明,因为这是用户登录之后,每次访问接口的时候,都需要通过这个接口进行token验证,并把用户信息放入到SecurityContextHolder上下文中,然后后台服务就可以直接在上下文中获取用户信息。

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter{
    @Autowired
    private TokenService tokenService;
  
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
       //从请求头中获取token,并从缓存中查询用户信息(缓存中用户信息是在用户登录后放入缓存,可以加快查询效率)       
        LoginUser loginUser = tokenService.getLoginUser(request);
        if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())){
            tokenService.verifyToken(loginUser);//验证token,同时自动刷新token使用时间
          	//以下逻辑就是把通过token验证的用户信息放入到上下文中,后台服务可以直接通过上下文获取当前用户
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        chain.doFilter(request, response);
    }
}
//后台服务获取当前用户代码
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
	String username = ((UserDetails)principal).getUsername();
} else {
	String username = principal.toString();
}

以上,就是我对springsecurity安全框架做出的总结。另外,文章里的部分代码,是借鉴若依大佬的RuoyiVue这套前后端分离框架的,完全开源的,有不对的地方,请大家指正。后边文章,我会写前端如何跟后端进行token接口交互的文章,整合前端。



Tags:   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
说到远程控制,首先你会想到的是什么?是TeamViewer 还是向日葵?抑或是QQ远程还是anydesk?对,就在不久前,我们熟知的都是以上的产品,但是只2020年开始,一款新的远控产品ToDesk进入到我...【详细内容】
2021-12-27  Tags:   点击:(1)  评论:(0)  加入收藏
就在今天,腾讯方面宣布将在2022年1月31日下架企业QQ和营销QQ,其实这一消息的降临并不让笔者意外,因为早在今年的10月28日20点之后,企业QQ和营销QQ就被停止了续费服务。相信很多...【详细内容】
2021-12-27  Tags:   点击:(2)  评论:(0)  加入收藏
一、前言有朋友问:怎么才能让Windows电脑与iPhone方便的交换文件,我的解决方案是:利用Documents By Readdle 来完成Windows 11 与 iPhone / iPad 互传文件。苹果电脑与手机间通...【详细内容】
2021-12-27  Tags:   点击:(1)  评论:(0)  加入收藏
果粉之家,专业苹果手机技术研究十年!您身边的苹果专家~近日,网上突然出现一则 iPhone 信号问题只需10块钱就能解决的传言,引起了小编(果粉之家)的特别关注。而根据网友表示,手机只...【详细内容】
2021-12-27  Tags:   点击:(1)  评论:(0)  加入收藏
这是很久以前的一则数据,我在iOS平台开发了“先知 - 优质生活”App,本想依靠封闭式环境,广告少体验不错等优点。会有一定的下载量,没想到开发完成后,就被App store埋藏起来了。个...【详细内容】
2021-12-27  Tags:   点击:(2)  评论:(0)  加入收藏
个人所得税递延纳税报告【业务概述】自然人符合规定条件的,可以申请个人所得税递延纳税,主要包括以下情形:1.非上市公司股权激励个人所得税递延纳税备案非上市公司授予本公司员...【详细内容】
2021-12-27  Tags:   点击:(2)  评论:(0)  加入收藏
Python 是一个很棒的语言。它是世界上发展最快的编程语言之一。它一次又一次地证明了在开发人员职位中和跨行业的数据科学职位中的实用性。整个 Python 及其库的生态系统使...【详细内容】
2021-12-27  Tags:   点击:(1)  评论:(0)  加入收藏
20年前,等离子电视凭借过硬的技术和显示效果,深受大众喜爱,人们也常说“外行买液晶,内行选等离子”,可见等离子电视在人们心中的地位不一般。现如今,大数据告诉我们,技术过硬不代表...【详细内容】
2021-12-27  Tags:   点击:(1)  评论:(0)  加入收藏
  1、明确产品的需求分析+功能  这是最基本的也是第一步,我们要明确自己或者客户真的想要开发一款app应用,其次就要了解到底要开发什么功能什么类别和种类的app应用。所...【详细内容】
2021-12-27  Tags:   点击:(1)  评论:(0)  加入收藏
菜单驱动程序简介菜单驱动程序是通过显示选项列表从用户那里获取输入并允许用户从选项列表中选择输入的程序。菜单驱动程序的一个简单示例是 ATM(自动取款机)。在交易的情况下...【详细内容】
2021-12-27  Tags:   点击:(1)  评论:(0)  加入收藏
▌简易百科推荐
摘 要 (OF作品展示)OF之前介绍了用python实现数据可视化、数据分析及一些小项目,但基本都是后端的知识。想要做一个好看的可视化大屏,我们还要学一些前端的知识(vue),网上有很多比...【详细内容】
2021-12-27  项目与数据管理    Tags:Vue   点击:(1)  评论:(0)  加入收藏
程序是如何被执行的  程序是如何被执行的?许多开发者可能也没法回答这个问题,大多数人更注重的是如何编写程序,却不会太注意编写好的程序是如何被运行,这并不是一个好...【详细内容】
2021-12-23  IT学习日记    Tags:程序   点击:(9)  评论:(0)  加入收藏
阅读收获✔️1. 了解单点登录实现原理✔️2. 掌握快速使用xxl-sso接入单点登录功能一、早期的多系统登录解决方案 单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器...【详细内容】
2021-12-23  程序yuan    Tags:单点登录(   点击:(8)  评论:(0)  加入收藏
下载Eclipse RCP IDE如果你电脑上还没有安装Eclipse,那么请到这里下载对应版本的软件进行安装。具体的安装步骤就不在这赘述了。创建第一个标准Eclipse RCP应用(总共分为六步)1...【详细内容】
2021-12-22  阿福ChrisYuan    Tags:RCP应用   点击:(7)  评论:(0)  加入收藏
今天想简单聊一聊 Token 的 Value Capture,就是币的价值问题。首先说明啊,这个话题包含的内容非常之光,Token 的经济学设计也可以包含诸多问题,所以几乎不可能把这个问题说的清...【详细内容】
2021-12-21  唐少华TSH    Tags:Token   点击:(9)  评论:(0)  加入收藏
实现效果:假如有10条数据,分组展示,默认在当前页面展示4个,点击换一批,从第5个开始继续展示,到最后一组,再重新返回到第一组 data() { return { qList: [], //处理后...【详细内容】
2021-12-17  Mason程    Tags:VUE   点击:(14)  评论:(0)  加入收藏
什么是性能调优?(what) 为什么需要性能调优?(why) 什么时候需要性能调优?(when) 什么地方需要性能调优?(where) 什么时候来进行性能调优?(who) 怎么样进行性能调优?(How) 硬件配...【详细内容】
2021-12-16  软件测试小p    Tags:性能调优   点击:(19)  评论:(0)  加入收藏
Tasker 是一款适用于 Android 设备的高级自动化应用,它可以通过脚本让重复性的操作自动运行,提高效率。 不知道从哪里听说的抖音 app 会导致 OLED 屏幕烧屏。于是就现学现卖,自...【详细内容】
2021-12-15  ITBang    Tags:抖音防烧屏   点击:(23)  评论:(0)  加入收藏
11 月 23 日,Rust Moderation Team(审核团队)在 GitHub 上发布了辞职公告,即刻生效。根据公告,审核团队集体辞职是为了抗议 Rust 核心团队(Core team)在执行社区行为准则和标准上...【详细内容】
2021-12-15  InfoQ    Tags:Rust   点击:(24)  评论:(0)  加入收藏
一个项目的大部分API,测试用例在参数和参数值等信息会有很多相似的地方。我们可以复制API,复制用例来快速生成,然后做细微调整既可以满足我们的测试需求1.复制API:在菜单发布单...【详细内容】
2021-12-14  AutoMeter    Tags:AutoMeter   点击:(20)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条