SpringSecurity(二)、权限项目框架搭建

Springboot + SpringSecurity权限项目框架搭建


目录

一、项目介绍

二、项目搭建(父子工程)

        1、添加 pom 依赖

        2、修改 yml 配置

        3、编写JwtTokenUtil工具类

        4、公共返回对象

        5、用户实体类修改实现 UserDetails(该接口是默认权限框架)

        6、登陆成功后获取token 

        7、获取当前登录用户信息

        8、配置security登录授权过滤器 及 Jwt登录授权过滤器 及 添加自定义未登录 及未授权结果返回

        9、配置接口文档swagger

        10、登录验证码配置​​​​​​​


一、项目介绍

该项目是管理系统 系统的搭建主要采用了主流的 Springboot + SpringSecurity + Oauths2.0 + JWT + MybatisPlus + Mysql + Redis + Rabbitmq + Maven + FastDfs + Nginx 等技术,这里我们主要展示的是权限框架的搭建

二、项目搭建(父子工程)

        1、添加 pom 依赖

<!-- web -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- lombok  -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
</dependency>

<!-- mysql -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.48</version>
  <scope>runtime</scope>
</dependency>

<!-- mybatis-plus -->
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.0.5</version>
</dependency>

<!-- swagger2 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>

<!-- Swagger第三方ui依赖  -->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>swagger-bootstrap-ui</artifactId>
    <version>1.9.6</version>
</dependency>

<!--security依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- jwt -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.0</version>
</dependency>

        2、修改 yml 配置

server:
  port: 8081

spring:
  #数据源配置
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/***?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: ****
    password: ******
    hikari:
      #连接池名
      pool-name: DateHikariCP
      #最小空闲连接数
      minimum-idle: 5
      #空闲连接存货最大时间
      idle-timeout: 180000
      #最大连接数
      maximum-pool-size: 10
      #从连接池返回的连接的自动提交
      auto-commit: true
      #连接最大存活时间,0表示永久存活
      max-lifetime: 1800000
      #连接超时时间
      connection-timeout: 30000
      #测试连接是否可用的查询语句
      connection-test-query: SELECT 1

# Mybatis-plus配置
mybatis-plus:
  #配置Mapper映射文件
  mapper-locations: classpath*:/mapper/*Mapper.xml
  #配置Mybatis数据返回类型别名(默认别名是类名)
  type-aliases-package: com.hierway.pojo
  configuration:
    #自动驼峰命名
    map-underscore-to-camel-case: false

## Mybatis SQL 打印(方法接口所在的包,不是Mapper.xml所在的包)
logging:
  level:
    com.hierway.mapper: debug

jwt:
  # JWT存储的请求头
  tokenHeader: Authorization
  # JWT加密使用的密钥
  secret: yeb-secret
  # JWT的超期限时间(60*60*24)
  expiration: 604800
  # JWT 负载中拿到开头
  tokenHead: Bearer

3、编写JwtTokenUtil工具类

/**
 * JwtToken配置类
 */
@Component
public class JwtTokenUtil {

    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;

    /**
     * 根据用户信息生成Token
     * @param userDetails
     * @return
     */
    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);
    }

    /**
     * 根据荷载生成JWT Token
     * @param claims
     * @return
     */
    private String generateToken(Map<String,Object> claims){
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS256,secret)
                .compact();
    }

    /**
     * 验证Token是否有效
     * @param token
     * @param userDetails
     * @return
     */
    public boolean validateToken(String token,UserDetails userDetails){
        String username = getUsernameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    /**
     * 判断token是否可以被刷新
     * @param token
     * @return
     */
    public boolean canRefresh(String token){
        return !isTokenExpired(token);
    }

    /**
     * 刷新token
     * @param token
     * @return
     */
    public String refreshToken(String token){
        Claims claims = getClaimsFromToken(token);
        claims.put(CLAIM_KEY_CREATED,new Date());
        return generateToken(claims);
    }

    /**
     * 判断token是否失效
     * @param token
     * @return
     */
    private boolean isTokenExpired(String token) {
        Date expireDate = getExpiredFromToken(token);
        return expireDate.before(new Date());
    }

    /**
     * 从token中获取过期时间
     * @param token
     * @return
     */
    private Date getExpiredFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 从token中获取登陆用户名
     * @param token
     * @return
     */
    public String getUsernameFromToken(String token){
        String username;
        try{
            Claims claims = getClaimsFromToken(token);
            username = (String) claims.get(CLAIM_KEY_USERNAME);
            //username = claims.getSubject();
        } catch (Exception e){
            username = null;
        }

        return username;
    }

    /**
     * 从token中获取荷载
     * @param token
     * @return
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return claims;
    }


    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration*1000);
    }
}

        4、公共返回对象

/**
 * @author guoce
 * @date 2022/11/30 11:24
 * note : 公共返回对象
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RespBean {

    private Integer code;
    private String message;
    private Object obj;

    /**
     * 成功返回结果
     * @param message message
     * @return RespBean
     */
    public static RespBean success(String message){
        return new RespBean(200,message,null);
    }

    /**
     * 成功返回结果
     * @param message message
     * @param obj obj
     * @return RespBean
     */
    public static RespBean success(String message,Object obj){
        return new RespBean(200,message,obj);
    }

    /**
     * 失败返回结果
     * @param message message
     * @return RespBean
     */
    public static RespBean error(String message){
        return new RespBean(418,message,null);
    }

    /**
     * 失败返回结果
     * @param message message
     * @param obj obj
     * @return RespBean
     */
    public static RespBean error(String message,Object obj){
        return new RespBean(418,message,obj);
    }
}

        5、用户实体类修改实现 UserDetails(该接口是默认权限框架)

