anonymoususer,anonymous letter

  

  背景:   

  

  最近选型使用昵称的前后端分离框架进行研发,除了管理系统部分还有小程序部分功能,需要提供美国石油学会(美国石油协会)给小程序部分,而小程序使用信息关联用户名,这样希望提供只根据用户名能够获取代币进行后续后台服务接口的访问需求,具体改造如下:   

  

  增加5个关键类和一个测试类修改一个配置类,具体如下:   

  

  拦截特殊验证的拦截器类   

  

  包com。若伊。框架。配置。q;导入Java。io。io异常;导入javax。servlet。servlet异常;导入javax。servlet。http。http servlet请求;导入javax。servlet。http。http servlet响应;导入组织。spring框架。安全。正宗的。authenticationserviceexception;导入org。spring框架。安全。核心。真实性;导入组织。spring框架。安全。核心。authenticationexception导入组织。spring框架。安全。网络。正宗的。abstractauthenticationprocessingfilter;导入组织。spring框架。安全。网络。util。火柴人。antpathrequestmatcher导入org。spring框架。util。字符串实用程序;公共类QAuthenticationProcessingFilter扩展了AbstractAuthenticationProcessingFilter { public static final String SPRING _ SECURITY _ FORM _ USERNAME _ KEY=' KEY ';私有字符串KEY参数=SPRING _ SECURITY _ FORM _ USERNAME _ KEY;public QAuthenticationProcessingFilter(){ super(new AntPathRequestMatcher('/loginq ',' GET ');} @覆盖公共验证尝试验证(http servlet请求请求,HttpServletResponse响应)抛出AuthenticationException,IOException,servlet异常{ String key=获取密钥(请求);if(字符串实用程序。isempty(key)){ throw new AuthenticationServiceException(' key不能为空');} //TODO根据键查询用户名字符串用户名=密钥返回this.getAuthenticationManager().认证(新的QAuthenticationToken(用户名));}受保护的字符串获取密钥(HttpServletRequest请求){退货请求。getparameter(关键参数);}}验证实际处理类   

  

  包com。若伊。框架。配置。q;导入org。spring框架。豆子。工厂。注释。自动连线;导入组织。spring框架。安全。正宗的。badcredentialsexception导入组织。spring框架。安全。正宗的。usernamepasswordtuthenticationtoken;导入组织。spring框架。安全。正宗的。道。abstractuserdailsauthenticationprovider;导入org。spring框架。安全。核心。真实性;导入org。spring框架。安全。核心。作家(author的简写)   

enticationException;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;public class QAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { /** * 自定义用户认证逻辑 */ @Autowired private UserDetailsService userDetailsService; @Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { QAuthenticationToken qToken = (QAuthenticationToken) authentication; try { UserDetails userDetails = userDetailsService.loadUserByUsername(qToken.getUserName()); return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); } catch (Exception e) { logger.error(e); throw new BadCredentialsException("q登录异常:" + e.getMessage()); } } @Override protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { return null; } @Override public boolean supports(Class<?> authentication) { return (QAuthenticationToken.class.isAssignableFrom(authentication)); }}验证通过后的处理类

  

package com.ruoyi.framework.config.q;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpStatus;import org.springframework.security.core.Authentication;import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;import com.alibaba.fastjson.JSONObject;import com.ruoyi.common.constant.Constants;import com.ruoyi.common.core.domain.AjaxResult;import com.ruoyi.common.utils.SecurityUtils;import com.ruoyi.framework.web.service.TokenService;public class QAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { @Autowired private TokenService tokenService; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { //super.onAuthenticationSuccess(request, response, authentication); AjaxResult ajax = AjaxResult.success(); String token = tokenService.createToken(SecurityUtils.getLoginUser()); ajax.put(Constants.TOKEN, token); response.setContentType("application/json;charset=utf-8"); response.setStatus(HttpStatus.OK.value()); PrintWriter out = response.getWriter(); out.write(JSONObject.toJSONString(ajax)); out.flush(); out.close(); }}package com.ruoyi.framework.config.q;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.http.HttpStatus;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.AuthenticationFailureHandler;import com.alibaba.fastjson.JSONObject;import com.ruoyi.common.core.domain.AjaxResult;public class QAuthenticationFailureHandler implements AuthenticationFailureHandler {@Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { AjaxResult ajax = AjaxResult.error(exception.getMessage());response.setContentType("application/json;charset=utf-8"); response.setStatus(HttpStatus.OK.value()); PrintWriter out = response.getWriter(); out.write(JSONObject.toJSONString(ajax)); out.flush(); out.close(); }}验证bean对象

  

package com.ruoyi.framework.config.q;import org.springframework.security.authentication.AbstractAuthenticationToken;public class QAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = 1L;private String userName; public QAuthenticationToken(String userName) { super(null); this.setUserName(userName); } @Override public Object getCredentials() { return null; } @Override public Object getPrincipal() { return null; }public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}}测试类如下

  

package com.ruoyi.framework.config.q;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import com.ruoyi.common.core.domain.AjaxResult;@RestControllerpublic class QTestBizController {/** * 登录方法 * * @param loginBody 登录信息 * @return 结果 */@GetMapping("/loginq/test")public AjaxResult test() {AjaxResult ajax = AjaxResult.success();ajax.put("test", "test123");return ajax;}}6.SecurityConfig配置中增加部分配置,详细差别请自行对比

  

package com.ruoyi.framework.config;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.http.HttpMethod;import org.springframework.security.authentication.AuthenticationManager;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.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.web.authentication.UsernamePasswordAuthenticationFilter;import org.springframework.security.web.authentication.logout.LogoutFilter;import org.springframework.web.filter.CorsFilter;import com.ruoyi.framework.config.q.QAuthenticationFailureHandler;import com.ruoyi.framework.config.q.QAuthenticationProcessingFilter;import com.ruoyi.framework.config.q.QAuthenticationProvider;import com.ruoyi.framework.config.q.QAuthenticationSuccessHandler;import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;/** * spring security配置 * * @author ruoyi */@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)public class SecurityConfig extends WebSecurityConfigurerAdapter{ /** * 自定义用户认证逻辑 */ @Autowired private UserDetailsService userDetailsService; /** * 认证失败处理类 */ @Autowired private AuthenticationEntryPointImpl unauthorizedHandler; /** * 退出处理类 */ @Autowired private LogoutSuccessHandlerImpl logoutSuccessHandler; /** * token认证过滤器 */ @Autowired private JwtAuthenticationTokenFilter authenticationTokenFilter; /** * 跨域过滤器 */ @Autowired private CorsFilter corsFilter; /** * 解决 无法直接注入 AuthenticationManager * * @return * @throws Exception */ @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } /** * anyRequest | 匹配所有请求路径 * access | SpringEl表达式结果为true时可以访问 * anonymous | 匿名可以访问 * denyAll | 用户不能访问 * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录) * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问 * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问 * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问 * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问 * hasRole | 如果有参数,参数表示角色,则其角色可以访问 * permitAll | 用户可以任意访问 * rememberMe | 允许通过remember-me登录的用户访问 * authenticated | 用户登录后可访问 */ @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity // CSRF禁用,因为不使用session .csrf().disable() // 认证失败处理类 .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() // 基于token,所以不需要session .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() // 过滤请求 .authorizeRequests() // 对于登录login 验证码captchaImage 允许匿名访问 .antMatchers("/login", "/captchaImage").anonymous() .antMatchers( HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js" ).permitAll() .antMatchers("/profile/**").anonymous() .antMatchers("/common/download**").anonymous() .antMatchers("/common/download/resource**").anonymous() .antMatchers("/swagger-ui.html").anonymous() .antMatchers("/swagger-resources/**").anonymous() .antMatchers("/webjars/**").anonymous() .antMatchers("/*/api-docs").anonymous() .antMatchers("/druid/**").anonymous() // 除上面外的所有请求全部需要鉴权认证 .anyRequest().authenticated() .and() .headers().frameOptions().disable(); httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler); // 添加JWT filter httpSecurity.addFilterBefore(qAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class); httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // 添加CORS filter httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class); httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class); } @Bean public QAuthenticationProcessingFilter qAuthenticationProcessingFilter() throws Exception { QAuthenticationProcessingFilter filter = new QAuthenticationProcessingFilter(); filter.setAuthenticationSuccessHandler(qAuthenticationSuccessHandler()); filter.setAuthenticationFailureHandler(qAuthenticationFailureHandler()); filter.setAuthenticationManager(super.authenticationManagerBean()); return filter; } @Bean public QAuthenticationSuccessHandler qAuthenticationSuccessHandler() { // 不配置跳转地址,为了返回数据流 QAuthenticationSuccessHandler qAuthenticationSuccessHandler = new QAuthenticationSuccessHandler(); return qAuthenticationSuccessHandler; } @Bean public QAuthenticationFailureHandler qAuthenticationFailureHandler() { // 不配置跳转地址,为了返回数据流 QAuthenticationFailureHandler qAuthenticationFailureHandler = new QAuthenticationFailureHandler(); return qAuthenticationFailureHandler; } /** * 强散列哈希加密实现 */ @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @Bean public QAuthenticationProvider qAuthenticationProvider() { return new QAuthenticationProvider(); } /** * 身份认证接口 */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(qAuthenticationProvider()); auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); }}测试效果方式如下:

  

通过访问http://localhost:8088/loginq?key=admin获取token

  

正确结果是:

  

{"msg":"操作成功","code":200,"token":"eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImFjNTcwMmJhLWQyYTItNDBlZS1hYjVkLTI2ZDExYjU4Yzk5OSJ9.R2ROekesiKL1fngPletnl6WfSqka-GGKq0zkBrHfnjIyAyjGtaENOM6L_AJKI5c4XXEBr0iOl44chY4RqJbwlw"}

  

如果未获取到结果如下:

  

{"msg":"key不能为空","code":500}

  


  

通过访问http://localhost:8088/loginq/test并且在header头中增加Authorization为key,值为上一个返回的token执行测试

相关文章