ylbtech-Java-Class-@I:java.annotation.Resource.java |
1.返回顶部 |
2.返回顶部 |
1.1、
import javax.annotation.Resource;
1.2、
package com.ylbtech.api.platform.controller.auth; import com.ylbtech.api.platform.core.jwt.JwtConfigurationProperties; import com.ylbtech.api.platform.core.jwt.JwtUtil; import com.ylbtech.api.platform.core.response.Result; import com.ylbtech.api.platform.core.response.ResultGenerator; import com.ylbtech.edu.organization.domain.Organization; import com.ylbtech.edu.organization.service.IOrganizationService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Slf4j @Api(value = "账户接口") @Validated @RestController @RequestMapping("/user") public class AuthController { @Resource private JwtUtil jwtUtil; @Autowired private IOrganizationService organizationService; /** * showdoc * @catalog 用户 * @title 账户注销 * @description 账户注销接口 * @method Delete * @url https://ip:port/user/token/logout * @param adminID 必选 string 账号 * @return {"code":200} * @remark */ @ApiOperation(value = "账户注销") @PostMapping("/token/logout") public Result logout(@ApiParam(required = true) @RequestBody OrganizationAdmin organizationAdmin) { if (organizationAdmin.getAdminID() == null || organizationAdmin.getAdminID().equalsIgnoreCase("")) { return ResultGenerator.genFailedResult("adminID is null"); } this.jwtUtil.invalidRedisToken(organizationAdmin.getAdminID()); return ResultGenerator.genOkResult(); } }
1.3、
3.返回顶部 |
4.返回顶部 |
1、
/* * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package javax.annotation; import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; /** * The Resource annotation marks a resource that is needed * by the application. This annotation may be applied to an * application component class, or to fields or methods of the * component class. When the annotation is applied to a * field or method, the container will inject an instance * of the requested resource into the application component * when the component is initialized. If the annotation is * applied to the component class, the annotation declares a * resource that the application will look up at runtime. <p> * * Even though this annotation is not marked Inherited, deployment * tools are required to examine all superclasses of any component * class to discover all uses of this annotation in all superclasses. * All such annotation instances specify resources that are needed * by the application component. Note that this annotation may * appear on private fields and methods of superclasses; the container * is required to perform injection in these cases as well. * * @since Common Annotations 1.0 */ @Target({TYPE, FIELD, METHOD}) @Retention(RUNTIME) public @interface Resource { /** * The JNDI name of the resource. For field annotations, * the default is the field name. For method annotations, * the default is the JavaBeans property name corresponding * to the method. For class annotations, there is no default * and this must be specified. */ String name() default ""; /** * The name of the resource that the reference points to. It can * link to any compatible resource using the global JNDI names. * * @since Common Annotations 1.1 */ String lookup() default ""; /** * The Java type of the resource. For field annotations, * the default is the type of the field. For method annotations, * the default is the type of the JavaBeans property. * For class annotations, there is no default and this must be * specified. */ Class<?> type() default java.lang.Object.class; /** * The two possible authentication types for a resource. */ enum AuthenticationType { CONTAINER, APPLICATION } /** * The authentication type to use for this resource. * This may be specified for resources representing a * connection factory of any supported type, and must * not be specified for resources of other types. */ AuthenticationType authenticationType() default AuthenticationType.CONTAINER; /** * Indicates whether this resource can be shared between * this component and other components. * This may be specified for resources representing a * connection factory of any supported type, and must * not be specified for resources of other types. */ boolean shareable() default true; /** * A product specific name that this resource should be mapped to. * The name of this resource, as defined by the <code>name</code> * element or defaulted, is a name that is local to the application * component using the resource. (It's a name in the JNDI * <code>java:comp/env</code> namespace.) Many application servers * provide a way to map these local names to names of resources * known to the application server. This mapped name is often a * <i>global</i> JNDI name, but may be a name of any form. <p> * * Application servers are not required to support any particular * form or type of mapped name, nor the ability to use mapped names. * The mapped name is product-dependent and often installation-dependent. * No use of a mapped name is portable. */ String mappedName() default ""; /** * Description of this resource. The description is expected * to be in the default language of the system on which the * application is deployed. The description can be presented * to the Deployer to help in choosing the correct resource. */ String description() default ""; }
2、
5.返回顶部 |
1、JwtUtil.java
package com.ylbtech.api.platform.core.jwt; import com.ylbtech.api.platform.core.rsa.RsaUtils; import com.ylbtech.api.platform.util.RedisUtils; import io.jsonwebtoken.*; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.stereotype.Component; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.time.Duration; import java.util.*; import java.util.function.Supplier; import java.util.stream.Collectors; /** * Json web token 工具 验证、生成 token */ @Slf4j @Component public class JwtUtil { @Resource private RedisUtils redisUtils; @Resource private RsaUtils rsaUtils; @Resource private JwtConfigurationProperties jwtProperties; private Claims getClaims(final String token) { final Jws<Claims> jws = this.parseToken(token); return jws == null ? null : jws.getBody(); } /** * 根据 token 得到账户名 */ public String getName(final String token) { final Claims claims = this.getClaims(token); return claims == null ? null : claims.getSubject(); } /** * 签发 token * * @param name 账户名 * @param grantedAuthorities 账户权限信息[ADMIN, TEST, ...] */ public String sign( final String name, final Collection<? extends GrantedAuthority> grantedAuthorities) { // 函数式创建 token,避免重复书写 final Supplier<String> createToken = () -> this.createToken(name, grantedAuthorities); // 看看缓存有没有账户token final String token = (String) this.redisUtils.getValue(name); // 没有登录过 if (StringUtils.isBlank(token)) { return createToken.get(); } final boolean isValidate = (boolean) this.redisUtils.getValue(token); // 有 token,仍有效,将 token 置为无效,并重新签发(防止 token 被利用) if (isValidate) { this.invalidRedisToken(name); } // 重新签发 return createToken.get(); } /** * 清除账户在 Redis 中缓存的 token * * @param name 账户名 */ public void invalidRedisToken(final String name) { // 将 token 设置为无效 final String token = (String) this.redisUtils.getValue(name); Optional.ofNullable(token).ifPresent(_token -> this.redisUtils.setValue(_token, false)); } /** * 从请求头或请求参数中获取 token */ public String getTokenFromRequest(final HttpServletRequest httpRequest) { final String header = this.jwtProperties.getHeader(); final String token = httpRequest.getHeader(header); return StringUtils.isNotBlank(token) ? token : httpRequest.getParameter(header); } /** * 返回账户认证 */ public UsernamePasswordAuthenticationToken getAuthentication( final String name, final String token) { // 解析 token 的 payload final Claims claims = this.getClaims(token); // 因为 JwtAuthenticationFilter 拦截器已经检查过 token 有效,所以可以忽略 get 空指针提示 assert claims != null; final String claimKeyAuth = this.jwtProperties.getClaimKeyAuth(); // 账户角色列表 final List<String> authList = Arrays.asList(claims.get(claimKeyAuth).toString().split(",")); // 将元素转换为 GrantedAuthority 接口集合 final Collection<? extends GrantedAuthority> authorities = authList.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); final User user = new User(name, "", authorities); return new UsernamePasswordAuthenticationToken(user, null, authorities); } /** * 验证 token 是否正确 */ public boolean validateToken(final String token) { boolean isValidate = true; final Object redisTokenValidate = this.redisUtils.getValue(token); // 可能 redis 部署出现了问题 // 或者清空了缓存导致 token 键不存在 if (redisTokenValidate != null) { isValidate = (boolean) redisTokenValidate; } // 能正确解析 token,并且 redis 中缓存的 token 也是有效的 return this.parseToken(token) != null && isValidate; } /** * 生成 token */ private String createToken( final String name, final Collection<? extends GrantedAuthority> grantedAuthorities) { // 获取账户的角色字符串,如 USER,ADMIN final String authorities = grantedAuthorities .stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.joining(",")); log.debug("==> user<{}> authorities: {}", name, authorities); // 过期时间 final Duration expireTime = this.jwtProperties.getExpireTime(); // 当前时间 + 有效时长 final Date expireDate = new Date(System.currentTimeMillis() + expireTime.toMillis()); // 创建 token,比如 "Bearer abc1234" final String token = this.jwtProperties.getTokenType() + " " + Jwts.builder() // 设置账户名 .setSubject(name) // 添加权限属性 .claim(this.jwtProperties.getClaimKeyAuth(), authorities) // 设置失效时间 .setExpiration(expireDate) // 私钥加密生成签名 .signWith(SignatureAlgorithm.RS256, this.rsaUtils.loadPrivateKey()) // 使用LZ77算法与哈夫曼编码结合的压缩算法进行压缩 .compressWith(CompressionCodecs.DEFLATE) .compact(); // 保存账户 token // 因为账户注销后 JWT 本身只要没过期就仍然有效,所以只能通过 redis 缓存来校验有无效 // 校验时只要 redis 中的 token 无效即可(JWT 本身可以校验有无过期,而 redis 过期即被删除了) // true 有效 this.redisUtils.setValue(token, true, expireTime); // redis 过期时间和 JWT 的一致 this.redisUtils.setValue(name, token, expireTime); log.debug("==> Redis set uid<{}> token: {}", name, token); return token; } /** * 解析 token */ private Jws<Claims> parseToken(final String token) { try { return Jwts.parser() // 公钥解密 .setSigningKey(this.rsaUtils.loadPublicKey()) .parseClaimsJws(token.replace(this.jwtProperties.getTokenType(), "")); } catch (final SignatureException e) { // 签名异常 log.debug("Invalid JWT signature"); } catch (final MalformedJwtException e) { // 格式错误 log.debug("Invalid JWT token"); } catch (final ExpiredJwtException e) { // 过期 log.debug("Expired JWT token"); } catch (final UnsupportedJwtException e) { // 不支持该JWT log.debug("Unsupported JWT token"); } catch (final IllegalArgumentException e) { // 参数错误异常 log.debug("JWT token compact of handler are invalid"); } return null; } }
2、
6.返回顶部 |
作者:ylbtech 出处:http://ylbtech.cnblogs.com/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 |