Spring Security 和Swagger常用注解
一、Spring Security概述
Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架
Spring Security的核心:认证(登录),鉴权
1、security认证入门案例
-
添加依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
-
启动项目
security默认提供了一个登录界面,访问地址为:http://127.0.0.1:8080/login
默认的帐号:user 默认密码:会在控制台打印 Using generated security password: e6b75106-50f0-446c-8d62-ee7ab14b27dd
security默认提供了退出系统的业务,访问地址为:http://127.0.0.1:8080/logout
2、使用自定义帐号密码实现认证
在security中用户的密码必须是加密的。否则报错。
Spring Security 内置的 Password Encoder 有:
加密算法名称 | PasswordEncoder |
---|---|
NOOP | NoOpPasswordEncoder.getInstance() |
SHA256 | new StandardPasswordEncoder() |
BCRYPT(官方推荐) | new BCryptPasswordEncoder() |
LDAP | new LdapShaPasswordEncoder() |
PBKDF2 | new Pbkdf2PasswordEncoder() |
SCRYPT | new SCryptPasswordEncoder() |
MD4 | new Md4PasswordEncoder() |
MD5 | new MessageDigestPasswordEncoder(“MD5”) |
SHA_1 | new MessageDigestPasswordEncoder(“SHA-1”) |
SHA_256 | new MessageDigestPasswordEncoder(“SHA-256”) |
/**
* spring security配置类(重点)
*/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 实例化密码管理器
* @return
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 该方法是认证的起点
* 作用: 获得登录页面用户提交的帐号和密码
* 将用户输入的帐号和密码与正确的帐号和密码做对比
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
String pwd= passwordEncoder().encode("123");
auth.inMemoryAuthentication().withUser("tom") //正确的帐号
.password(pwd) //用户正确的密码
.roles("admin"); //用户拥有的权限编码
}
}
二、根据数据库实现认证
1、认证实现
security中的认证请求只能以post方式发送queryString
-
添加依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- springboot 整合mybaits plus 相关 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.2</version> </dependency> <!--实体类工具--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
-
根据用户输入的帐号获得正确的用户信息(用户信息,用户的所有角色编码,用户所有的权限编码)
-
创建处理登录业务的service
@Service @Transactional @Slf4j public class LoginService implements UserDetailsService { @Resource private UserinfoMapper userinfoMapper; @Resource private RoleMapper roleMapper; @Resource private PermissionMapper permissionMapper; /** * UserDetailsService对象是security中用来提供用户正确的帐号,密码,权限的对象 * security中接收登录页面发过来的帐号和密码默认:username,password * @param username the username identifying the user whose data is required. * * @return * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //根据帐号查询用户信息 Userinfo userinfo=userinfoMapper.getUserinfoByAccount(username); String authorities="";//保存用户拥有的权限 if(userinfo!=null){ //根据用户id查询到用户拥有的角色+权限编码 List<String> roleCode=roleMapper.listRoleCode(userinfo.getId()); List<String> perCode=permissionMapper.listPermissionCode(userinfo.getId()); authorities= StringUtils.join(roleCode,","); authorities=authorities+","+StringUtils.join(perCode,","); log.info("用户权限:{}",authorities); } //将查询出来的用户信息,转为security的UserDetails对象, //参数一:正确的帐号 参数二:正确的密码 参数三:用户拥有的权限(角色+权限编码) return new User(userinfo.getAccount(),userinfo.getPassword() , AuthorityUtils.commaSeparatedStringToAuthorityList(authorities)); } }
-
修改security配置类
/** * spring security配置类(重点) */ @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { //认证业务类 @Resource private LoginService loginService; /** * 实例化密码管理器 * @return */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } /** * 该方法是认证的起点 * 作用: 获得登录页面用户提交的帐号和密码 * 将用户输入的帐号和密码与正确的帐号和密码做对比 * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(loginService).passwordEncoder(passwordEncoder()); } }
2、security内置过滤器【重点】
security默认有13个过滤器,不同的功能由不同的过滤器来执行,我们只需要记住下面四个即可
-
LogoutFilter: 在过滤器链的第三个,用来拦截用户的退出请求。默认删除保存在security的session中存的认证令牌
-
UsernamePasswordAuthenticationFilter:认证的过滤器,当用户发送logitn请求时会被该过滤器拦截(获得用户输入的帐号和密码)
security中的认证请求必须是post方式且数据格式为queryString
-
ExceptionTranslationFilter: 异常过滤器,security中所有的异常都由该过滤器捕获,在过滤器链的倒数第二个
-
FilterSecurityInterceptor: 鉴权过滤器,在过滤器链的倒数第一个
注意:security中出现的异常,只能由security自己才能捕获到。
3、认证失败后的处理(返回json提示)
-
修改security配置类
/** * spring security配置类(重点) */ @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Resource private LoginService loginService; /** * 实例化密码管理器 * @return */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } /** * 该方法是认证的起点 * 作用: 获得登录页面用户提交的帐号和密码 * 将用户输入的帐号和密码与正确的帐号和密码做对比 * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(loginService).passwordEncoder(passwordEncoder()); } /** * security过滤器链操作 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { //鉴权相关的过滤器 暂时不管 http.authorizeRequests() .anyRequest() .authenticated(); // 1 //配置与登录相关的过滤器 http.formLogin() .permitAll();//这句配置很重要,新手容易忘记。 //关闭security session(使用redis存用户的认证token) http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.csrf().disable(); //关闭csrf } }
认证过滤器配置补充说明【了解】:
//配置与登录相关的过滤器 http.formLogin() .loginPage("/index.html") //设置项目默认登录页面 .loginProcessingUrl("/dologin") //修改认证请求的url .usernameParameter("account") //用户的帐号必须叫account .passwordParameter("pwd") .permitAll();//这句配置很重要,新手容易忘记。放开 login.html和dologin 的访问权
-
创建认证失败的处理器
/** * 认证失败的处理器 */ @Component public class SimpleAuthenticationFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException exception) throws IOException, ServletException { //设置响应数据的编码 httpServletResponse.setContentType("application/json;charset=UTF-8"); ResponseResult<Void> responseResult=null; if(exception instanceof InternalAuthenticationServiceException){ responseResult=new ResponseResult<Void>(2007, "帐号不存在"); } if(exception instanceof BadCredentialsException){ responseResult=new ResponseResult<Void>(2003, "密码错误"); } //输出json字符串到客户端 PrintWriter printWriter =httpServletResponse.getWriter(); printWriter.print(JacksonUtil.toJsonString(responseResult)); printWriter.flush(); printWriter.close(); } }
-
将认证失败处理器注册到认证过滤器中
/** * security过滤器链操作 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { //鉴权相关的过滤器 暂时不管 http.authorizeRequests() .anyRequest() .authenticated(); // 1 //配置与登录相关的过滤器 http.formLogin() .failureHandler(simpleAuthenticationFailureHandler) //认证失败后的处理器 .permitAll();//这句配置很重要,新手容易忘记。放开 login.html和dologin 的访问权 //关闭security session(使用redis存用户的认证token) http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.csrf().disable(); //关闭csrf }
4、认证成功后的处理
-
创建认证成功后的处理器
/** * 认证成功后的处理器 */ @Component public class SimpleAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Resource private RedisMapper redisMapper; @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { //设置响应数据的编码 httpServletResponse.setContentType("application/json;charset=UTF-8"); //从security中取出保存的用户信息(帐号,权限) User user= (User) authentication.getPrincipal(); //获得帐号 String account= user.getUsername().split(",")[1]; //获得权限 Collection<GrantedAuthority> authoriteList= user.getAuthorities(); String authorites= StringUtils.join(authoriteList,","); //生成jwsToken String jwsToken= JwtUtils.createJwtToken(user.getUsername()); //获得用户的帐号和权限,保存到redis redisMapper.setKey(account+":login",jwsToken,30, TimeUnit.MINUTES ); redisMapper.setKey(account+":author", authorites,30, TimeUnit.MINUTES ); //返回 ResponseResult<String> responseResult=new ResponseResult<String>(2000, "OK", jwsToken); //输出json字符串到客户端 PrintWriter printWriter =httpServletResponse.getWriter(); printWriter.print(JacksonUtil.toJsonString(responseResult)); printWriter.flush(); printWriter.close(); } }
-
将认证成功处理器注册到认证过滤器中
/** * security过滤器链操作 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { //鉴权相关的过滤器 暂时不管 http.authorizeRequests() .anyRequest() .authenticated(); // 1 //配置与登录相关的过滤器 http.formLogin() .successHandler(simpleAuthenticationSuccessHandler) //认证成功后的处理地器 .failureHandler(simpleAuthenticationFailureHandler) //认证失败后的处理器 .permitAll();//这句配置很重要,新手容易忘记。放开 login.html和dologin 的访问权 //关闭security session(使用redis存用户的认证token) http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.csrf().disable(); //关闭csrf }
5、security认证流程【重点】
- 当用户发送的请求中带有login字符串,会被UsernamePasswordAuthenticationFilter过滤器拦截
- 拦截到登录请求会会获得用户输入的帐号和密码并保存到AuthenticationManager。
- AuthenticationManager将用户输入的帐号传给UserDetailsService,通过UserDetailsService获得用户正确的信息(密码,权限)。封装到UserDetails对象中返回给AuthenticationManager
- “表面上” AuthenticationManager的做认证和鉴权比对工作的那个人,它是认证和鉴权比对工作的起点。实际上是由AuthenticationProvider 接口的实现类ProvierderManager
6、退出处理器
-
创建退出成功处理器
/** * 退出成功处理器 */ @Component public class SimpLogoutSuccessHandler implements LogoutSuccessHandler { @Resource private RedisMapper redisMapper; @Override public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { //设置响应数据的编码 httpServletResponse.setContentType("application/json;charset=UTF-8"); //获得请求头 String jwsToken = httpServletRequest.getHeader("jwsToken"); //解析 String str = JwtUtils.getUserNameFormJwt(jwsToken); String account = str.split(",")[1]; //删除redis中的登录和权限token redisMapper.delKey(account + ":login"); redisMapper.delKey(account + ":author"); ResponseResult<Void> responseResult = new ResponseResult<Void>(2000, "退出系统成功"); //输出json字符串到客户端 PrintWriter printWriter = httpServletResponse.getWriter(); printWriter.print(JacksonUtil.toJsonString(responseResult)); printWriter.flush(); printWriter.close(); } }
-
修改security配置类
/** * security过滤器链操作 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { //鉴权相关的过滤器 暂时不管 http.authorizeRequests() .anyRequest() .authenticated(); // 1 //配置与登录相关的过滤器 http.formLogin() .successHandler(simpleAuthenticationSuccessHandler) //认证成功后的处理地器 .failureHandler(simpleAuthenticationFailureHandler) //认证失败后的处理器 .permitAll();//这句配置很重要,新手容易忘记。放开 login.html和dologin 的访问权 //退出操作 http.logout().logoutSuccessHandler(simpleLogoutSuccessHandler);//退出成功处理器 //关闭security session(使用redis存用户的认证token) http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.csrf().disable(); //关闭csrf }
三、security鉴权
1、自定义过滤器对token续期
鉴权前需要判断用户是否登录过。续期
-
创建自定义过滤器,判断用户是否登录过。登录过则续期。没有登录过则提示
/** * 判断用户是否登录过 */ @Component public class JwtFilter extends OncePerRequestFilter { @Resource private RedisMapper redisMapper; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { //判断当前请求是不是非登录请求 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if(authentication!=null){ //上下文中有AuthenticationToken表示当前是登录请求直接放行 filterChain.doFilter(request, response); return; } /* 非登录请求,判断用户是否登录过 */ String tokenStr=request.getHeader("jwsToken"); // 请求头中没有token 未登录 if(StringUtils.isEmpty(tokenStr)){ //请求中没有请求头,放行到下一个过滤器(异常过滤器) filterChain.doFilter(request, response); return; } //有token,验证token是否合法 不合法提示 if(!JwtUtils.verify(tokenStr)){ //不合法 filterChain.doFilter(request, response); return; } //合法,判断redis中token是否过期 不存在 //解板出帐号 String userStr=JwtUtils.getUserNameFormJwt(tokenStr); String account=userStr.split(",")[1]; if(redisMapper.getKey(account+":login")==null){ //token已过期 filterChain.doFilter(request, response); return; } //合法,与redis中不一样 String redisToken= redisMapper.getKey(account+":login").toString(); if(!tokenStr.equals(redisToken)){ //请求头中的token和redis中的token不一样 filterChain.doFilter(request, response); return; } //合法,没过期 续期 String authorites=redisMapper.getKey(account+":author").toString(); redisMapper.setKey(account+":login",redisToken,30, TimeUnit.MINUTES ); redisMapper.setKey(account+":author", authorites,30, TimeUnit.MINUTES ); //将jwtToken转为usernamePasswordAuthenticationToker UsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(userStr,redisToken, AuthorityUtils.commaSeparatedStringToAuthorityList(authorites)); //将security认证令牌添加到上下文中 SecurityContextHolder.getContext().setAuthentication(authenticationToken); filterChain.doFilter(request, response);//放行到下一个过滤器 } }
-
将自定义过滤器添加到security过滤器链中
必须添加到UsernamePasswordAuthenticationFilter和ExceptionTranslationFilter之间
/** * security过滤器链操作 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { //鉴权相关的过滤器 暂时不管 http.authorizeRequests() .anyRequest() .authenticated(); // 1 //配置与登录相关的过滤器 http.formLogin() .successHandler(simpleAuthenticationSuccessHandler) //认证成功后的处理地器 .failureHandler(simpleAuthenticationFailureHandler) //认证失败后的处理器 .permitAll();//这句配置很重要,新手容易忘记。放开 login.html和dologin 的访问权 //退出操作 http.logout().logoutSuccessHandler(simpleLogoutSuccessHandler);//退出成功处理器 //将JwtFilter添加以认证过滤器下面 http.addFilterAfter(jwtFilter, UsernamePasswordAuthenticationFilter.class); //关闭security session(使用redis存用户的认证token) http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.csrf().disable(); //关闭csrf }
2、鉴权异常处理
FilterSecurityInterceptor 会抛出 2 种异常
-
在用户 “该登录而未登录” 时,抛出 AuthenticationException 异常;默认情况下,抛出 AuthenticationException 异常时,Spring Security 返回 401 错误:未授权(Unauthorized)。
-
在用户 “权限不够” 时,抛出 AccessDeniedException 异常。默认情况下,抛出 AccessDeniedException 异常时,Spring Security 返回 403 错误:被拒绝(Forbidden)访问
-
创建认证异常处理器
/** * 认证异常处理器 */ @Component public class SimpleAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { //设置响应数据的编码 httpServletResponse.setContentType("application/json;charset=UTF-8"); ResponseResult<Void> responseResult=new ResponseResult<Void>(4001, "未登录或token已过期"); //输出json字符串到客户端 PrintWriter printWriter =httpServletResponse.getWriter(); printWriter.print(JacksonUtil.toJsonString(responseResult)); printWriter.flush(); printWriter.close(); } }
-
创建鉴权异常处理器
/** * 鉴权异常 */ @Component public class SimpleAccessDeniedHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException { //设置响应数据的编码 httpServletResponse.setContentType("application/json;charset=UTF-8"); ResponseResult<Void> responseResult=new ResponseResult<Void>(4003, "无此权限请联系管理员"); //输出json字符串到客户端 PrintWriter printWriter =httpServletResponse.getWriter(); printWriter.print(JacksonUtil.toJsonString(responseResult)); printWriter.flush(); printWriter.close(); } }
-
修改security配置类
/** * security过滤器链操作 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { //鉴权相关的过滤器 暂时不管 http.authorizeRequests() .anyRequest() .authenticated(); // 1 //配置与登录相关的过滤器 http.formLogin() .successHandler(simpleAuthenticationSuccessHandler) //认证成功后的处理地器 .failureHandler(simpleAuthenticationFailureHandler) //认证失败后的处理器 .permitAll();//这句配置很重要,新手容易忘记。放开 login.html和dologin 的访问权 //退出操作 http.logout().logoutSuccessHandler(simpleLogoutSuccessHandler);//退出成功处理器 //将JwtFilter添加以认证过滤器下面 http.addFilterAfter(jwtFilter, UsernamePasswordAuthenticationFilter.class); //鉴权异常处理 http.exceptionHandling() .authenticationEntryPoint(simpleAuthenticationEntryPoint) //认证异常 .accessDeniedHandler(simpleAccessDeniedHandler); //鉴权异常 //关闭security session(使用redis存用户的认证token) http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.csrf().disable(); //关闭csrf }
3、鉴权
在security中支持两种鉴权方式:配置类方式,注解
a、配置类方式【了解】
当前用户是否有权限访问某个 URI 的相关配置也是写在 configure(HttpSecurity http)
方法中。
.antMatchers() 方法是一个采用 ANT 风格的 URL 匹配器。
-
使用
?
匹配任意单个字符 -
使用
*
匹配 0 或任意数量的字符 -
使用
**
匹配 0 或更多的目录
权限表达式 | 说明 |
---|---|
permitAll() | 永远返回 true |
denyAll() | 永远返回 false |
anonymous() | 当前用户是匿名用户(anonymous)时返回 true |
rememberMe() | 当前用户是 rememberMe 用户时返回 true |
authentication | 当前用户不是匿名用户时,返回 true |
fullyAuthenticated | 当前用户既不是匿名用户,也不是 rememberMe 用户时,返回 true |
hasRole(“role”) | 当用户拥有指定身份时,返回 true |
hasAnyRole(“role1”, “role2”, …) | 当用户返回指定身份中的任意一个时,返回 true |
hasAuthority(“authority1”) | 当用于拥有指定权限时,返回 true |
hasAnyAuthority(“authority1”, “authority2”) | 当用户拥有指定权限中的任意一个时,返回 true |
hasIpAddress(“xxx.xxx.x.xxx”) | 发送请求的 ip 符合指定时,返回 true |
principal | 允许直接访问主体对象,表示当前用户 |
修改配置类
/**
* security过滤器链操作
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
//鉴权相关的过滤器 暂时不管
http.authorizeRequests()
.antMatchers("/goods/list").hasRole("EXPLOIT") //角色值必须大写,且前面不能加ROLE_
.antMatchers("/goods/list").hasAuthority("goods:list")
.antMatchers("/hello").anonymous() //匿名可访问
.antMatchers("/hello2").permitAll() //不管有没有权限都可以访问
.anyRequest()
.authenticated(); // 1
//配置与登录相关的过滤器
http.formLogin()
.successHandler(simpleAuthenticationSuccessHandler) //认证成功后的处理地器
.failureHandler(simpleAuthenticationFailureHandler) //认证失败后的处理器
.permitAll();//这句配置很重要,新手容易忘记。放开 login.html和dologin 的访问权
//退出操作
http.logout().logoutSuccessHandler(simpleLogoutSuccessHandler);//退出成功处理器
//将JwtFilter添加以认证过滤器下面
http.addFilterAfter(jwtFilter, UsernamePasswordAuthenticationFilter.class);
//鉴权异常处理
http.exceptionHandling()
.authenticationEntryPoint(simpleAuthenticationEntryPoint) //认证异常
.accessDeniedHandler(simpleAccessDeniedHandler); //鉴权异常
//关闭security session(使用redis存用户的认证token)
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.csrf().disable(); //关闭csrf
}
b、注解方式【日常使用】
只需要在controller方法上添加鉴权注解即可。
security支持三套鉴权注解,默认都是关闭状态需要打开。
JSR-250 注解:基于角色的权限验证
@RolesAllowed 拥有指定角色才能访问
@DenyAll 匿名可访问
@PermitAll 永远可访问
@Secured 注解是 jsr250 标准出现之前,Spring Security 框架自己定义的注解。基于角色的权限验证
PrePost 注解: Spring Security 框架自己定义的注解
@PreAuthorize("hasRole('USER')") 判断是否拥有指定角色
@PreAuthorize("hasAuthority('user:insert')") 判断是否拥有指定权限
-
开启security注解支持
/** * spring security配置类(重点) */ @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) //开启PrePost注解 public class SecurityConfig extends WebSecurityConfigurerAdapter { }
-
修改controller
@PostMapping("/goods/add") @PreAuthorize("hasAuthority('goods:add')") public ResponseResult<Goods> addGoods(@RequestBody Goods goods){ return new ResponseResult<>(2000, goods); }
如果需要配置匿名访问,只能在配置类中进行
四、Swagger常用注解
-
@Api:写在controller类上,对类的说明
@RestController @Api(tags = "商品API") public class GoodsController
-
@ApiOperation: 写在controller方法上,对方法进行说明
@GetMapping("/goods/delete") @PreAuthorize("hasAuthority('goods:delete')") @ApiOperation(value = "删除商品", notes = "根据id删除商品", response =ResponseResult.class ) public ResponseResult<Void> deleteGoods(Integer id) 属性说明: value:方法说明标题 notes:方法详细描述 response:方法返回值类型
-
@ApiImplicitParams: 对方法的非对象形参进行说明
@GetMapping("/goods/delete") @ApiImplicitParams(value = { @ApiImplicitParam(name="id", value = "商品id", type = "Integer", required = false, paramType = "query", defaultValue = "0") }) public ResponseResult<Void> deleteGoods(@RequestParam(value = "id",required = false,defaultValue = "0") Integer id) 属性说明: name:形参名称 value:形参的说明文字 type:形参类型 required:该参数是否必须 true|false paramType: 用于描述参数是以何种方式传递到 Controller 的,它的值常见有: path, query, body 和 header path 表示参数是『嵌在』路径中的,它和 @PathVariable 参数注解遥相呼应; query 表示参数是以 query string 的形式传递到后台的(无论是 get 请求携带在 url 中,还是 post 请求携带在请求体中),它和 @RequestParam 参数注解遥相呼应; body 表示参数是以 json string 的形式携带在请求体中传递到后台的,它和 @RequestBody 参数注解遥相呼应; header 表示参数是『藏在』请求头中传递到后台的,它和 @RequestHeader 参数注解遥相呼应的。 form 不常用。 defaultValue :参数默认值
-
@ApiModel: 对方法的对象形参进行说明
该注解是写在形参对象中
-
修改形参实体类
@ApiModel public class Goods implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "商品编号,自增主键") private Integer id; /** * 商品名称 */ @ApiModelProperty(value = "商品名称") private String goodsName; /** * 单价 */ @ApiModelProperty(value = "商品单价") private BigDecimal price; }
-
-
ApiResponse: 用于方法的返回值说明
@PostMapping("/goods/add") @PreAuthorize("hasAuthority('goods:add')") @ApiOperation(value = "添加商品", notes = "添加商品", response =ResponseResult.class ) @ApiResponses({ @ApiResponse(code = 2000, message = "添加成功", response = ResponseResult.class), @ApiResponse(code = 5000, message = "添加失败", response = ResponseResult.class) }) public ResponseResult<Goods> addGoods(@RequestBody Goods goods)