区块链技术博客
www.b2bchain.cn

重构用户名密码登录获取token

这篇文章主要介绍了重构用户名密码登录获取token的讲解,通过具体代码实例进行24263 讲解,并且分析了重构用户名密码登录获取token的详细步骤与相关技巧,需要的朋友可以参考下https://www.b2bchain.cn/?p=24263

本文实例讲述了2、树莓派设置连接WiFi,开启VNC等等的讲解。分享给大家供大家参考文章查询地址https://www.b2bchain.cn/7039.html。具体如下:

重构用户名密码登录获取token
重构用户名密码登录获取token

文章目录

  • 用户名密码登录获取token
    • WhaleAuthenticationSuccessHandler
    • WhaleResourceServerConfig
    • 启动测试获取token
  • 重构短信登录获取token
    • 测试用手机验证获取token
      • WhaleResourceServerConfig
      • 拿着token请求发送手机短信验证码的接口
      • postman用手机短信码去获取token及问题
    • 重构验证码存储逻辑
      • @Autowired
      • 验证码存储 ValidateCodeRepository
        • RedisValidateCodeRepository
        • SessionValidateCodeRepository
      • AbstractValidateCodeProcessor 更换验证码存储接口
      • redis配置
    • 测试

重构用户名密码登录获取token

用户名密码登录获取token

WhaleAuthenticationSuccessHandler

AuthenticationSuccessHandler
在成功处理器中根据请求头解析出client-id
重构用户名密码登录获取token
参考 org.springframework.security.web.authentication.www.BasicAuthenticationFilter#doFilterInternal