@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_admin")
@ApiModel(value="Admin对象", description="管理员表")
public class Admin implements Serializable, UserDetails {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "id")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty(value = "姓名")
    private String name;

    @ApiModelProperty(value = "手机号码")
    private String phone;

    @ApiModelProperty(value = "住宅电话")
    private String telephone;

    @ApiModelProperty(value = "联系地址")
    private String address;

    @ApiModelProperty(value = "用户名")
    private String username;

    @ApiModelProperty(value = "密码")
    private String password;

    @ApiModelProperty(value = "用户头像")
    private String userFace;

    @ApiModelProperty(value = "备注")
    private String remark;

    @ApiModelProperty(value = "是否启用1 0")
    private Boolean enabled;

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUserFace() {
        return userFace;
    }

    public void setUserFace(String userFace) {
        this.userFace = userFace;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

//    public Boolean getEnabled() {
//        return enabled;
//    }

    public void setEnabled(Boolean enabled) {
        this.enabled = enabled;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return enabled;
    }
}

        6、登陆成功后获取token 

                a、创建登录实体类

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value = "AdminLogin对象",description = "")
public class AdminLoginParam {

    @ApiModelProperty(value = "用户名",required = true)
    private String username;
    @ApiModelProperty(value = "密码",required = true)
    private String password;
    @ApiModelProperty(value = "验证码",required = true)
    private String code;

}

                b、创建当前登录用户信息接口

1.controller层
@Api(tags = "LoginController")
@RestController
public class LoginController {

    @Autowired
    private IAdminService iAdminService;

    @ApiOperation(value = "登陆之后返回token")
    @PostMapping("/login")
    public RespBean login(@RequestBody AdminLoginParam adminLoginParam , HttpServletRequest request){
        return iAdminService.login(adminLoginParam.getUsername(),adminLoginParam.getPassword(),adminLoginParam.getCode(),request);
    }
}

2.service层
public interface IAdminService extends IService<Admin> {

    /**
     * 登陆之后返回token
     * @param username
     * @param password
     * @param request
     * @return
     */
    RespBean login(String username, String password, String code, HttpServletRequest request);
}

3.serviceImpl层
@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    /**
     * 登录之后返回token
     * @param username 用户名
     * @param password 密码
     * @param request 请求参数
     * @return RespBean
     */
    @Override
    public RespBean login(String username, String password, String code, HttpServletRequest request) {
        //获取到session中的验证码
        String captcha = (String) request.getSession().getAttribute("captcha");
        if(StringUtils.isEmpty(code) || !code.equalsIgnoreCase(captcha)){
            return RespBean.error("验证码错误,请重新输入!");
        }
        //登录
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        if(null == userDetails || !passwordEncoder.matches(password,userDetails.getPassword())){
            return RespBean.error("用户名或密码不正确");
        }
        if(!userDetails.isEnabled()){
            return RespBean.error("账号被禁用,请联系管理员!");
        }
        //更新security登陆用户对象(把登陆成功的用户放到security的全文中)
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,
                null,userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        //生成token
        String token = jwtTokenUtil.generateToken(userDetails);
        Map<String,String> tokenMap = new HashMap<>();
        tokenMap.put("token",token);
        tokenMap.put("tokenHead",tokenHead);
        return RespBean.success("登陆成功",tokenMap);
    }
}

        7、获取当前登录用户信息

1.controller层
@ApiOperation(value = "获取当前登录用户信息")
@GetMapping("/admin/info")
public Admin getAdminInfo(Principal principal){
        if(principal == null){
        return null;
        }
        String username = principal.getName();
        Admin admin = iAdminService.getAdminByUsername(username);
        admin.setPassword(null);
        return admin;
        }

