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;
        }
    
    }
    
  • 相关阅读:
    jquery easy ui 学习 (8)basic treegrid
    jquery easy ui 学习 (7) TreeGrid Actions
    jquery easy ui 学习 (6) basic validatebox
    jquery easy ui 学习 (5) windowlayout
    jquery easy ui 学习 (4) window 打开之后 限制操纵后面元素属性
    提示“应用程序无法启动,因为应用程序的并行配置不正确”不能加载 System.Data.SQLite.dll
    visual studio 添加虚线的快捷键
    VS2010打开项目时,出现“已经在解决方案中打开了具有该名称的项目”问题的解决方案
    visual studio 编译时 出现 Files 的值 乱码
    微信 连接被意外关闭
  • 原文地址:https://www.cnblogs.com/typ1805/p/14077843.html
Copyright © 2011-2022 走看看