@Component("whaleAuthenticationSuccessHandler") public class WhaleAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {  	private Logger logger = LoggerFactory.getLogger(getClass());  	// ObjectMapper spring mvc 提供的 	@Autowired 	private ObjectMapper objectMapper;  	@Autowired 	private SecurityProperties securityProperties;  	@Autowired 	private ClientDetailsService clientDetailsService;  	@Autowired 	private  AuthorizationServerTokenServices authorizationServerTokenServices;   	/* 	 * (non-Javadoc) 	 *  	 * @see org.springframework.security.web.authentication. 	 * AuthenticationSuccessHandler#onAuthenticationSuccess(javax.servlet.http. 	 * HttpServletRequest, javax.servlet.http.HttpServletResponse, 	 * org.springframework.security.core.Authentication) 	 */ 	@Override 	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, 										Authentication authentication) throws IOException, ServletException {  		logger.info("登录成功");  		String header = request.getHeader("Authorization");  		if (header == null || !header.toLowerCase().startsWith("basic ")) { //			chain.doFilter(request, response); 			throw new UnapprovedClientAuthenticationException("请求头中无client信息"); //			return; 		} //		try { 		String[] tokens = extractAndDecodeHeader(header, request); 		assert tokens.length == 2;  		String username = tokens[0];  		String clientId = tokens[0]; 		String clientSecret = tokens[1];  		//拿到了clientDetails 		ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);         //校验 		if(clientDetails==null){ 			throw new UnapprovedClientAuthenticationException("client-id对应信息不存在:"+clientId); 		}else if(! StringUtils.equals(clientDetails.getClientSecret(),clientSecret)){ 			throw new UnapprovedClientAuthenticationException("client-secret对应信息不匹配:"+clientSecret); 		}  		//不需要再构建authentication 传一个空的map 		//grantType 为四种授权模式  我们是自定义的 		TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP,clientId,clientDetails.getScope(),"custom");  		OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);  		OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);  		OAuth2AccessToken oAuth2AccessToken = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);    		response.setContentType("application/json;charset=UTF-8"); //		response.getWriter().write(objectMapper.writeValueAsString(authentication)); 		response.getWriter().write(objectMapper.writeValueAsString(oAuth2AccessToken));  //		if(LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())){ //			response.setContentType("application/json;charset=UTF-8"); //			response.getWriter().write(objectMapper.writeValueAsString(authentication)); //		}else { //			//如果配置的返回类型不是json,则调用父类方法,进行跳转 //			super.onAuthenticationSuccess(request,response,authentication); //		}  	}  		/** 		 * Decodes the header into a username and password. 		 * 		 * @throws BadCredentialsException if the Basic header is not present or is not valid 		 * Base64 		 */ 		private String[] extractAndDecodeHeader(String header, HttpServletRequest request) 			throws IOException {  			byte[] base64Token = header.substring(6).getBytes("UTF-8"); 			byte[] decoded; 			try { 				decoded = Base64.getDecoder().decode(base64Token); 			} 			catch (IllegalArgumentException e) { 				throw new BadCredentialsException( 						"Failed to decode basic authentication token"); 			}  //			String token = new String(decoded, getCredentialsCharset(request)); 			String token = new String(decoded, "UTF-8");  			int delim = token.indexOf(":");  			if (delim == -1) { 				throw new BadCredentialsException("Invalid basic authentication token"); 			} 			return new String[] { token.substring(0, delim), token.substring(delim + 1) }; 		} } 

WhaleResourceServerConfig

参考 BrowserSecurityConfig

@Configuration @EnableResourceServer public class WhaleResourceServerConfig extends ResourceServerConfigurerAdapter {      @Autowired     protected AuthenticationSuccessHandler whaleAuthenticationSuccessHandler;      @Autowired     protected AuthenticationFailureHandler whaleAuthenticationFailureHandler;      @Autowired     private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;      @Autowired     private SecurityProperties securityProperties;      @Override     public void configure(HttpSecurity http) throws Exception {         super.configure(http);          http.formLogin()                 .loginPage(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL)                 .loginProcessingUrl(SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_FORM)                 .successHandler(whaleAuthenticationSuccessHandler)                 .failureHandler(whaleAuthenticationFailureHandler);          http//.apply(validateCodeSecurityConfig)                //.and()                 .apply(smsCodeAuthenticationSecurityConfig)                 .and()                /*                APP上没有rember的概念                .rememberMe()                 .tokenRepository(persistentTokenRepository())                 .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSecodes())*/                /* .userDetailsService(userDetailsService)                 .and()                 .sessionManagement()                  .invalidSessionStrategy(invalidSessionStrategy)                 .maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())                 .maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())                 .expiredSessionStrategy(sessionInformationExpiredStrategy)*/  //                .invalidSessionUrl("/session/invalid") //                .maximumSessions(1)//为1 后面登录的session会把前面的登录的session失效掉 //                .maxSessionsPreventsLogin(true)//当session数量达到最大时 阻止后面的登录 //                .expiredSessionStrategy(new MyExpiredSessionStrategy())//并发登录导致超时的处理策略 //                .and() //                .and() //                .logout() //                .logoutUrl("/signOut") //                .logoutSuccessUrl("/logOut.html") //                .logoutSuccessHandler(LogoutSuccessHandler) //Handler和Url是互斥的 //                .deleteCookies("JESSIONID")//清除cookie中的 当前session id //                .and()                 .authorizeRequests()                 .antMatchers(                         SecurityConstants.DEFAULT_UNAUTHENTICATION_URL,                         SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE,                         securityProperties.getBrowser().getLoginPage(),                         SecurityConstants.DEFAULT_VALIDATE_CODE_URL_PREFIX+"/*",                         securityProperties.getBrowser().getSession().getSessionInvalidUrl()+".json",                         securityProperties.getBrowser().getSession().getSessionInvalidUrl()+".html",                         "/session/invalid")                 .permitAll()                 .anyRequest()                 .authenticated()                 .and()                 .cors().disable().csrf().disable();// 禁用跨站攻击      } } 

启动测试获取token

模拟表单登录获取token
重构用户名密码登录获取token重构用户名密码登录获取token

拿着token请求资源
重构用户名密码登录获取token
直接浏览器访问会报错
重构用户名密码登录获取token

重构短信登录获取token

测试用手机验证获取token

重构用户名密码登录获取token

WhaleResourceServerConfig

重构用户名密码登录获取token这个不能配置,因为如果加上了验证码校验的配置,表单获取token的时候也就需要验证码了,
继而不能请求发送手机短信的token,后面再说吧
解决
ValidateCodeFilter 注释掉表单登录的验证码验证

//        urlMap.put(SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_FORM, ValidateCodeType.IMAGE); 

ok

拿着token请求发送手机短信验证码的接口

上次的token9995dfa3-f3c5-441d-9e3a-032ab62eec02
重构用户名密码登录获取token
只需要在请求头上加上token就可以请求资源

重构用户名密码登录获取token

postman用手机短信码去获取token及问题

重构用户名密码登录获取token
我们的postman是模拟浏览器请求,会带上cookie,cookie里面又还有session id 可以找到session
但是如果我们用代码去发送请求,它是没有cookie也没有session 所有 会报一个短信验证码不存在的错误
因为我们的验证码是存在session里面的

所有app中我们不能用session去存储手机验证码

重构验证码存储逻辑

重构用户名密码登录获取token

@Autowired

@Autowired为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入。

@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。

验证码存储 ValidateCodeRepository

重构用户名密码登录获取token

ValidateCodeRepository

public interface ValidateCodeRepository  {       /**      * 保存验证码      * @param request      * @param validateCode      * @param validateCodeType      */     void save(ServletWebRequest request ,ValidateCode validateCode,ValidateCodeType validateCodeType);       /**      * 获取验证码      * @param request      * @param validateCodeType      * @return      */     ValidateCode get(ServletWebRequest request,ValidateCodeType validateCodeType);       /**      * 移除验证码      * @param request      * @param validateCodeType      * @return      */     void remove(ServletWebRequest request,ValidateCodeType validateCodeType); }  

RedisValidateCodeRepository

app端我们把验证码存到redis里面
重构用户名密码登录获取token

@Component public class RedisValidateCodeRepository implements ValidateCodeRepository {      @Autowired     private RedisTemplate<Object,Object> redisTemplate;      /**      * 保存验证码      *      * @param request      * @param validateCode      * @param validateCodeType      */     @Override     public void save(ServletWebRequest request, ValidateCode validateCode, ValidateCodeType validateCodeType) {         //存redis 30分钟超时时间         redisTemplate.opsForValue().set(buildKey(request,validateCodeType),validateCode,30,TimeUnit.MINUTES);     }      /**      * 获取验证码      * @param request      * @param validateCodeType      * @return      */     @Override     public ValidateCode get(ServletWebRequest request, ValidateCodeType validateCodeType) {         Object value = redisTemplate.opsForValue().get(buildKey(request, validateCodeType));         if(value==null){             return null;         }         return (ValidateCode) value;     }      /**      * 移除验证码      *      * @param request      * @param validateCodeType      * @return      */     @Override     public void remove(ServletWebRequest request, ValidateCodeType validateCodeType) {         redisTemplate.delete(buildKey(request,validateCodeType));     }      private String buildKey(ServletWebRequest request, ValidateCodeType validateCodeType) {         String deviceId = request.getHeader("deviceId");         if(StringUtils.isBlank(deviceId)){             throw new ValidateCodeException("请在请求头中携带deviceId参数");         }         return "code:"+validateCodeType.toString().toLowerCase()+":"+deviceId;      }      /**      * 根据请求的url获取校验码的类型      *      * @param request      * @return      */     private ValidateCodeType getValidateCodeType(ServletWebRequest request) {         String type = StringUtils.substringBefore(getClass().getSimpleName(), "CodeProcessor");         return ValidateCodeType.valueOf(type.toUpperCase());     } } 

SessionValidateCodeRepository

浏览器端还是存到session中国

重构用户名密码登录获取token

`@Component public class SessionValidateCodeRepository implements ValidateCodeRepository {       /**      * 操作session的工具类      */     private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();      /**      * 保存验证码      *      * @param request      * @param validateCode      * @param validateCodeType      */     @Override     public void save(ServletWebRequest request, ValidateCode validateCode, ValidateCodeType validateCodeType) {         ValidateCode code = new ValidateCode(validateCode.getCode(),validateCode.getExpireTime());         sessionStrategy.setAttribute(request, getSessionKey(request), code);     }      /**      * 获取验证码      *      * @param request      * @param validateCodeType      * @return      */     @Override     public ValidateCode get(ServletWebRequest request, ValidateCodeType validateCodeType) {          String sessionKey = getSessionKey(request);          ValidateCode codeInSession = (ValidateCode) sessionStrategy.getAttribute(request, sessionKey);          return codeInSession;     }      /**      * 移除验证码      *      * @param request      * @param validateCodeType      * @return      */     @Override     public void remove(ServletWebRequest request, ValidateCodeType validateCodeType) {         sessionStrategy.removeAttribute(request,getSessionKey(request));     }       /**      * 构建验证码放入session时的key      *      * @param request      * @return      */     private String getSessionKey(ServletWebRequest request) { //		return SESSION_KEY_PREFIX + getProcessorType(request);         return SESSION_KEY_PREFIX + getValidateCodeType(request).toString().toUpperCase();      }      /**      * 根据请求的url获取校验码的类型      *      * @param request      * @return      */     private ValidateCodeType getValidateCodeType(ServletWebRequest request) {         String type = StringUtils.substringBefore(getClass().getSimpleName(), "CodeProcessor");         return ValidateCodeType.valueOf(type.toUpperCase());      }    } 

`

AbstractValidateCodeProcessor 更换验证码存储接口

引入

	@Autowired 	private ValidateCodeRepository validateCodeRepository; 

来对应操作验证码

在依赖app的时候就会找到我们的RedisValidateCodeRepository 的bean

redis配置

## Redis服务器地址 spring.redis.host=192.168.85.134 ## Redis服务器连接端口 spring.redis.port=6379 ## Redis服务器连接密码(默认为空) spring.redis.password=123456 

测试

重构用户名密码登录获取token重构用户名密码登录获取token测试成功

本文转自互联网,侵权联系删除重构用户名密码登录获取token

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » 重构用户名密码登录获取token
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们