/**
 * 与前端约定好 后端接口状态码200 来删除请求头里的token
 * @return
 */
@ApiOperation(value = "退出登录")
@PostMapping("/logout")
public RespBean logout(){
        return RespBean.success("注销成功!");
        }

        2.service层
        Admin getAdminByUsername(String username);

        3.serviceImpl层
/**
 * 根据用户名获取用户
 * @param username 用户名
 * @return Admin
 */
@Override
public Admin getAdminByUsername(String username) {
        return adminMapper.selectOne(new QueryWrapper<Admin>().eq("username",username).eq("enabled",1));
}

        8、配置security登录授权过滤器 及 Jwt登录授权过滤器 及 添加自定义未登录 及未授权结果返回

1. security配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private IAdminService iAdminService;

    @Autowired
    private RestAuthorizationEntryPoint restAuthorizationEntryPoint;

    @Autowired
    private RestfulAccessDeniedHandler restfulAccessDeniedHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /** 使用JWT 不需要csrf */
        http.csrf()
                .disable()
                /** 基于token 不需要session */
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                /** 所有的请求都需要被认证 */
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                /** 禁用缓存 */
                .headers()
                .cacheControl();

        /** 添加jwt 登录授权过滤器 */
        http.addFilterBefore(jwtAuthencationTokenFilter(), UsernamePasswordAuthenticationFilter.class);

        /** 添加自定义未登录与未授权结果返回 */
        http.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthorizationEntryPoint);
    }

    /**
     * 重写了UserDetailsService中的方法,编写自己的登录逻辑
     * @return
     */
    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        return username -> {
            Admin admin = iAdminService.getAdminByUsername(username);
            if(null != admin){
                return admin;
            }
            throw new UsernameNotFoundException("用户名或密码不正确!");
        };
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public JwtAuthencationTokenFilter jwtAuthencationTokenFilter(){
        return new JwtAuthencationTokenFilter();
    }
}

2.jwt登录授权过滤器
/**
 * note:jwt登录授权过滤器
 */
public class JwtAuthencationTokenFilter extends OncePerRequestFilter {

    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 所有的登录都需要走该过滤器
     * note:判断该请求是否携带token,如果没有直接过滤掉,如果携带token,需要对该token进行校验,该token是否合法,如果合法则放行,否则过滤掉
     * @param request
     * @param response
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String header = request.getHeader(tokenHeader);   /** 判断请求头部是否携带token */
        //存在token
        if(header != null && header.startsWith(tokenHead)){
            String token = header.substring(tokenHead.length());
            String username = jwtTokenUtil.getUsernameFromToken(token);
            //token存在用户名但未登录
            if(username != null && null == SecurityContextHolder.getContext().getAuthentication()){
                //登录
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                //验证token是否有效,重新设置用户对象
                if(jwtTokenUtil.validateToken(token,userDetails)){
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                            userDetails,null,userDetails.getAuthorities());
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
            }
        }
        filterChain.doFilter(request,response);
    }
}

3.自定义未登录过滤器
/**
 * note:当未登录或者token失效访问接口时,自定义的返回结果
 */
@Component
public class RestAuthorizationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        PrintWriter writer = response.getWriter();
        RespBean bean = RespBean.error("未登录,请登录!");
        bean.setCode(401);
        writer.write(new ObjectMapper().writeValueAsString(bean));
        writer.flush();
        writer.close();
    }
}

4.自定义未授权过滤器
/**
 * note:未授权处理器配置类
 */
@Component
public class RestfulAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        PrintWriter writer = response.getWriter();
        RespBean bean = RespBean.error("权限不足,请联系管理员!");
        bean.setCode(403);
        writer.write(new ObjectMapper().writeValueAsString(bean));
        writer.flush();
        writer.close();
    }
}

        9、配置接口文档swagger

1.security配置类
/**
 * 配置释放的访问路径(swagger接口文档释放口,及登录退出页面释放口)
 * @param web
 * @throws Exception
 */
@Override
public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
        "/login",
        "/logout",
        "/css/**",
        "/js/**",
        "/index.html",
        "favicon.ico",
        "/doc.html",
        "/webjars/**",
        "/swagger-resources/**",
        "/v2/api-docs/**",
        "/captcha"
        );
        }

        2.swagger配置类
/**
 * note:swagger配置类
 */
