微服务Security+jwt+验证码实现认证和授权

  • 简要介绍
  • 基本流程
  • 核心代码
  • 测试

简要介绍

本次博客采用Spring Security、jwt、验证码的形式实现登录验证,项目本身是一个前后端分离项目。如果你的项目在登陆时不需要验证码,你只需要在后续的代码中,将有关验证码的过滤器删除。
gitee仓库连接

基本流程

1、前端请求后端"/captcha"验证码接口,后端生成验证码文本及编码并将其存入redis缓存,然后返回验证码文本(五个字符)和验证码base64编码给前端。
2、前端显示验证码图片,用户输入用户名、密码、验证码点击登录。
3、后端开启验证
(1)开启验证码验证,走验证码过滤器,如果正确则放行走下一个过滤器,如果错误则抛出异常给登录失败过滤器,返回失败信息给前端。
(2)开启jwt验证。

a:如果请求没有携带token,则认为是首次登录,jwt过滤器不做任何事情,放行走UsernamePasswordAuthenticationFilter过滤器,该过滤器会通过查数据库验证用户的身份信息决定用户是否能登录。如果验证成功会生成一个Authentication,并保存在SecurityContext(security上下文)中。Authentication包含用户的信息及权限
b:如果请求中携带了token,走jwt过滤器,过滤器判断jwt是否为空、携带信息(用户名)是否为空,jwt是否过期,如果上述条件都正常,创建一个Authentication的实现类对象,并通过自定义的获取用户权限方法获取权限,然后通过userDetailService的loadUserByUsername方法得到UserDetails对象,里面包含用户信息和权限,调用Authentication的setUserDetails方法,最后将该Authentication对象存入到Security上下文中,后续的过滤器查询到该Authentication,就会直接放行,比如UsernamePasswordAuthenticationFilter过滤器。

上述认证都是由过滤器完成,因为认证是有顺序的,所以在security配置文件中我们要设置这三个过滤器的顺序为:验证码过滤器=》jwt过滤器=》UsernamePasswordAuthenticationFilter

.addFilterBefore(captchaFilter,UsernamePasswordAuthenticationFilter.class)
.addFilterAt(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)

.addFilterAt(a,b)默认会将a设置在b之前。

至此登录认证就结束了,需要注意的是,我们在认证的时候已经将用户的权限列表加入到了Authentication并放在了Security上下文中,所以后续对于资源做权限判断时时,只需要再目标接口上加入一下注解实现。@PreAuthorize(“hasAuthority(‘sys:role:list’)”)
@PreAuthorize(“hasRole(‘ROLE_admin’)”)

当请求该接口时,security就会去Authentication中查询有无该权限或者该角色。

核心代码

1、验证码过滤器
该过滤器用于验证验证码是否正确。该过滤器继承的是OncePerRequestFilter,因为每次登录只需要验证一次。

