当前位置: 首页 > news >正文

开发设计移动网站建设广西住房和城乡建设厅官方网站

开发设计移动网站建设,广西住房和城乡建设厅官方网站,建购物网站需要多少钱,成品影视app下载有哪些软件系列文章 ruoyi若依框架学习笔记-01 ruoyi若依框架分页实现分析 ruoyi若依框架SpringSecurity实现分析 文章目录 系列文章前言具体分析一、项目中的SpringSecurity版本二、登录认证流程分析三、权限鉴定四、退出登录五、SpringSecurity配置类 总结 前言 在ruoyi-vue若依框…系列文章 ruoyi若依框架学习笔记-01 ruoyi若依框架分页实现分析 ruoyi若依框架SpringSecurity实现分析 文章目录 系列文章前言具体分析一、项目中的SpringSecurity版本二、登录认证流程分析三、权限鉴定四、退出登录五、SpringSecurity配置类 总结 前言 在ruoyi-vue若依框架中使用到了SpringSecurity作为认证授权的技术栈。今天来分析一下若依中是如何实现认证授权的。 具体分析 一、项目中的SpringSecurity版本 可见当前springsecurity的版本还是相对比较旧的security5。所以我们在自己的项目中可以对此进行重构升级成security6的版本。但目前只是先分析一下它的实现原理。 二、登录认证流程分析 首先看一下登录控制器 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java PostMapping(/login)public AjaxResult login(RequestBody LoginBody loginBody){AjaxResult ajax AjaxResult.success();// 生成令牌String token loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),loginBody.getUuid());ajax.put(Constants.TOKEN, token);return ajax;}内容比较简单我们去看一下login方法 public String login(String username, String password, String code, String uuid){// 验证码校验validateCaptcha(username, code, uuid);// 登录前置校验loginPreCheck(username, password);// 用户验证Authentication authentication null;try{//UsernamePasswordAuthenticationToken是Authenticatiion的实现类UsernamePasswordAuthenticationToken authenticationToken new UsernamePasswordAuthenticationToken(username, password);//这里设置成上下文的意图是在身份验证过程中//其他组件或方法可以获取到该对象以便进行相关的操作//比如记录登录日志、获取用户信息等。AuthenticationContextHolder.setContext(authenticationToken);// 该方法会去调用UserDetailsServiceImpl.loadUserByUsernameauthentication authenticationManager.authenticate(authenticationToken);}catch (Exception e){if (e instanceof BadCredentialsException){//这里去使用日志记录相关错误AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message(user.password.not.match)));throw new UserPasswordNotMatchException();}else{AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));throw new ServiceException(e.getMessage());}}finally{//最后要在对应操作完成之后清理ContextAuthenticationContextHolder.clearContext();}AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message(user.login.success)));//这里就是拿到自定义封装的用户信息LoginUser loginUser (LoginUser) authentication.getPrincipal();//将登录信息存入到数据库recordLoginInfo(loginUser.getUserId());// 生成tokenreturn tokenService.createToken(loginUser);}然后我们去看一下loadUserByUsername方法 com.ruoyi.framework.web.service.UserDetailsServiceImpl Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{//从数据库中查询相关用户数据SysUser user userService.selectUserByUserName(username);if (StringUtils.isNull(user)){log.info(登录用户{} 不存在., username);throw new ServiceException(MessageUtils.message(user.not.exists));}else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())){log.info(登录用户{} 已被删除., username);throw new ServiceException(MessageUtils.message(user.password.delete));}else if (UserStatus.DISABLE.getCode().equals(user.getStatus())){log.info(登录用户{} 已被停用., username);throw new ServiceException(MessageUtils.message(user.blocked));}//密码校验这里主要是看用户在短时间内输错了多少次密码防止过分重复登录passwordService.validate(user);//将用户信息封装成我们自定义的LoginUser对象他是UserDetails的实现类return createLoginUser(user);}public UserDetails createLoginUser(SysUser user){return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));}由于框架本身的UserDetails对象无法满足我们的需求所以需要自定义一个实现类。 这里是UserDetails的实现类com.ruoyi.common.core.domain.model.LoginUser#serialVersionUID public class LoginUser implements UserDetails {private static final long serialVersionUID 1L;/*** 用户ID*/private Long userId;/*** 部门ID*/private Long deptId;/*** 用户唯一标识*/private String token;/*** 登录时间*/private Long loginTime;/*** 过期时间*/private Long expireTime;/*** 登录IP地址*/private String ipaddr;/*** 登录地点*/private String loginLocation;/*** 浏览器类型*/private String browser;/*** 操作系统*/private String os;/*** 权限列表*/private SetString permissions;/*** 用户信息*/private SysUser user;public LoginUser(){}public LoginUser(SysUser user, SetString permissions){this.user user;this.permissions permissions;}public LoginUser(Long userId, Long deptId, SysUser user, SetString permissions){this.userId userId;this.deptId deptId;this.user user;this.permissions permissions;}public Long getUserId(){return userId;}public void setUserId(Long userId){this.userId userId;}public Long getDeptId(){return deptId;}public void setDeptId(Long deptId){this.deptId deptId;}public String getToken(){return token;}public void setToken(String token){this.token token;}JSONField(serialize false)Overridepublic String getPassword(){return user.getPassword();}Overridepublic String getUsername(){return user.getUserName();}/*** 账户是否未过期,过期无法验证*/JSONField(serialize false)Overridepublic boolean isAccountNonExpired(){return true;}/*** 指定用户是否解锁,锁定的用户无法进行身份验证* * return*/JSONField(serialize false)Overridepublic boolean isAccountNonLocked(){return true;}/*** 指示是否已过期的用户的凭据(密码),过期的凭据防止认证* * return*/JSONField(serialize false)Overridepublic boolean isCredentialsNonExpired(){return true;}/*** 是否可用 ,禁用的用户不能身份验证* * return*/JSONField(serialize false)Overridepublic boolean isEnabled(){return true;}public Long getLoginTime(){return loginTime;}public void setLoginTime(Long loginTime){this.loginTime loginTime;}public String getIpaddr(){return ipaddr;}public void setIpaddr(String ipaddr){this.ipaddr ipaddr;}public String getLoginLocation(){return loginLocation;}public void setLoginLocation(String loginLocation){this.loginLocation loginLocation;}public String getBrowser(){return browser;}public void setBrowser(String browser){this.browser browser;}public String getOs(){return os;}public void setOs(String os){this.os os;}public Long getExpireTime(){return expireTime;}public void setExpireTime(Long expireTime){this.expireTime expireTime;}public SetString getPermissions(){return permissions;}public void setPermissions(SetString permissions){this.permissions permissions;}public SysUser getUser(){return user;}public void setUser(SysUser user){this.user user;}Overridepublic Collection? extends GrantedAuthority getAuthorities(){return null;} } 其实我觉得最后应该也要重写getAuthorities()方法内部如下 if (ObjectUtils.isEmpty(authorities)) {authorities new ArrayList();permissions.forEach(permission - authorities.add(()-permission));}return authorities;还望大佬发表看法。 在ruoyi-vue中有对认证失败的处理类 com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl 在其中直接将错误信息渲染返回给前端 Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)throws IOException{int code HttpStatus.UNAUTHORIZED;String msg StringUtils.format(请求访问{}认证失败无法访问系统资源, request.getRequestURI());ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));}当用户需要访问其他接口的时候我们需要验证请求头中是否携带合法的token并将用户信息存入Authentication中。 在com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter中有token过滤器验证token有效性。 Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {Autowiredprivate TokenService tokenService;Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException{//从token中获取用户信息封装成LoginUser对象LoginUser loginUser tokenService.getLoginUser(request);if (StringUtils.isNotNull(loginUser) StringUtils.isNull(SecurityUtils.getAuthentication())){//验证token是否合法tokenService.verifyToken(loginUser);//封装成authentication对象UsernamePasswordAuthenticationToken authenticationToken new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());//设置详细信息可以获取到请求的详细信息例如请求的IP地址、请求的会话ID等。//设置详细信息可以帮助记录日志、进行安全审计和监控等操作authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authenticationToken);}chain.doFilter(request, response);} } 三、权限鉴定 我们先看一下controller层方法的上面的注解 ss.hasPermi(‘system:menu:list’)的意思是调用ss这个容器下的hasPermi方法 可以看到ruoyi是自定义的权限校验方法。那我们来看一下这个容器 com.ruoyi.framework.web.service.PermissionService Service(ss) public class PermissionService {/*** 验证用户是否具备某权限* * param permission 权限字符串* return 用户是否具备某权限*/public boolean hasPermi(String permission){if (StringUtils.isEmpty(permission)){return false;}LoginUser loginUser SecurityUtils.getLoginUser();if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())){return false;}PermissionContextHolder.setContext(permission);return hasPermissions(loginUser.getPermissions(), permission);}/*** 验证用户是否不具备某权限与 hasPermi逻辑相反** param permission 权限字符串* return 用户是否不具备某权限*/public boolean lacksPermi(String permission){return hasPermi(permission) ! true;}/*** 验证用户是否具有以下任意一个权限** param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表* return 用户是否具有以下任意一个权限*/public boolean hasAnyPermi(String permissions){if (StringUtils.isEmpty(permissions)){return false;}LoginUser loginUser SecurityUtils.getLoginUser();if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())){return false;}PermissionContextHolder.setContext(permissions);SetString authorities loginUser.getPermissions();for (String permission : permissions.split(Constants.PERMISSION_DELIMETER)){if (permission ! null hasPermissions(authorities, permission)){return true;}}return false;}/*** 判断用户是否拥有某个角色* * param role 角色字符串* return 用户是否具备某角色*/public boolean hasRole(String role){if (StringUtils.isEmpty(role)){return false;}LoginUser loginUser SecurityUtils.getLoginUser();if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())){return false;}for (SysRole sysRole : loginUser.getUser().getRoles()){String roleKey sysRole.getRoleKey();if (Constants.SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role))){return true;}}return false;}/*** 验证用户是否不具备某角色与 isRole逻辑相反。** param role 角色名称* return 用户是否不具备某角色*/public boolean lacksRole(String role){return hasRole(role) ! true;}/*** 验证用户是否具有以下任意一个角色** param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表* return 用户是否具有以下任意一个角色*/public boolean hasAnyRoles(String roles){if (StringUtils.isEmpty(roles)){return false;}LoginUser loginUser SecurityUtils.getLoginUser();if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())){return false;}for (String role : roles.split(Constants.ROLE_DELIMETER)){if (hasRole(role)){return true;}}return false;}/*** 判断是否包含权限* * param permissions 权限列表* param permission 权限字符串* return 用户是否具备某权限*/private boolean hasPermissions(SetString permissions, String permission){return permissions.contains(Constants.ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));} }别忘了在配置类中加上注解 EnableGlobalMethodSecurity(prePostEnabled true, securedEnabled true) 这里就不具体一个一个分析了因为比较简单都是很容易看懂的。 四、退出登录 若依中还自定义了退出登录处理类com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl Configuration public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {Autowiredprivate TokenService tokenService;/*** 退出处理* * return*/Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)throws IOException, ServletException{LoginUser loginUser tokenService.getLoginUser(request);if (StringUtils.isNotNull(loginUser)){String userName loginUser.getUsername();// 删除用户缓存记录tokenService.delLoginUser(loginUser.getToken());// 记录用户退出日志AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message(user.logout.success)));}//返回信息交给前端渲染ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success(MessageUtils.message(user.logout.success))));} }五、SpringSecurity配置类 EnableGlobalMethodSecurity(prePostEnabled true, securedEnabled true) public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 自定义用户认证逻辑*/Autowiredprivate UserDetailsService userDetailsService;/*** 认证失败处理类*/Autowiredprivate AuthenticationEntryPointImpl unauthorizedHandler;/*** 退出处理类*/Autowiredprivate LogoutSuccessHandlerImpl logoutSuccessHandler;/*** token认证过滤器*/Autowiredprivate JwtAuthenticationTokenFilter authenticationTokenFilter;/*** 跨域过滤器*/Autowiredprivate CorsFilter corsFilter;/*** 允许匿名访问的地址*///这里我先不分析以后补上Autowiredprivate PermitAllUrlProperties permitAllUrl;/*** 解决 无法直接注入 AuthenticationManager** return* throws Exception*/BeanOverridepublic AuthenticationManager authenticationManagerBean() throws Exception{return super.authenticationManagerBean();}/*** anyRequest | 匹配所有请求路径* access | SpringEl表达式结果为true时可以访问* anonymous | 匿名可以访问* denyAll | 用户不能访问* fullyAuthenticated | 用户完全认证可以访问非remember-me下自动登录* hasAnyAuthority | 如果有参数参数表示权限则其中任何一个权限可以访问* hasAnyRole | 如果有参数参数表示角色则其中任何一个角色可以访问* hasAuthority | 如果有参数参数表示权限则其权限可以访问* hasIpAddress | 如果有参数参数表示IP地址如果用户IP和参数匹配则可以访问* hasRole | 如果有参数参数表示角色则其角色可以访问* permitAll | 用户可以任意访问* rememberMe | 允许通过remember-me登录的用户访问* authenticated | 用户登录后可访问*/Overrideprotected void configure(HttpSecurity httpSecurity) throws Exception{// 注解标记允许匿名访问的urlExpressionUrlAuthorizationConfigurerHttpSecurity.ExpressionInterceptUrlRegistry registry httpSecurity.authorizeRequests();permitAllUrl.getUrls().forEach(url - registry.antMatchers(url).permitAll());//我主要看这部分httpSecurity// CSRF禁用因为不使用session.csrf().disable()// 禁用HTTP响应标头.headers().cacheControl().disable().and()// 认证失败处理类.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()// 基于token所以不需要session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()// 过滤请求.authorizeRequests()// 对于登录login 注册register 验证码captchaImage 允许匿名访问.antMatchers(/login, /register, /captchaImage).permitAll()// 静态资源可匿名访问.antMatchers(HttpMethod.GET, /, /*.html, /**/*.html, /**/*.css, /**/*.js, /profile/**).permitAll().antMatchers(/swagger-ui.html, /swagger-resources/**, /webjars/**, /*/api-docs, /druid/**).permitAll()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated().and().headers().frameOptions().disable();// 添加Logout filterhttpSecurity.logout().logoutUrl(/logout).logoutSuccessHandler(logoutSuccessHandler);// 添加JWT filterhttpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);// 添加CORS filterhttpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);}/*** 强散列哈希加密实现*/Beanpublic BCryptPasswordEncoder bCryptPasswordEncoder(){return new BCryptPasswordEncoder();}/*** 身份认证接口*/Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception{auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());} }总结 其实ruoyi-vue中对SpringSecurity的使用非常时候我们用来复习SpringSecurity以及学习它的编码风格绝对收益不浅。
http://www.pierceye.com/news/514076/

相关文章:

  • 网站设置不能通过链接访问中专网站建设与管理就业前景
  • 大连网站建设哪个公司好郑州最新通告
  • 如何自己搭建网站做装修的业务网站
  • app网站的优点手机自助建站永久免费
  • 搜索栏搜索网站?热?文市场调研流程
  • 外贸网站建设课本建设网站群的好处
  • 网站开发文献综述范文网络推广计划书格式
  • 有免费网站服务器吗在线美图
  • 电商网站设计的原则免费下载app软件下载大全
  • 餐饮网站建设优化建站wordpress copyright
  • 腾讯建站官网设计网页步骤
  • 网站建设三方合同范本wordpress数字链接出现404
  • 下载用的网站怎么做网站模板怎么使用教程
  • 没有网站 可以做百度口碑吗展馆的科普网站建设
  • 河北网站备案查询系统商城网站seo
  • 网站申请页面网站空间不够用怎么办
  • 网站开发最合适的搭配螺栓球网架
  • 广东网站建设排名凡科建站下载
  • 建设厅网站预算员报名时间网站建设策划书的编制
  • 厦门手机网站建设公司哪家好鲜花网站源码
  • 北京家居网站建设如何制作软件手机软件
  • 北京网站建设策划解决方案长沙建设工程造价网站
  • 北京网站设计公司价格阿里云wordpress插件
  • 网站建设自助建站企业萧山人才网手机版
  • 长沙建站挺找有为太极wordpress 需要zend
  • 通信管理局 网站备案天猫网站设计教程
  • 营销型网站制作成都打造品牌的三点策略
  • 做查工资的网站如何下载网页在线视频
  • 北沙滩网站建设公司主页怎么填
  • 手机asp网站网站设计方案