如图红色框

问题:

1.认证

1.1 什么是认证,什么时候认证,认证什么东西,怎么算成功,怎么算失败

1.2 认证失败怎么处理

1.3 与jwt关系

2.鉴权

1.1 什么是鉴权,如何鉴权,鉴权什么东西,怎么算成功,怎么算失败

1.2 鉴权失败怎么处理

1.3 与jwt关系

---------------------------------------------------------------------------------------------------------------------------

答:

1.认证

1.1

什么是认证:就是验签(常规的签名,验签),根据token和秘钥secret解析jwt

什么时候:调用接口时需要传递token进行认证;

认证什么:校验用户名,操作用户是否是登录用户,token是不过期

失败:根据token反解jwt异常,如下

 private Claims getClaimsFromToken(String token) {Claims claims = null;try {claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();} catch (Exception e) {LOGGER.info("JWT格式验证失败:{}", token, e);}return claims;}

1.2

调用接口,走jwt过滤器,因为无法根据token解析jwt,无法后续认证(用户名,过期),过掉这个调用链。需要自定义一个认证失败处理器。两种方式,见下

/*** 当未登录或者token失效访问接口时,自定义的返回结果*/
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
//public class RestAuthenticationEntryPoint implements AuthenticationFailureHandler {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {response.setCharacterEncoding("UTF-8");response.setContentType("application/json");response.getWriter().println(JSON.toJSONString(BaseResult.unauthorized(authException.getMessage())));response.getWriter().flush();}//    @Override
//    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
//                    AuthenticationException e) throws IOException, ServletException {
//
//    }
}

1.3

在springSecurigy config加入 认证过滤器,以下代码为securityConfig

见:::://添加自定义未授权和未登录结果返回

2.鉴权

先说一下权限控制,有两种

1.返回有权限的菜单或按钮,不可见即没权限;2.看不见,如果直接调接口,无权限也无法访问

这里鉴权就是针对第二种情况

2.1 什么是鉴权:带token调某接口,该用户是否有权限

2.2 如何鉴权:纯security 与 jwt无关。也有关系,调接口都要走jwt过滤器,在过滤器中调用了渲染权限的接口,见 JwtAuthenticationTokenFilter

2.2.1 调接口时实时从数据库中取用户权限信息,放入security