package com.komorebi.security;import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.komorebi.common.CaptchaException;
import com.komorebi.common.Const;
import com.komorebi.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*CaptchaFilter用于验证码验证
* 因为验证码值需要一次校验,所以继承OncePerRequestFilter
* 自己写的过滤器要在security配置类中配置
* */
@Slf4j
@Component
public class CaptchaFilter extends OncePerRequestFilter {@AutowiredRedisUtil redisUtil;@AutowiredLoginFailureHandler loginFailureHandler;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {log.info("开始验证码验证");String url = request.getRequestURI();//只有登陆时才会验证验证码if("/login".equals(url) && request.getMethod().equals("POST")){try{//校验验证码validate(request);}catch (CaptchaException e){//发现异常,则交给登录失败处理器loginFailureHandler.onAuthenticationFailure(request,response,e);}}//将请求转发给下一个过滤器filterChain.doFilter(request,response);}//校验验证码逻辑private void validate(HttpServletRequest request) {String key = request.getParameter("tokens");String code = request.getParameter("code");if(StringUtils.isBlank(key) || StringUtils.isBlank(code)){throw new CaptchaException("验证码信息为空");}if(!code.equals(redisUtil.hget(Const.CAPTCHA_KEY,key))){throw new CaptchaException("验证码错误");}//保证每个验证码只使用一次:安全redisUtil.del(Const.CAPTCHA_KEY,key);}
}

2、jwt过滤器

package com.komorebi.security;import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.komorebi.entity.SysUser;
import com.komorebi.mapper.SysUserMapper;
import com.komorebi.service.SysUserService;
import com.komorebi.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;//jwt认证过滤器
@Slf4j
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {@AutowiredJwtUtils jwtUtils;@AutowiredUserDetailServiceImpl userDetailService;@AutowiredSysUserService sysUserService;public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {super(authenticationManager);}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {log.info("开启jwt认证");String jwt = request.getHeader(jwtUtils.getHeader());if(jwt != null){Claims claim = jwtUtils.getClaimByToken(jwt);if(claim != null){String username = claim.getSubject();log.info("jwt认证:检查用户名");if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){SysUser sysUser = sysUserService.getByUserName(username);Long userId = sysUser.getId();UserDetails userDetails = userDetailService.loadUserByUsername(username);if(!jwtUtils.isTokenExpired(claim)){UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null, userDetailService.getUserAuthority(userId));auth.setDetails(userDetails);log.info("通过jwt认证,设置Authentication,后续过滤器放行");SecurityContextHolder.getContext().setAuthentication(auth);}}}}else {log.info("首次登陆 jwt为空");}chain.doFilter(request,response);}
}

由于该过滤器我们继承于BasicAuthenticationFilter,也可以继承BasicAuthenticationFilter 类,并且重写了构造函数,所以在SecurityConfig中要采用Bean注入。对应SecurityConfig文件

@BeanJwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {return new JwtAuthenticationFilter(authenticationManager());}

3、UserDetailServiceImpl
UsernamePasswordAuthenticationFilter主要功能为:用户登录信息验证,获取用户权限,并将上述信息封装为UserDetails,然后生成Authentication,将UserDetails加入到Authentication中,最终将Authentication加入到security上下文中。
封装为UserDetails的功能是通过UserDetailService实现的,因为UserDetailService是接口,所以定义UserDetailServiceImpl实现该接口,即UserDetailServiceImpl用于验证用户信息和获取用用户权限。