@Configuration
@EnableSwagger2
public class Swagger2Config {

    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.hierway.controller"))
                .paths(PathSelectors.any())
                .build()
                .securityContexts(securityContexts())
                .securitySchemes(securitySchemes());
    }

    private ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("海量接口文档")
                .description("海量接口文档")
                .contact(new Contact("GuoCe","http://localhost:8081/doc.html","hailiang@hailiang.com"))
                .version("1.0")
                .build();
    }

    private List<ApiKey> securitySchemes(){
        //设置请求头信息
        List<ApiKey> result = new ArrayList<>();
        ApiKey apiKey = new ApiKey("Authorization","Authorization","Header");
        result.add(apiKey);
        return result;
    }

    private List<SecurityContext> securityContexts(){
        //设置需要登录认证的路径
        List<SecurityContext> result = new ArrayList<>();
        result.add(getContextByPath("/hello/.*"));
        return result;
    }

    private SecurityContext getContextByPath(String pathRegex) {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex(pathRegex))
                .build();
    }

    private List<SecurityReference> defaultAuth() {
        List<SecurityReference> result = new ArrayList<>();
        AuthorizationScope authorizationScope = new AuthorizationScope("global","accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        result.add(new SecurityReference("Authorization",authorizationScopes));
        return result;
    }
}        

        10、登录验证码配置

1.添加pom依赖
<!-- google 验证码依赖-->
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>kaptcha</artifactId>
<version>0.0.9</version>
</dependency>

        2.图形验证码配置类
/**
 * note:图形验证码Controller
 */
@Configuration
public class CaptchaConfig {

    @Bean
    public DefaultKaptcha defaultKaptcha(){
        //验证码生成器
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        //配置
        Properties properties = new Properties();
        //是否有边框
        properties.setProperty("kaptcha.border","yes");
        //设置边框颜色
        properties.setProperty("kaptcha.border.color","105,179,90");
        //验证码
        properties.setProperty("kaptcha.session.key","code");
        //验证码文本字符颜色,默认为黑色
        properties.setProperty("kaptcha.textproducer.font.color","blue");
        //设置字体样式
        properties.setProperty("kaptcha.textproducer.font.names","宋体,楷体,微软雅黑");
        //字体大小,默认为40
        properties.setProperty("kaptcha.textproducer.font.size","30");
        //字符长度,默认为5
        properties.setProperty("kaptcha.textproducer.char.length","4");
        //字符间距
        properties.setProperty("kaptcha.textproducer.char.space","4");
        //验证码图片宽度,默认为200
        properties.setProperty("kaptcha.image.width","100");
        //验证码图片高度 默认为40
        properties.setProperty("kaptcha.image.height","40");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;

    }
}

3.图形验证码接口
@RestController
public class CaptchaController {

    @Autowired
    private DefaultKaptcha defaultKaptcha;

    @ApiOperation(value = "获取验证码")
    @GetMapping(value = "/captcha",produces = "image/jpeg")
    public void captcha(HttpServletRequest request, HttpServletResponse response){
        //定义response输出类型为image/jpeg类型
        response.setDateHeader("Expires",0);
        //Set standard HTTP/1.1 no-cache headers
        response.setHeader("Cache-Control","no-store,no-cache,must-revalidate");
        //Set IE extended HTTP/1.1 no-cache headers (use addHeader)
        response.addHeader("Cache-Control","post-check=0,pre-check=0");
        //Set IE extended HTTP/1.1 no-cache header
        response.setHeader("Pragma","no-cache");
        //return a jpeg
        response.setContentType("image/jpeg");

        /** ===============================生成验证码 begin============================ */
        //获取验证码文本内容
        String text = defaultKaptcha.createText();
        System.out.println("验证码内容:" + text);
        //将验证码文本内容放入session  /** captcah */
        request.getSession().setAttribute("captcha",text);
        //根据文本验证码内容创建图形验证码
        BufferedImage image = defaultKaptcha.createImage(text);
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            //输出流输出图片
            ImageIO.write(image,"jpg",outputStream);
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(null != outputStream){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        /** ===============================生成验证码 end============================== */

    }
}

4.swagger配置类释放该接口
/**
 * 配置释放的访问路径(swagger接口文档释放口,及登录退出页面释放口)
 * @param web
 * @throws Exception
 */
@Override
public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
        "/login",
        "/logout",
        "/css/**",
        "/js/**",
        "/index.html",
        "favicon.ico",
        "/doc.html",
        "/webjars/**",
        "/swagger-resources/**",
        "/v2/api-docs/**",
        "/captcha"
        );
        }

        5.登录接口进行校验
//获取到session中的验证码
        String captcha = (String) request.getSession().getAttribute("captcha");
        if(StringUtils.isEmpty(code) || !code.equalsIgnoreCase(captcha)){
        return RespBean.error("验证码错误,请重新输入!");
        }

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只鸟儿

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值