2.2.2 在每一个接口上加权限注解 @PreAuthorize,标明当前接口权限 如:

    @Override@Beanpublic UserDetailsService userDetailsService() {//获取登录用户信息return username -> {SysUser sysUser = sysUserService.getAdminByUsername(username);if (sysUser != null) {List<SysPermission> permissionList = sysUserService.getPermissionList(sysUser.getId());return new AdminUserDetails(sysUser, permissionList);}throw new UsernameNotFoundException("用户名或密码错误");};}
    @PreAuthorize("hasAuthority('product')")@GetMapping("myRoom")@ApiOperation("我的直播间")public BaseResult<ResTextLiveProgramVo> myChatRoom() {return textLiveProgrammeService.myChatRoom();}

怎么算成功,怎么算失败:security封装好了

1.2 鉴权失败怎么处理

以上工作完成后,无权限报错: 不允许访问,这是security封装的异常消息。我们可以自定义自己的无权限处理类

/*** 访问接口没有权限时,自定义的返回结果*/
@Component
public class RestfulAccessDeniedHandler implements AccessDeniedHandler{@Overridepublic void handle(HttpServletRequest request,HttpServletResponse response,AccessDeniedException e) throws IOException, ServletException {response.setCharacterEncoding("UTF-8");response.setContentType("application/json");response.getWriter().println(JSON.toJSONString(BaseResult.forbidden(e.getMessage())));response.getWriter().flush();}
}

1.3 与jwt关系

见上2.2,

        //添加自定义未授权和未登录结果返回httpSecurity.exceptionHandling().accessDeniedHandler(restfulAccessDeniedHandler).authenticationEntryPoint(restAuthenticationEntryPoint);

SecurityConfig

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate ISysUserService sysUserService;@Autowiredprivate RestfulAccessDeniedHandler restfulAccessDeniedHandler;@Autowiredprivate RestAuthenticationEntryPoint restAuthenticationEntryPoint;@Overrideprotected void configure(HttpSecurity httpSecurity) throws Exception {httpSecurity.csrf()// 由于使用的是JWT,我们这里不需要csrf.disable().sessionManagement()// 基于token,所以不需要session.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers(HttpMethod.GET, // 允许对于网站静态资源的无授权访问"/","/*.html","/favicon.ico","/**/*.html","/**/*.css","/**/*.js","/swagger-resources/**","/v2/api-docs/**").permitAll().antMatchers("/sys/user/login", "/sys/user/register")// 对登录注册要允许匿名访问.permitAll().antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求.permitAll().antMatchers("/**")//测试时全部运行访问.permitAll().anyRequest()// 除上面外的所有请求全部需要鉴权认证.authenticated();// 禁用缓存httpSecurity.headers().cacheControl();// 添加JWT filterhttpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);//添加自定义未授权和未登录结果返回httpSecurity.exceptionHandling().accessDeniedHandler(restfulAccessDeniedHandler).authenticationEntryPoint(restAuthenticationEntryPoint);}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Override@Beanpublic UserDetailsService userDetailsService() {//获取登录用户信息return username -> {SysUser sysUser = sysUserService.getAdminByUsername(username);if (sysUser != null) {List<SysPermission> permissionList = sysUserService.getPermissionList(sysUser.getId());return new AdminUserDetails(sysUser, permissionList);}throw new UsernameNotFoundException("用户名或密码错误");};}@Beanpublic JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){return new JwtAuthenticationTokenFilter();}/*** 允许跨域调用的过滤器*/@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration config = new CorsConfiguration();config.addAllowedOrigin("*");config.setAllowCredentials(true);config.addAllowedHeader("*");config.addAllowedMethod("*");source.registerCorsConfiguration("/**", config);FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(source));bean.setOrder(0);return new CorsFilter(source);}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}}

JwtAuthenticationTokenFilter

public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class);@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate JwtTokenUtil jwtTokenUtil;@Value("${jwt.tokenHeader}")private String tokenHeader;@Value("${jwt.tokenHead}")private String tokenHead;@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws ServletException, IOException {String authHeader = request.getHeader(this.tokenHeader);if (authHeader != null && authHeader.startsWith(this.tokenHead)) {String authToken = authHeader.substring(this.tokenHead.length());// The part after "Bearer "String username = jwtTokenUtil.getUserNameFromToken(authToken);LOGGER.info("checking username:{}", username);if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);if (jwtTokenUtil.validateToken(authToken, userDetails)) {UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));LOGGER.info("authenticated user:{}", username);SecurityContextHolder.getContext().setAuthentication(authentication);}}}chain.doFilter(request, response);}
}

JwtTokenUtil

/*** JwtToken生成的工具类* JWT token的格式:header.payload.signature* header的格式(算法、token的类型):* {"alg": "HS512","typ": "JWT"}* payload的格式(用户名、创建时间、生成时间):* {"sub":"wang","created":1489079981393,"exp":1489684781}* signature的生成算法:* HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)* Created by macro on 2018/4/26.*/
@Component
public class JwtTokenUtil {private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);private static final String CLAIM_KEY_USERNAME = "sub";private static final String CLAIM_KEY_CREATED = "created";@Value("${jwt.secret}")private String secret;@Value("${jwt.expiration}")private Long expiration;/*** 根据负责生成JWT的token*/private String generateToken(Map<String, Object> claims) {return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate()).signWith(SignatureAlgorithm.HS512, secret).compact();}/*** 从token中获取JWT中的负载*/private Claims getClaimsFromToken(String token) {Claims claims = null;try {claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();} catch (Exception e) {LOGGER.info("JWT格式验证失败:{}", token, e);}return claims;}/*** 生成token的过期时间*/private Date generateExpirationDate() {return new Date(System.currentTimeMillis() + expiration * 1000);}/*** 从token中获取登录用户名*/public String getUserNameFromToken(String token) {String username;try {Claims claims = getClaimsFromToken(token);username =  claims.getSubject();} catch (Exception e) {username = null;}return username;}/*** 验证token是否还有效** @param token       客户端传入的token* @param userDetails 从数据库中查询出来的用户信息*/public boolean validateToken(String token, UserDetails userDetails) {String username = getUserNameFromToken(token);return username.equals(userDetails.getUsername()) && !isTokenExpired(token);}/*** 判断token是否已经失效*/private boolean isTokenExpired(String token) {Date expiredDate = getExpiredDateFromToken(token);return expiredDate.before(new Date());}/*** 从token中获取过期时间*/private Date getExpiredDateFromToken(String token) {Claims claims = getClaimsFromToken(token);return claims.getExpiration();}/*** 根据用户信息生成token*/public String generateToken(UserDetails userDetails) {Map<String, Object> claims = new HashMap<>();claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());claims.put(CLAIM_KEY_CREATED, new Date());return generateToken(claims);}/*** 判断token是否可以被刷新*/public boolean canRefresh(String token) {return !isTokenExpired(token);}/*** 刷新token*/public String refreshToken(String token) {Claims claims = getClaimsFromToken(token);claims.put(CLAIM_KEY_CREATED, new Date());return generateToken(claims);}
}

