Java-Class-@I:java.annotation.Resource

ylbtech-Java-Class-@I:java.annotation.Resource

 

1.返回頂部
 
2.返回頂部
1.一、
import javax.annotation.Resource;
1.二、
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.返回頂部
 
4.返回頂部
一、
/*
 * 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 "";
}
二、
5.返回頂部
一、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;
    }
}
JwtUtil.java
二、
 
6.返回頂部
 
warn 做者:ylbtech
出處:http://ylbtech.cnblogs.com/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。
相關文章
相關標籤/搜索