package com.komorebi.security;import com.komorebi.entity.SysUser;
import com.komorebi.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;
@Slf4j
@Component
public class UserDetailServiceImpl implements UserDetailsService {@AutowiredSysUserService userService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {log.info("开始登陆验证,用户名为: {}",username);SysUser user = userService.getByUserName(username);if(user == null){log.info("用户名或密码不正确");throw new UsernameNotFoundException("用户名或密码不正确");}//UserDetails是接口,User是它的一个实现类//将用户密码告诉springSecurity//剩下的认证 就由框架Security帮我们完成return new User(user.getUsername(),user.getPassword(),getUserAuthority(user.getId()));}/*获取用户权限信息(角色,菜单权限)* */public List<GrantedAuthority> getUserAuthority(Long userId){//返回拥有角色和权限,逗号分隔String authority = userService.getUserAuthority(userId);//AuthorityUtils.commaSeparatedStringToAuthorityList将逗号分隔的字符串转为权限列表return AuthorityUtils.commaSeparatedStringToAuthorityList(authority);}
}

4、登陆成功过滤器

package com.komorebi.security;import cn.hutool.json.JSONUtil;
import com.komorebi.common.Result;
import com.komorebi.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Componentpublic class LoginSuccessHandler implements AuthenticationSuccessHandler{@AutowiredJwtUtils jwtUtils;@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("application/json;charset=UTF-8");ServletOutputStream outputStream = response.getOutputStream();String username = authentication.getName();// 生成jwt,并放置到请求头中String jwt = jwtUtils.generateToken(username);//将jwt放入response header中:Authorizationresponse.setHeader(jwtUtils.getHeader(), jwt);Result result = Result.success("登陆成功过滤器执行");outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));outputStream.flush();outputStream.close();}
}

这里,我们过滤器需要向前端传递json数据,但是security是不支持return json数据的,所以我们只能通过流的方式返回数据。
基本步骤:
(1)获取reponse的字节输出流
(2)创建返回对象
(3)将对象转为字节数组输出给response
(4)刷新缓冲区,关闭流
后续的过滤器只要涉及到返回数据给前端,都会使用该方法。
5、登陆失败过滤器

package com.komorebi.security;import cn.hutool.json.JSONUtil;
import com.komorebi.common.Result;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {response.setContentType("application/json;charset=UTF-8");//security的返回值是重定向,对于前后端分离的项目需要返回json数据,所以使用流的形式//因为返回类型是void,并且返回值是json类型数据,所以要使用到流ServletOutputStream outputStream = response.getOutputStream();Result result = Result.fail(exception.getMessage());outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));outputStream.flush();outputStream.close();}
}

6、登出成功过滤器
该处理器会返还给前端一个空的jwt,即前端下次请求时jwt为空,代表未登录。如果是将jwt存在redis中,还要清除缓存。

package com.komorebi.security;import cn.hutool.json.JSONUtil;
import com.komorebi.common.Const;
import com.komorebi.common.Result;
import com.komorebi.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtLogoutSuccessHandler implements LogoutSuccessHandler {@AutowiredJwtUtils jwtUtils;@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {System.out.println("退出成功处理器");//如果认证的身份凭证不为空,需要手动退出if(authentication != null){new SecurityContextLogoutHandler().logout(request,response,authentication);}response.setContentType("application/json;charset=UTF-8");ServletOutputStream outputStream = response.getOutputStream();//等处成功将jwt设置为空,因为jwt是无状态的只能在过期后消失response.setHeader(jwtUtils.getHeader(),"");Result result = Result.success("登出成功");outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));outputStream.flush();outputStream.close();}
}

7、权限不足过滤器
该过滤器是用于处理权限不足时的情况。

package com.komorebi.security;import cn.hutool.json.JSONUtil;
import com.komorebi.common.Result;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {response.setContentType("application/json;charset=UTF-8");ServletOutputStream outputStream = response.getOutputStream();//权限不足response.setStatus(HttpServletResponse.SC_FORBIDDEN);Result result = Result.fail(accessDeniedException.getMessage());outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));outputStream.flush();outputStream.close();}
}

8、未认证过滤器
该过滤器是用于处理用户未登录的情况。

package com.komorebi.security;import cn.hutool.json.JSONUtil;
import com.komorebi.common.Result;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {response.setContentType("application/json;charset=UTF-8");ServletOutputStream outputStream = response.getOutputStream();//未认证response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);Result result = Result.fail("请先登录");outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));outputStream.flush();outputStream.close();}
}

9、JWT工具类

package com.komorebi.utils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.Date;
@Data
@Component
@ConfigurationProperties(prefix = "komorebi.jwt")
//通过配置文件赋值expire、secret
public class JwtUtils {//两个是参数private long expire;//保留天数private String secret;//密钥private String header;//{header:jwt}传给前端//生成jwtpublic String generateToken(String username){Date nowDate = new Date();Date expireDate = new Date(nowDate.getTime() * expire);return Jwts.builder().setHeaderParam("typ","JWT").setSubject(username).setIssuedAt(nowDate).setExpiration(expireDate).signWith(SignatureAlgorithm.HS256,secret).compact();}//解析jwtpublic Claims getClaimByToken(String jwt){try{return Jwts.parser().setSigningKey(secret).parseClaimsJws(jwt).getBody();}catch (Exception e){return null;}}//jwt是否过期public boolean isTokenExpired(Claims claims){//如果过期时间在当前时间之前,就代表过期return claims.getExpiration().before(new Date());}
}

expire、secret、header三个变量存放在application.yml文件中

通过该注解@ConfigurationProperties(prefix = “komorebi.jwt”)实现通过配置文件赋值expire、secret、header。
10、SecurityConfig
该配置类会对前面定义的所有过滤器进行配置

package com.komorebi.config;import com.komorebi.security.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredLoginSuccessHandler loginSuccessHandler;@AutowiredLoginFailureHandler loginFailureHandler;@AutowiredCaptchaFilter captchaFilter;@AutowiredJwtAccessDeniedHandler jwtAccessDeniedHandler;@AutowiredJwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;@AutowiredUserDetailsService userDetailService;@AutowiredJwtLogoutSuccessHandler  jwtLogoutSuccessHandler;@BeanJwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {return new JwtAuthenticationFilter(authenticationManager());}@BeanBCryptPasswordEncoder bCryptPasswordEncoder(){return new BCryptPasswordEncoder();}//Java数组初始化用的是{花括号}//URL白名单,访问时不需要拦截private static final String [] URL_WHITELIST = {"/login","/logout","/captcha","/favicon.ico",};@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {//设置userDetail和加密方法auth.userDetailsService(userDetailService).passwordEncoder(new BCryptPasswordEncoder());}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors().and().csrf().disable()//登陆配置.formLogin().successHandler(loginSuccessHandler)//登陆成功处理器.failureHandler(loginFailureHandler)//登录失败处理器//退出.and().logout().logoutSuccessHandler(jwtLogoutSuccessHandler)//设置不生成session策略.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)//配置拦截规则.and().authorizeRequests().antMatchers(URL_WHITELIST).permitAll()//所有人都可以访问.anyRequest().authenticated()//需要登陆,即需要认证//异常处理器.and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)//没有认证.accessDeniedHandler(jwtAccessDeniedHandler)//没有权限//配置自定义的过滤器=》前置过滤器.and().addFilterBefore(captchaFilter,UsernamePasswordAuthenticationFilter.class).addFilterAt(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);}
}

测试

1、当验证码错误时

2、验证码、密码正确时(没有携带jwt登录)

此时会返回token

3、携带jwt请求后端接口

@RestController
@RequestMapping("/test")
public class TestController {@AutowiredSysUserService sysUserService;@GetMapping@PreAuthorize("hasRole('admin')")public Object test(){return Result.success(sysUserService.list());}
}

/test接口需要用户具备admin角色,此处登录的用户具有该角色,则访问成功。

4、对于需要某种权限或者角色才能访问的后端接口只需要在节后上面进行设置

(1)需要权限才能访问

//新增@PostMapping("/save")@PreAuthorize("hasAuthority('sys:role:save')")public Result save(@Validated @RequestBody SysRole sysRole){//添加时设置create时间sysRole.setCreated(LocalDateTime.now());sysRole.setStatu(Const.STATUS_ON);sysRoleService.save(sysRole);return Result.success(sysRole);}

(2)需要用于某种角色才可以访问

@RestController
@RequestMapping("/test")
public class TestController {@AutowiredSysUserService sysUserService;@GetMapping@PreAuthorize("hasRole('admin')")public Object test(){return Result.success(sysUserService.list());}
}

此处登录的用户不具备该角色,所以会走权限不足过滤器

Security+jwt+验证码实现验证和授权相关推荐

