zoukankan      html  css  js  c++  java
  • SpringCloud Alibaba Security安全认证

    一、 Security配置(auth认证中心)

    代码地址

    https://github.com/typ1805/blog-cloud

    Spring Security是一套安全框架,可以基于RBAC(基于角色的权限控制)对用户的访问权限进行控制。

    添加依赖

     <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-security</artifactId>
     </dependency>
    <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
         <groupId>com.nimbusds</groupId>
         <artifactId>nimbus-jose-jwt</artifactId>
    </dependency>
    

    1、WebSecurityConfig

    登录认证授权等主要采用Spring security + JWT,首先配置WebSecurityConfig,Redis配置主要是为了满足需:

    • 当用户的角色或者权限变动后
    • 已获授权的用户需要重新登录授权
    package com.blog.config;
    
    import com.blog.jwt.JWTAuthenticationEntryPoint;
    import com.blog.jwt.JWTAuthenticationFilter;
    import com.blog.jwt.JWTAuthorizationFilter;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.http.HttpMethod;
    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.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.crypto.password.PasswordEncoder;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    
    /**
     * @path:com.blog.config.WebSecurityConfig.java
     * @className:WebSecurityConfig.java
     * @description:Security配置
     * @author:tanyp
     * @dateTime:2020/11/9 16:31 
     * @editNote:
     */
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        @Qualifier("userDetailsServiceImpl")
        private UserDetailsService userDetailsService;
    
        @Autowired
        private StringRedisTemplate redisTemplate;
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/login").permitAll()
                    .anyRequest().authenticated()
                    .and()
                    .addFilterBefore(new JWTAuthenticationFilter(authenticationManager(), redisTemplate), UsernamePasswordAuthenticationFilter.class)
                    .addFilterBefore(new JWTAuthorizationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .exceptionHandling().authenticationEntryPoint(new JWTAuthenticationEntryPoint());
        }
    
    }
    
    

    2、UserDetailsServiceImpl

    通过用户名去查找用户及拥有的角色和权限

    package com.blog.service;
    
    import com.blog.domain.AuthUser;
    import com.blog.common.core.constants.Constants;
    import com.blog.common.core.constants.JWTConstants;
    import com.blog.common.core.result.Wrapper;
    import com.blog.provider.UserProvider;
    import com.blog.vo.MenuVo;
    import com.blog.vo.RoleVo;
    import com.blog.vo.UserVo;
    import org.apache.dubbo.config.annotation.DubboReference;
    import org.springframework.beans.BeanUtils;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    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.Service;
    import org.springframework.util.StringUtils;
    
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    /**
     * @path:com.blog.service.impl.UserDetailsServiceImpl.java
     * @className:UserDetailsServiceImpl.java
     * @description:自定义用户认证和授权
     * @author:tanyp
     * @dateTime:2020/11/9 15:44 
     * @editNote:
     */
    @Service
    public class UserDetailsServiceImpl implements UserDetailsService {
    
        @DubboReference
        private UserProvider userProvider;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            Wrapper<UserVo> userInfo = userProvider.findByUsername(username);
            if (userInfo.getCode() != Constants.SUCCESS) {
                throw new UsernameNotFoundException("用户:" + username + ",不存在!");
            }
    
            Set<SimpleGrantedAuthority> grantedAuthorities = new HashSet<>();
            UserVo userVo = new UserVo();
            BeanUtils.copyProperties(userInfo.getResult(), userVo);
    
            Wrapper<List<RoleVo>> roleInfo = userProvider.getRoleByUserId(String.valueOf(userVo.getId()));
            if (roleInfo.getCode() == Constants.SUCCESS) {
                List<RoleVo> roleVoList = roleInfo.getResult();
                for (RoleVo role : roleVoList) {
                    // 角色必须是ROLE_开头,可以在数据库中设置
                    SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(JWTConstants.ROLE_PREFIX + role.getValue());
                    grantedAuthorities.add(grantedAuthority);
    
                    // 获取权限
                    Wrapper<List<MenuVo>> menuInfo = userProvider.getRolePermission(String.valueOf(role.getId()));
                    if (menuInfo.getCode() == Constants.SUCCESS) {
                        List<MenuVo> permissionList = menuInfo.getResult();
                        for (MenuVo menu : permissionList) {
                            if (!StringUtils.isEmpty(menu.getUrl())) {
                                SimpleGrantedAuthority authority = new SimpleGrantedAuthority(menu.getUrl());
                                grantedAuthorities.add(authority);
                            }
                        }
                    }
                }
            }
    
            AuthUser user = new AuthUser(userVo.getUsername(), userVo.getPassword(), grantedAuthorities);
            user.setId(userVo.getId());
            return user;
        }
    
    }
    
    

    3、JWTAuthorizationFilter

    主要对用户进行认证工作,当登录时,获取用户名和密码,通过authenticationManager.authenticate,最终会调用UserDetailsServiceImpl来获取用户信息(在DaoAuthenticationProvider的retrieveUser中),
    然后在DaoAuthenticationProvider的additionalAuthenticationChecks中校验密码。

    package com.blog.jwt;
    
    import com.alibaba.fastjson.JSONObject;
    import com.blog.domain.AuthUser;
    import com.blog.common.core.constants.JWTConstants;
    import com.blog.common.core.result.WrapMapper;
    import com.nimbusds.jose.JOSEException;
    import com.nimbusds.jose.JWSVerifier;
    import com.nimbusds.jose.crypto.MACVerifier;
    import com.nimbusds.jwt.SignedJWT;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.http.MediaType;
    import org.springframework.security.authentication.AccountExpiredException;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
    import org.springframework.util.StringUtils;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.text.ParseException;
    import java.util.Date;
    
    /**
     * @path:com.blog.jwt.JWTAuthorizationFilter.java
     * @className:JWTAuthorizationFilter.java
     * @description:授权
     * @author:tanyp
     * @dateTime:2020/11/19 13:19 
     * @editNote:
     */
    @Slf4j
    public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
    
        public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {
            super(authenticationManager);
        }
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
            String token = request.getHeader(JWTConstants.TOKEN_HEADER);
            if (StringUtils.isEmpty(token) || !token.startsWith(JWTConstants.TOKEN_PREFIX)) {
                chain.doFilter(request, response);
                return;
            }
    
            try {
                Authentication authentication = getAuthentication(token);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                onSuccessfulAuthentication(request, response, authentication);
                chain.doFilter(request, response);
            } catch (Exception e) {
                e.printStackTrace();
                onUnsuccessfulAuthentication(request, response, new AccountExpiredException(e.getMessage()));
            }
        }
    
        @Override
        protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException {
            log.info("=============Token 验证成功=================");
        }
    
        @Override
        protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException {
            log.error("================token校验失败=======================");
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding("UTF-8");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write(JSONObject.toJSONString(WrapMapper.error(HttpServletResponse.SC_UNAUTHORIZED, failed.getMessage())));
        }
    
        /**
         * @methodName:getAuthentication
         * @description:这里从token中获取用户信息并新建一个token
         * @author:tanyp
         * @dateTime:2020/11/19 13:37
         * @Params: [tokenHeader]
         * @Return: org.springframework.security.authentication.UsernamePasswordAuthenticationToken
         * @editNote:
         */
        private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) throws ParseException, JOSEException {
            String token = tokenHeader.replace(JWTConstants.TOKEN_PREFIX, "");
            SignedJWT jwt = SignedJWT.parse(token);
            JWSVerifier verifier = new MACVerifier(JWTConstants.SECRET);
    
            // 校验是否有效
            if (!jwt.verify(verifier)) {
                throw new AccountExpiredException(JWTConstants.TOKEN_INVALID);
            }
    
            // 校验超时
            Date expirationTime = jwt.getJWTClaimsSet().getExpirationTime();
            if (new Date().after(expirationTime)) {
                throw new AccountExpiredException(JWTConstants.TOKEN_EXPIRE);
            }
    
            // 获取载体中的数据
            Object account = jwt.getJWTClaimsSet().getClaim("payload");
            if (account != null) {
                AuthUser user = JSONObject.parseObject(account.toString(), AuthUser.class);
                return new UsernamePasswordAuthenticationToken(user.getUsername(), null, user.getAuthorities());
            }
            return null;
        }
    
    }
    
    

    4.JWTAuthenticationFilter

    在JWTAuthenticationFilter中,把权限信息等写入到了redis中。

    只要后台权限变动的时候,根据key的规则清除redis数据即可, 然后在gateway中获取不到相应的权限, 那么会要求用户重新登录。

    package com.blog.jwt;
    
    import com.alibaba.fastjson.JSONObject;
    import com.blog.common.core.constants.JWTConstants;
    import com.blog.common.core.constants.RedisConstants;
    import com.blog.common.core.enums.AuthEnum;
    import com.blog.common.core.result.WrapMapper;
    import com.blog.common.core.result.Wrapper;
    import com.blog.common.core.utils.JWTUtiles;
    import com.blog.common.core.utils.Md5Utils;
    import com.blog.domain.AuthUser;
    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.http.MediaType;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.BadCredentialsException;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @path:com.blog.jwt.JWTAuthenticationFilter.java
     * @className:JWTAuthenticationFilter.java
     * @description:权限变动重新授权
     * @author:tanyp
     * @dateTime:2020/11/19 13:15 
     * @editNote:
     */
    @Slf4j
    public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    
        private AuthenticationManager authenticationManager;
    
        private StringRedisTemplate redisTemplate;
    
        public JWTAuthenticationFilter(AuthenticationManager authenticationManager, StringRedisTemplate redisTemplate) {
            this.authenticationManager = authenticationManager;
            this.redisTemplate = redisTemplate;
        }
    
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        }
    
        @SneakyThrows
        @Override
        protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
            AuthUser user = (AuthUser) authResult.getPrincipal();
    
            // 生成token
            String payload = JSONObject.toJSONString(user);
            String jwtToken = JWTUtiles.createToken(payload);
    
            // 生成Key, 把权限放入到redis中
            String keyPrefix = RedisConstants.TOKEN_KEY_PREFIX + user.getId() + ":";
            String keySuffix = Md5Utils.getMD5(jwtToken.getBytes());
            String key = keyPrefix + keySuffix;
            String authKey = key + RedisConstants.AUTH_KEY;
    
            redisTemplate.opsForValue().set(key, jwtToken, JWTConstants.EXPIRE_TIME, TimeUnit.MILLISECONDS);
            redisTemplate.opsForValue().set(authKey, JSONObject.toJSONString(user.getAuthorities()), JWTConstants.EXPIRE_TIME, TimeUnit.SECONDS);
    
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding("UTF-8");
            response.getWriter().write(JSONObject.toJSONString(WrapMapper.success().result(jwtToken)));
        }
    
        @Override
        protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
            log.error("========登录认证失败:", failed);
            Wrapper result = null;
            int status = AuthEnum.AUTH_NO_TOKEN.getKey();
            if (failed instanceof UsernameNotFoundException) {
                result = WrapMapper.error(AuthEnum.AUTH_NONEXISTENT.getKey(), AuthEnum.AUTH_NONEXISTENT.getValue());
            } else if (failed instanceof BadCredentialsException) {
                result = WrapMapper.error(AuthEnum.AUTH_NO_TOKEN.getKey(), AuthEnum.AUTH_NO_TOKEN.getValue());
            }
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding("UTF-8");
            response.setStatus(status);
            response.getWriter().write(JSONObject.toJSONString(result));
        }
    
    }
    
    

    注: 主要是生成JWT的token, 并且把权限信息放入redis。

    登录直接调用Security框架的login方法即可

    格式:

    Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwicGF5bG9hZCI6IntcImFjY291bnROb25FeHBpcmVkXCI6dHJ1ZSxcImFjY291bnROb25Mb2NrZWRcIjp0cnVlLFwiYXV0aG9yaXRpZXNcIjpbe1wiYXV0aG9yaXR5XCI6XCJcL21zcy11cG1zXC9vcmRlclwvbGlzdFwifSx7XCJhdXRob3JpdHlcIjpcIlwvbXNzLXVwbXNcL29yZGVyXC9kZXRhaWxcIn0se1wiYXV0aG9yaXR5XCI6XCJST0xFX2FkbWluXCJ9XSxcImNyZWRlbnRpYWxzTm9uRXhwaXJlZFwiOnRydWUsXCJlbmFibGVkXCI6dHJ1ZSxcImlkXCI6NDgsXCJwYXNzd29yZFwiOlwiJDJhJDEwJHZtcC56V1duWDNMRnhTczZJMDBpMGV1cmxIUjd5bWNmVVE1SHRYdzcxdzlRSi4ySlVmOFVhXCIsXCJ1c2VybmFtZVwiOlwiYWRtaW5cIn0iLCJleHAiOjE2MDYxMzA4MDd9.Wb-2UkAcVrj4KbQteT6D9RbktXgkPLI-tB5ymMkqsjI
    

    二、网关校验(gateway模块)

    网关的主要作用是对JWT和具体的URL进行校验,校验不通过则返回错误信息,主要通过AuthGlobalFilter来实现。

    1、AuthGlobalFilter

    package com.blog.filter;
    
    import com.alibaba.fastjson.JSON;
    import com.blog.common.core.constants.JWTConstants;
    import com.blog.common.core.constants.RedisConstants;
    import com.blog.common.core.enums.AuthEnum;
    import com.blog.common.core.result.WrapMapper;
    import com.blog.common.core.utils.JWTUtiles;
    import com.blog.common.core.utils.Md5Utils;
    import com.blog.config.ExclusionUrlConfig;
    import com.blog.vo.Authority;
    import com.blog.vo.UserVo;
    import com.nimbusds.jwt.SignedJWT;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.Ordered;
    import org.springframework.core.io.buffer.DataBuffer;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.MediaType;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.util.AntPathMatcher;
    import org.springframework.util.StringUtils;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    import java.text.ParseException;
    import java.util.List;
    
    /**
     * @path:com.blog.filter.AuthGlobalFilter.java
     * @className:AuthGlobalFilter.java
     * @description:token过滤器
     * @author:tanyp
     * @dateTime:2020/11/10 18:06 
     * @editNote:
     */
    @Slf4j
    @Component
    public class AuthGlobalFilter implements GlobalFilter, Ordered {
    
        @Autowired
        private ExclusionUrlConfig exclusionUrlConfig;
    
        AntPathMatcher antPathMatcher = new AntPathMatcher();
    
        @Autowired
        private StringRedisTemplate redisTemplate;
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
            String headerToken = request.getHeaders().getFirst(JWTConstants.TOKEN_HEADER);
            log.info("headerToken:{}", headerToken);
    
            // 只要带上了token, 就需要判断Token是否有效
            if (!StringUtils.isEmpty(headerToken) && !JWTUtiles.verifierToken(headerToken)) {
                return getVoidMono(response, AuthEnum.AUTH_NO_TOKEN.getKey(), AuthEnum.AUTH_NO_TOKEN.getValue());
            }
            String path = request.getURI().getPath();
            log.info("request path:{}", path);
    
            // 判断是否是过滤的路径, 是的话就放行
            if (isExclusionUrl(path)) {
                return chain.filter(exchange);
            }
    
            // 判断请求的URL是否有权限
            boolean permission = hasPermission(headerToken, path);
            if (!permission) {
                return getVoidMono(response, AuthEnum.AUTH_NO_ACCESS.getKey(), AuthEnum.AUTH_NO_ACCESS.getValue());
            }
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    
        private Mono<Void> getVoidMono(ServerHttpResponse response, int i, String msg) {
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            response.setStatusCode(HttpStatus.OK);
            byte[] bits = JSON.toJSONString(WrapMapper.error(i, msg)).getBytes();
            DataBuffer buffer = response.bufferFactory().wrap(bits);
            return response.writeWith(Mono.just(buffer));
        }
    
        private boolean isExclusionUrl(String path) {
            List<String> exclusions = exclusionUrlConfig.getUrl();
            if (exclusions.size() == 0) {
                return false;
            }
            return exclusions.stream().anyMatch(action -> antPathMatcher.match(action, path));
        }
    
        /**
         * @methodName:hasPermission
         * @description:判断请求的URL是否有权限
         * @author:tanyp
         * @dateTime:2020/11/24 9:38
         * @Params: [headerToken, path]
         * @Return: boolean
         * @editNote:
         */
        private boolean hasPermission(String headerToken, String path) {
            try {
                if (StringUtils.isEmpty(headerToken)) {
                    return false;
                }
    
                SignedJWT jwt = JWTUtiles.getSignedJWT(headerToken);
                Object payload = jwt.getJWTClaimsSet().getClaim("payload");
                UserVo user = JSON.parseObject(payload.toString(), UserVo.class);
                // 生成Key, 把权限放入到redis中
                String keyPrefix = RedisConstants.TOKEN_KEY_PREFIX + user.getId() + ":";
                String token = headerToken.replace(JWTConstants.TOKEN_PREFIX, "");
                String keySuffix = Md5Utils.getMD5(token.getBytes());
                String key = keyPrefix + keySuffix;
                String authKey = key + RedisConstants.AUTH_KEY;
    
                String authStr = redisTemplate.opsForValue().get(authKey);
                if (StringUtils.isEmpty(authStr)) {
                    return false;
                }
    
                List<Authority> authorities = JSON.parseArray(authStr, Authority.class);
                return authorities.stream().anyMatch(authority -> antPathMatcher.match(authority.getAuthority(), path));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return false;
        }
    
    }
    

    2、白名单配置(ExclusionUrlConfig)

    package com.blog.config;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @path:com.blog.config.ExclusionUrlConfig.java
     * @className:ExclusionUrlConfig.java
     * @description:白名单配置
     * @author:tanyp
     * @dateTime:2020/11/19 14:01 
     * @editNote:
     */
    @Data
    @Component
    @ConfigurationProperties(prefix = "exclusion")
    public class ExclusionUrlConfig {
    
        private List<String> url;
    
    }
    
    

    配置信息

    # 配置白名单路径
    exclusion:
      url:
        - /auth/checkUser
        - /auth/login
    

    三、相关工具类

    1、JWT

    package com.blog.common.core.utils;
    
    import com.blog.common.core.constants.JWTConstants;
    import com.nimbusds.jose.JOSEException;
    import com.nimbusds.jose.JWSAlgorithm;
    import com.nimbusds.jose.JWSHeader;
    import com.nimbusds.jose.JWSVerifier;
    import com.nimbusds.jose.crypto.MACSigner;
    import com.nimbusds.jose.crypto.MACVerifier;
    import com.nimbusds.jwt.JWTClaimsSet;
    import com.nimbusds.jwt.SignedJWT;
    import lombok.extern.slf4j.Slf4j;
    
    import java.text.ParseException;
    import java.util.Date;
    
    /**
     * @path:com.blog.common.core.utils.JWTUtiles.java
     * @className:JWTUtiles.java
     * @description:JWT工具类
     * @author:tanyp
     * @dateTime:2020/11/24 9:32 
     * @editNote:
     */
    @Slf4j
    public class JWTUtiles {
    
        /**
         * @methodName:createToken
         * @description:创建token
         * @author:tanyp
         * @dateTime:2020/11/24 10:20
         * @Params: [user]
         * @Return: java.lang.String
         * @editNote:
         */
        public static String createToken(String payload) throws JOSEException {
            // 创建密钥
            MACSigner macSigner = new MACSigner(JWTConstants.SECRET);
    
            // payload
            JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                    .subject("subject")
                    .claim("payload", payload)
                    .expirationTime(new Date(System.currentTimeMillis() + JWTConstants.EXPIRE_TIME))
                    .build();
            JWSHeader jwsHeader = new JWSHeader(JWSAlgorithm.HS256);
    
            // 创建签名的JWT
            SignedJWT signedJWT = new SignedJWT(jwsHeader, claimsSet);
            signedJWT.sign(macSigner);
    
            // 生成token
            String jwtToken = signedJWT.serialize();
            return jwtToken;
        }
    
        /**
         * @methodName:verifierToken
         * @description:验证token
         * @author:tanyp
         * @dateTime:2020/11/24 9:35
         * @Params: [headerToken]
         * @Return: boolean
         * @editNote:
         */
        public static boolean verifierToken(String headerToken) {
            try {
                SignedJWT jwt = getSignedJWT(headerToken);
                JWSVerifier verifier = new MACVerifier(JWTConstants.SECRET);
                // 校验是否有效
                if (!jwt.verify(verifier)) {
                    log.error("token不合法,检测不过关");
                    return false;
                }
    
                // 校验超时
                Date expirationTime = jwt.getJWTClaimsSet().getExpirationTime();
                if (new Date().after(expirationTime)) {
                    log.error("token已经过期");
                    return false;
                }
                // 获取载体中的数据
                return true;
            } catch (ParseException | JOSEException e) {
                log.error("token校验出错", e);
            }
            return false;
        }
    
        public static SignedJWT getSignedJWT(String headerToken) throws ParseException {
            String token = headerToken.replace(JWTConstants.TOKEN_PREFIX, "");
            log.info("token is {}", token);
            return SignedJWT.parse(token);
        }
    
    }
    
    

    2、MD5加密

    package com.blog.common.core.utils;
    
    import java.io.UnsupportedEncodingException;
    
    /**
     * @path:com.blog.common.core.utils.Md5Utils.java
     * @className:Md5Utils.java
     * @description:MD5加密
     * @author:tanyp
     * @dateTime:2020/11/9 15:31
     * @editNote:
     */
    public class Md5Utils {
    
        private static final int HEX_VALUE_COUNT = 16;
    
        public static String getMD5(byte[] bytes) {
            char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
            char[] str = new char[16 * 2];
            try {
                java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
                md.update(bytes);
                byte[] tmp = md.digest();
                int k = 0;
                for (int i = 0; i < HEX_VALUE_COUNT; i++) {
                    byte byte0 = tmp[i];
                    str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                    str[k++] = hexDigits[byte0 & 0xf];
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return new String(str);
        }
    
        public static String getMD5(String value, String encode) {
            String result = "";
            try {
                result = getMD5(value.getBytes(encode));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return result;
        }
    
    }
    
  • 相关阅读:
    2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 C: Coconut
    2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 A: Banana
    第2周项目1c++语言中函数参数传递的三种方式
    第2周项目2程序的多文件组织
    【BZOJ 3224】普通平衡树
    【POJ 1741】Tree
    浅谈树分治
    【luogu 2709 / BZOJ 3781】小B的询问
    【luogu 1972 / BZOJ 1878】HH的项链
    【BZOJ 3339 / BZOJ 3585 / luogu 4137】Rmq Problem / mex
  • 原文地址:https://www.cnblogs.com/typ1805/p/14077843.html
Copyright © 2011-2022 走看看