springSecurity jwt 认证与鉴权及异常相关推荐

  1. 「springcloud 2021 系列」Spring Cloud Gateway + OAuth2 + JWT 实现统一认证与鉴权

    通过认证服务进行统一认证,然后通过网关来统一校验认证和鉴权. 将采用 Nacos 作为注册中心,Gateway 作为网关,使用 nimbus-jose-jwt JWT 库操作 JWT 令牌 理论介绍 ...

  2. SpringBoot中使用Shiro和JWT做认证和鉴权

    最近新做的项目中使用了shiro和jwt来做简单的权限验证,在和springboot集成的过程中碰到了不少坑.做完之后对shiro的体系架构了解的也差不多了,现在把中间需要注意的点放出来,给大家做个参 ...

  3. Spring Security源码解析(一)——认证和鉴权

    目录 认证过程 AuthenticationManager Authentication AbstractAuthenticationToken UsernamePasswordAuthenticat ...

  4. 微服务接入oauth2_微服务权限终极解决方案,Spring Cloud Gateway+Oauth2实现统一认证和鉴权!...

    最近发现了一个很好的微服务权限解决方案,可以通过认证服务进行统一认证,然后通过网关来统一校验认证和鉴权.此方案为目前最新方案,仅支持Spring Boot 2.2.0.Spring Cloud Hox ...

  5. 微服务架构下的安全认证与鉴权

    微服务架构下的安全认证与鉴权 转载自:https://mp.weixin.qq.com/s/qBJ_257IWn3cctqmKfJ7FQ 作者:王海龙,来自:EAWorld 现任普元云计算架构师,毕业 ...

  6. JWT的API鉴权,基于拦截器的token与鉴权

    基于JWT的API鉴权 基于拦截器的token与鉴权 如果我们每个方法都去写一段代码,冗余度太高,不利于维护,那如何做使我们的代码看起来更清爽呢?我们可以  将这段代码放入拦截器去实现 Spring中 ...

  7. Golang jwt跨域鉴权

    Golang jwt跨域鉴权 JWT全称JSON Web Token是一种跨域认证解决方案,属于一个开放的标准,它规定了一种Token实现方式,目前多用于前后端分离项目和OAuth2.0 安装jwt ...

  8. Spring全家桶-Spring Security之自定义数据库表认证和鉴权

    Spring全家桶-Spring Security之自定义数据库表认证和鉴权 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供 ...

  9. Kong社区版集成Keycloak实现微服务认证与鉴权

    文章目录 Kong社区版集成Keycloak实现微服务认证与鉴权 前言 认证和鉴权流程 在Keycloak上配置 创建Realm 创建Client 创建Role 创建User 服务 环境准备 受保护的 ...

  10. Go语言学习笔记——jwt跨域鉴权

    文章目录 Golang jwt跨域鉴权 jwt介绍 JWT 到底是什么? JWT 和 OAuth 选择签名方法 签名方法和密钥类型 安装jwt 简单使用 生成JWT 解析jwt 测试:生成token并 ...

最新文章

  1. linux fcntl 函数 文件描述符选项控制
  2. Keil编译报错:Cannot open include file: 'stdbool.h': No such file or directory问题解决
  3. 计算机主板时钟,主板时钟电路工作原理
  4. python小程序:备份文件
  5. 万物皆可文本时代来临?如何搞定NLP最强模型GPT
  6. 计算机设计文献参考,优秀计算机设计论文参考文献 计算机设计论文参考文献数量是多少...
  7. JavaScript Array 对象(length)方法 (contact、push,pop,join,map、reverse、slice、sort)
  8. ip地址配置 mongodb_MongoDB 3.6版本中bind_ip设置详解
  9. 管理新语:搞绩效考评需谨慎,切勿随意
  10. 路孚特:金融行业数据复杂 成本高 难获取 看路孚特如何打破困局
  11. 51nod 1384
  12. android虚拟机启动失败
  13. DNS解析异常问题排查
  14. 智能性与实用性兼具,华为开启智能眼镜全民时代
  15. html前端显示tiff
  16. php怎么设置段落之间的距离,css如何设置段落间距?margin 属性设置段落间距(代码实例)...
  17. 移动拨号上网开热点(不是360开热点,而是使用电脑自带的热点功能)详解
  18. Numpy数组的索引与切片:取数组的特定行列
  19. 【人工智能】拥抱人工智能,从机器学习开始
  20. Web 页面如何添加水印?

热门文章

  1. 【K-DB干货】浅谈KRAC内存融合技术
  2. MongoDB(一)——简介
  3. SAP WM Stock Removal Strategy - StringentFIFO 在仓库号级别下的先进先出
  4. Spring context:annotation-config/ 说明
  5. 暴力/set Codeforces Round #291 (Div. 2) C. Watto and Mechanism
  6. wordpress获取home_wordpress各种获取路径和URl地址的函数总结
  7. linux下类似Bus Hound的工具
  8. /proc/meminfo之谜
  9. FreeSwitch +fusionpbx安装和基本使用
  10. Java的GUI学习八(键盘码查询器)