  1. Spring Boot+Spring Security+JWT 实现token验证

    Spring Boot+Spring Security+JWT 实现token验证 什么是JWT? JWT的工作流程 JWT的主要应用场景 JWT的结构 SpringBoot+Spring Secur ...

  2. 如何使用JWT进行身份验证与授权

    简介 JWT定义了一种紧凑的.自包含的方式,用于作为JSON对象在各方之间安全地传输信息.该信息可以被验证和信任,因为它是数字签名的. 工作流程 1.用户使用账号.密码登录应用,登录的请求发送到认证服 ...

  3. .NET6之MiniAPI(九):基于角色的身份验证和授权

    身份验证是这样一个过程:由用户提供凭据,然后将其与存储在操作系统.数据库.应用或资源中的凭据进行比较. 在授权过程中,如果凭据匹配,则用户身份验证成功,可执行已向其授权的操作. 授权指判断允许用户执行 ...

  4. 使用JWT的ASP.NET CORE令牌身份验证和授权(无Cookie)——第1部分

    目录 介绍 JWT(JSON Web令牌) ASP.NET Core中的JWToken配置 用户模型类 创建令牌 第1步 第2步 第4步 令牌存储 中间件 自定义中间件app.Use() 中间件app ...

  5. Spring Security简单的登陆验证授权

    Spring Security的介绍就省略了,直接记录一下登陆验证授权的过程. Spring Security的几个重要词 1.SecurityContextHolder:是安全上下文容器,可以在此得 ...

  6. Springboot Spring Security +Jwt+redis+mybatisPlus 动态完成 前后端分离认证授权

    Springboot Spring Security +Jwt 动态完成 前后端分离认证授权 文章目录 Springboot Spring Security +Jwt 动态完成 前后端分离认证授权 前 ...

  7. 使用Spring Security Oauth2 和 JWT保护微服务--Uaa授权服务器的编写

    学习自深入理解微服务 采用Spring Security OAuth2 和 JWT的方式,Uaa服务只需要验证一次,返回JWT.返回的JWT包含了用户的所有信息,包括权限信息 从三个方面讲解: JWT ...

  8. 【.NET Core项目实战-统一认证平台】第十二章 授权篇-深入理解JWT生成及验证流程...

    上篇文章介绍了基于Ids4密码授权模式,从使用场景.原理分析.自定义帐户体系集成完整的介绍了密码授权模式的内容,并最后给出了三个思考问题,本篇就针对第一个思考问题详细的讲解下Ids4是如何生成acce ...

  9. 使用JWT的ASP.NET CORE令牌身份验证和授权(无Cookie)——第2部分

    目录 介绍 用户角色 如何创建自定义授权特性? AuthorizeAttribute AuthorizeFilter 如何在控制器和操作方法级别设置权限? 检查用户权限的扩展方法 如何在操作方法(内联 ...

最新文章

  1. NeurIPS提前看 | 四篇论文,一窥元学习的最新研究进展
  2. 图片点击放大并可点击旋转插件(1)-jquery.artZoom.js
  3. js \n直接显示字符串_显示N个字符的最短时间
  4. 后续的C++测试并不一定会成功
  5. 添加class值_Java 虚拟机(二) - Class 文件结构
  6. Python自动化之高级语法单例模式
  7. 3 个 Zabbix常见问题的处理方法
  8. 在hibernate框架中,自己如何使用框架自己生成建表语句
  9. 为什么这本搜索引擎营销的书畅销呢?
  10. 重命名Docker容器名称
  11. 计算机基础ps变换蝴蝶,在PS中用自由变换制作飞舞的蝴蝶和用内容识别比例缩放的操作过程...
  12. 基于IP搭建SAN存储
  13. 易语言程序假死优化_易语言假死无响应采用处理事件解决办法
  14. 阿里云携手开源中国平台发百万悬赏项目
  15. 由JVM深入了解Java的线程安全与锁优化
  16. [表格扫描OCR]快速扫描识别并获取表格图片内容[免费]
  17. 针对Android TV端使用的自定义RecyclerView
  18. resample 重采样
  19. 必须掌握的电脑快捷键
  20. ×××S 2012 仪表 -- 关键绩效指标

热门文章

  1. AIX下RAC搭建 Oracle10G(一)检測系统环境
  2. Klockwork告警常见错误
  3. Android系统编译so库提示error undefined reference to '__android_log_print问题的解决
  4. android camera(三):camera V4L2 FIMC
  5. css中小型大写,css3 – OpenType小型大写的CSS回退
  6. 介绍一款facebook信息收集工具FBI
  7. Qt5标准文件对话框类
  8. 数据库01-范式总结
  9. 启动mysql的innodb monitor功能
  10. 第二个例子:单链表实现基排序(桶排序)