SpringBoot2.0 整合 Shiro+JWT+Redis 实现图形、短信验证码登陆

6 篇文章 0 订阅
4 篇文章 0 订阅

 

 这里使用到了Redis来实现JWT的过期刷新,话不多说,具体的实现代码如下

1.自定义AuthenticationToken类

public final class JwtToken implements AuthenticationToken {
	private static final long serialVersionUID = 1L;
	private String jwttoken;

	public JwtToken(String jwttoken) {
		super();
		this.jwttoken = jwttoken;
	}

	@Override
	public Object getCredentials() {
		return jwttoken;
	}

	@Override
	public Object getPrincipal() {
		return jwttoken;
	}
}

2.自定义一个JWT拦截器类

public class JWTFilter extends BasicHttpAuthenticationFilter {
	
	private Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	RedisUtil redisUtils;
	@Autowired
	private UserService userService;
	private AntPathMatcher pathMatcher = new AntPathMatcher();
	

	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
    	boolean isauth = 
    			Constant.URLS.stream()
    			.filter(x->!Objects.equals("/**",x))
    			.anyMatch(x->pathMatcher.matches(x,((HttpServletRequest)request).getRequestURI()));
        if (isauth || ((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())) {
            return true;
        }
		AuthenticationToken token = createToken(request,response);
		if (token.getCredentials() == null) {
			logger.info("未登录.....................");
			response(response,ResultUtil.resultCodes(ResponseEnum.OAUTH));
		}else{
			try {
				SecurityUtils.getSubject().login(token);
				return true;
			} catch (AuthenticationException e) {
				logger.error("AuthenticationException.....................",e);;
				if(e instanceof ExpiredCredentialsException){
				return refreshToken(request,response);
				}else response(response,ResultUtil.resultErr(e.getMessage()));
				e.printStackTrace();
			}
		}
		return false;
	} 
	
	
	/**
	 * 此处为AccessToken刷新,进行判断RefreshToken是否过期,未过期就返回新的AccessToken且继续正常访问
	 * @param servletRequest
	 * @param servletResponse
	 * @return
	 */
	private boolean refreshToken(ServletRequest request, ServletResponse response) {
		logger.info("刷新TOKEN...............................");
		HttpServletRequest request1 = (HttpServletRequest) request;
		HttpServletResponse response1 = (HttpServletResponse) response;
		String oldToken = getToken(request1);
		String uid = redisUtils.getUidByToken(oldToken,Constant.JWT_TOKEN);
		if (uid != null) {
				UserMsg userMsg = userService.findById(Integer.valueOf(uid));
				String newToken = JwtUtils.generateToken(userMsg);
				JwtToken jwtToken = new JwtToken(newToken);
				redisUtils.set(Constant.JWT_TOKEN+uid,newToken,Constant.MAX_EXPIRED);
				CookieUtil.addcookie(ImmutableMap.of("Authorization",newToken),request1,response1);
				SecurityUtils.getSubject().login(jwtToken);
				return true;
		}
		return false;
	}
	
	
	
	private String getToken(HttpServletRequest request){
		String token = request.getHeader("Authorization");
		if(token==null)token = CookieUtil.getcookie(request,"Authorization");
		return token;
	}

	/**
	 * 返回错误信息
	 * 
	 * @param response
	 * @param code
	 * @param msg
	 */
	@SuppressWarnings("deprecation")
	private void response(ServletResponse response,ResultUtil<?> resultUtil) {
		try {
			HttpServletResponse httpResponse = (HttpServletResponse) response;
			httpResponse.setStatus(HttpStatus.OK.value());
			response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
			httpResponse.getWriter().write(JSON.toJSONString(resultUtil));
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
	}

	
	/**
	 * 支持跨域
	 *
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@Override
	protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		HttpServletResponse httpServletResponse = (HttpServletResponse) response;
		httpServletResponse.setHeader("Access-control-Allow-Origin", "*");
		httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
		httpServletResponse.setHeader("Access-Control-Allow-Headers",
				"Authorization,Origin,X-Requested-With,Content-Type,Accept");
		// 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
		if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
			httpServletResponse.setStatus(HttpStatus.OK.value());
			return false;
		}
		return super.preHandle(httpServletRequest, httpServletResponse);
	}

	
	@Override
	protected AuthenticationToken createToken(ServletRequest arg0, ServletResponse arg1) {
		HttpServletRequest request = (HttpServletRequest) arg0;
		String token = getToken(request);
		return new JwtToken(token);
	}
}

3.自定义登陆验证策略

public class UserRealm extends AuthorizingRealm {

	@Autowired
	private UserService userService;

	@Autowired
	RedisUtil redisutils;

	@Override
	public boolean supports(AuthenticationToken token) {
		return true;
	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
		SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();
		UserMsg userMsg = (UserMsg) principal.getPrimaryPrincipal();
		Set<String> roles = Stream.of(userMsg.getIsadmin() == 1 ? "admin" : "user").collect(Collectors.toSet());
		Set<String> permissions = Stream
				.of(userMsg.getIsadmin() == 1 ? "select,delete,update,insert" : "select,update,insert")
				.flatMap(x -> Arrays.stream(x.split(","))).collect(Collectors.toSet());
		// 添加角色
		auth.setRoles(roles);
		// 添加权限
		auth.setStringPermissions(permissions);
		return auth;
	}
	
	public static void main(String[] args) {
		System.out.println(new Md5Hash("1230","450",3));
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		if (token instanceof JwtToken) {
			String jwttoken = (String) token.getPrincipal();
			String username = JwtUtils.getUsernameFromToken(jwttoken);
			if (username == null)throw new ExpiredCredentialsException();//token过期这里会尝试刷新token
			UserMsg usermsg = userService.findByName(username);
			System.out.println("usermsg "+usermsg.getPassword());
			String md5Hash = new Md5Hash(jwttoken,"jwttoken",5).toHex();
			return new SimpleAuthenticationInfo(usermsg,md5Hash,ByteSource.Util.bytes("jwttoken"),getName());
		}
		
		
		UsernamePasswordToken usernames = (UsernamePasswordToken) token;
		String username = usernames.getUsername();
		String password = new String(usernames.getPassword());
		System.out.println("Username "+username);
		System.out.println("password "+password);
		UserMsg usermsg = userService.findByName(username);
		System.out.println("usermsg" +usermsg);
		if (usermsg == null) {
			throw new UnknownAccountException();
		}
		if (redisutils.get(usermsg.getUsername()) != null) {
			Integer pass_count = Integer.valueOf(redisutils.get(usermsg.getUsername()));
			if (pass_count >= 5)throw new ExcessiveAttemptsException();
		}
		String md5Hash = new Md5Hash(password,usermsg.getSalt(),5).toHex();
		if (!Objects.equals(usermsg.getPassword(),md5Hash)) {
			//记录用户密码错误的次数
			if(redisutils.hasKey(usermsg.getUsername())){
				redisutils.incr(usermsg.getUsername(),1);
			}else redisutils.set(usermsg.getUsername(),"1",Constant.MAX_EXPIRED);
			throw new IncorrectCredentialsException();
		}
		return new SimpleAuthenticationInfo(usermsg,md5Hash,ByteSource.Util.bytes(usermsg.getSalt()),getName());
	}
}

4.定义Shiro配置类

@Configuration
public class ShiroConfig {
	
	/**
	 * 自定义jwt认证策略
	 * @return
	 */
//	@Bean("jwtRealm")
//    public JwtRealm jwtRealm(HashedCredentialsMatcher hashedCredentialsMatcher) {
//		JwtRealm myShiroRealm = new JwtRealm();
//        myShiroRealm.setCachingEnabled(true);
//        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
//        return myShiroRealm;
//    }
	
	/**
	 * 自定义用户登录认证策略
	 * @return
	 */
	@Bean("userRealm")
    public UserRealm userRealm(HashedCredentialsMatcher hashedCredentialsMatcher) {
		UserRealm myShiroRealm = new UserRealm();
        myShiroRealm.setCachingEnabled(true);
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return myShiroRealm;
    }

	/**
	 * 禁用Session
	 * @return
	 */
	@Bean("sessionManager")
    public DefaultSessionManager sessionManager() {
        DefaultSessionManager sessionManager = new DefaultSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(false);
        return sessionManager;
    }
 
	/**
	 * 禁用Session
	 * @return
	 */
    @Bean("defaultSessionStorageEvaluator")
    public DefaultSessionStorageEvaluator defaultSessionStorageEvaluator () {
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        return defaultSessionStorageEvaluator;
    }
    
    /**
     * MD5加密
     * @return
     */
    @Bean("hashedCredentialsMatcher")
	public HashedCredentialsMatcher hashedCredentialsMatcher() {
		HashedCredentialsMatcher hashed = new HashedCredentialsMatcher();
		hashed.setHashAlgorithmName("MD5");
		hashed.setHashIterations(5);
		return hashed;
    }
 
    @Bean("subjectDAO")
    public DefaultSubjectDAO subjectDAO(DefaultSessionStorageEvaluator defaultSessionStorageEvaluator) {
        DefaultSubjectDAO defaultSubjectDAO = new DefaultSubjectDAO();
        defaultSubjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        return defaultSubjectDAO;
    }
    
    @Bean
    public FilterRegistrationBean<Filter> delegatingFilterProxy(){
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<Filter>();
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName("shiroFilter");
        filterRegistrationBean.setFilter(proxy);
        return filterRegistrationBean;
    }
 
    @Bean("securityManager")
    public SecurityManager securityManager(
    		UserRealm userRealm,
    		DefaultSubjectDAO subjectDAO,
    		DefaultSessionManager sessionManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        securityManager.setSubjectDAO(subjectDAO);
        securityManager.setSessionManager(sessionManager);
        return securityManager;
    }
 
    @Bean("jwtFilter")
    public JWTFilter jwtFilter() {
        return new JWTFilter();
    }
    
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager,JWTFilter jwtFilter) {
    	ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        Map<String, Filter> filters = new HashMap<>();
        filters.put("authc",jwtFilter);
        shiroFilter.setFilters(filters);
        shiroFilter.setFilterChainDefinitionMap(Constant.URL_MAP);
        shiroFilter.setLoginUrl("/page/login_page");
        shiroFilter.setSuccessUrl("/page/index_page");
        shiroFilter.setUnauthorizedUrl("/page/err_page");
        return shiroFilter;
    }
    
    @Bean(name = "advisorAutoProxyCreator")
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
    
    @Bean("authorizationAttributeSourceAdvisor")
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

5.定义生成图形验证码和短信验证码的类

@Component
public class ValidatedUtil {
	
	private String SMS_Url = "http://gbk.api.smschinese.cn";
	private Random random = new Random();

	@Data
	@AllArgsConstructor
	@NoArgsConstructor
	@ToString
	public class ImageCode{
		private BufferedImage image;
	    private String code;
	    private LocalDateTime expireTime;
	    public ImageCode(BufferedImage image, String code, long expireIn) {
	        this.code = code;
	        this.image = image;
	        this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
	    }
	    public boolean isExpried() {
	        return LocalDateTime.now().isAfter(getExpireTime());
	    }
	}
	
	/**
	 * 生成验证码图片
	 * @return
	 */
	public ImageCode getImageCode(){
        BufferedImage image = new BufferedImage(Constants.width,Constants.height,BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        g.setColor(getRandColor(200,250));
        g.fillRect(0, 0, Constants.width,Constants.height);
        g.setColor(getRandColor(160,200));
        for (int i = 0; i < 155; i++) {
            int x = random.nextInt(Constants.width);
            int y = random.nextInt(Constants.height);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            g.drawLine(x, y, x + xl, y + yl);
        }
        g.setFont(new Font("黑体",Font.BOLD,30));
        FontMetrics fontMetrics = g.getFontMetrics();
        String sRand = random(Constants.length);
        for(int i = 0; i < sRand.length();i++){
        	String fonts = String.valueOf(sRand.charAt(i));
        	g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
        	int width = fontMetrics.stringWidth(fonts)*i+10,height=20;
        	g.rotate(Math.toRadians(random.nextInt(5)),width,height);
            g.drawString(fonts,width,height);
        }
        g.dispose();
        return new ImageCode(image,sRand,Constants.image_expire_second);
	}
	
	/**
     * 生成随机背景条纹
     * @param fc
     * @param bc
     * @return
     */
    private Color getRandColor(int fc, int bc) {
        Random random = new Random();
        if (fc > 255)fc = 255;
        if (bc > 255) bc = 255;
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }
    
    /**
     * 生成指定长度的英文字符
     * @param length
     * @return
     */
    private String random(int length){
    	length = length>26?26:length<1?5:length;
    	StringBuilder string = new StringBuilder();
    	String[] chars = IntStream.range(0,26)
    			.mapToObj(x->String.valueOf(((char)(97+x))))
    			.toArray(String[]::new);
        boolean[] nmber = new boolean[chars.length];
        do{
        	int ints = random.nextInt(chars.length);
        	if (nmber[ints] == false)string.append(chars[ints]);
        	nmber[ints] = true;
        }while(string.length()<length);
        return string.toString();
    }
    
    /**
     * 发送手机验证码
     * @param phone 接收验证码的手机号
     * @param length 验证码长度
     * @return
     */
    public SmsCode getSmsCode(String phone,int length){
    	String validatedCode = IntStream.range(0,length)
    	    	.map(x->random.nextInt(10))
    	    	.mapToObj(String::valueOf)
    	    	.collect(Collectors.joining());
			Map<String,String> map = new LinkedHashMap<>();
			map.put("Uid","你的ID");
			map.put("Key","你的Key");
			map.put("smsMob",phone);//发生的手机号
			map.put("smsText","你的验证码为 "+validatedCode+" 请勿提供他人使用");//发送的内容
			String message = (String)HttpUtil.request(SMS_Url,map,"POST");
			System.err.println("sendsms() "+message);
			return new SmsCode(phone, validatedCode, message);
    }
}

6.用于调用短信接口的方法

public static Object request(String url, Map<String, String> maps, String method) {
		try {
			isNull(url, maps, method);
			okhttp3.Request.Builder rbuilder = new Request.Builder().header("User-Agent",
					"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36");
			okhttp3.FormBody.Builder fbuilder = new FormBody.Builder(Charset.forName("GBK"));
			if (maps != null && maps.size() > 0)
				maps.forEach((a, b) -> fbuilder.add(a, b));
			Request requests = method.equalsIgnoreCase("get") ? rbuilder.get().url(url).build()
					: rbuilder.method(method, fbuilder.build()).url(url).build();
			Response response = OKHTTP.newCall(requests).execute();
			String type = response.header("content-type");
			return type.contains("application/json") ? JSON.parseObject(response.body().string())
					: response.body().string();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

7.定义JWT生成工具类

public abstract class JwtUtils {
	//private static final String secret = UUID.randomUUID().toString().replace("-","");
	private static final String secret = "abcdefg";
    private static final Long expiration = 60*10*1000L;//令牌过期时间10分钟
    /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private static String generateToken(Map<String, Object> claims) {
        Date expirationDate = new Date(System.currentTimeMillis() + expiration);
        return Jwts.builder()
        		.setClaims(claims)
        		.setExpiration(expirationDate)
        		.signWith(SignatureAlgorithm.HS512, secret)
        		.compact();
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    private static Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }
    
    public static String generateToken(UserMsg userMsg) {
        Map<String,Object> claims = new HashMap<>();
        claims.put("username",userMsg.getUsername());
        claims.put("uid",userMsg.getUid());
        claims.put("header",userMsg.getHeader());
        claims.put("lasttime",LocalDateTime.now());
        return generateToken(claims);
    }
    
    public static <T> T getUserByToken(String token,Class<T> classs) {
    	T user = null;
    	try {
    		Claims claims = getClaimsFromToken(token);
    		if(claims==null)return null;
    		user = classs.newInstance();
    		 for(Field field : classs.getDeclaredFields()){
    			String name = field.getName();
    			if(!claims.containsKey(name))continue;
    			field.setAccessible(true);
    			field.set(user,claims.get(name));
    		 }
		} catch (Exception e) {
			e.printStackTrace();
		}
        return user;
    }

    /**
     * 从令牌中获取用户名
     * @param token 令牌
     * @return 用户名
     */
    public static String getUsernameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username = claims.get("username",String.class);
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 判断令牌是否过期
     *
     * @param token 令牌
     * @return 是否过期
     */
    public static Boolean isTokenExpired(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            Date expiration = claims.getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 刷新令牌
     * @param token 原令牌
     * @return 新令牌
     */
    public static String refreshToken(String token) {
        String refreshedToken;
        try {
            Claims claims = getClaimsFromToken(token);
            claims.put(Claims.ISSUED_AT, new Date());
            refreshedToken = generateToken(claims);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }
}

上面的都准备好了接下来就开始编写接口方法了

1.定义用于获取图形验证码和发送短信验证码的Controller

@RestController
@RequestMapping("validate")
public class ValidateController extends BaseController {
	
	@Autowired
	RedisUtil redisutils;
	
	@Autowired
	ValidatedUtil validatedUtil;
	
//	@Autowired
//	SessionStrategy sessionStrategy;
	
	/**
	 * 获取短信验证码
	 * @param phone
	 * @return
	 */
	@ApiOperation("获取短信验证码")
	@RequestLimit
	@RequestMapping(value = "/sendSms", method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResultUtil<?> sendSms(@Validated(Reg.class) @ApiParam SmsCode phone){
		SmsCode smscode = validatedUtil.getSmsCode(phone.getPhone(),6);
		redisutils.set(phone.getPhone(),smscode.getCode(),60*10);
		String response = smscode.getMessage();
		if(response.matches("-?\\d+") && Integer.valueOf(response)>0)return ResultUtil.resultOK();
		return ResultUtil.resultErr(response);
	}
	
	/**
	 * 获取图形验证码
	 * @param request
	 * @param response
	 */
	@ApiOperation("获取图形验证码")
	@RequestMapping(value = "/imageCode", method = RequestMethod.POST)
	public void imageCode(@ApiParam HttpServletRequest request,@ApiParam HttpServletResponse response){
		try {
		ImageCode imagecode = validatedUtil.getImageCode();
		String token = UUID.randomUUID().toString().replace("-","");
		redisutils.set(token,imagecode.getCode(),60L);
		CookieUtil.addcookie(ImmutableMap.of(Constants.session_key,token), request, response);
		//sessionStrategy.setAttribute(new ServletWebRequest(request),Constants.session_key,imagecode);
		response.setContentType("image/jpeg");
		ImageIO.write(imagecode.getImage(),"JPEG",response.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

2.定义用户登陆Controller

@Api("用户Controller")
@RestController
//@RefreshScope
@RequestMapping("user")
@Validated
public class Usercontroller extends BaseController{

	@Value("${user.home}")
	private String home;

	@Value("${user.pass}")
	private String pass;
	
	@Autowired
	RedisUtil redisutils;
	
//	@Autowired
//	SessionStrategy sessionStrategy;

	@Autowired
	UserService userSerivce;

	/**
	 * 图形验证码登陆
	 * @param userMsg
	 * @param validated
	 * @param request
	 * @return
	 */
	@ApiOperation("图形验证码登陆接口")
	@RequestMapping(value = "/login",method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResultUtil<?> login(@Validated(Login.class) UserMsg userMsg,@NotEmpty(message="验证码为空") String validated,HttpServletRequest request,HttpServletResponse response) {
		UsernamePasswordToken passwordtoken = new UsernamePasswordToken(userMsg.getUsername(),userMsg.getPassword());
		Subject subjects = SecurityUtils.getSubject();
		subjects.login(passwordtoken);
		validate(validated,request);
		UserMsg usermsgs = (UserMsg)subjects.getPrincipal();
		String jwt_token = JwtUtils.generateToken(usermsgs);
		redisutils.set(Constant.JWT_TOKEN + usermsgs.getUid(), jwt_token, Constant.MAX_EXPIRED);
		CookieUtil.addcookie(ImmutableMap.of("Authorization",jwt_token),request,response);
		return ResultUtil.resultOK();
	}
	
	/**
	 * 注册接口
	 * @param userMsg
	 * @return
	 */
	@ApiOperation("注册接口")
	@RequestMapping(value = "/reg",method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResultUtil<?> reg(@Validated(Reg.class) UserMsg userMsg) {
		UserMsg user = userSerivce.findByName(userMsg.getUsername());
		if(user!=null)throw new RuntimeException("用户已存在");
		String salt = UUID.randomUUID().toString().replace("-","");
		String md5Hash = new Md5Hash(userMsg.getPassword(),salt,5).toHex();
		userMsg.setPassword(md5Hash);
		userMsg.setSalt(salt);
		UserMsg admin = userSerivce.findByAdmin();
		userMsg.setIsadmin(admin!=null?0:1);
		userMsg.setIsdelete(0);
		userSerivce.save(userMsg);
		return ResultUtil.resultOK();
	}
	
	/**
	 * 短信验证码登陆
	 * @param validated
	 * @param request
	 * @param response
	 * @return
	 */
	@ApiOperation("短信验证码登陆")
	@RequestMapping(value = "/smslogin",method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResultUtil<?> smslogin(@Validated(Login.class) SmsCode validated,HttpServletRequest request,HttpServletResponse response) {
		if(!redisutils.hasKey(validated.getPhone()))throw new RuntimeException("验证码已过期");
		if(!Objects.equals(validated.getCode(),redisutils.get(validated.getPhone())))throw new RuntimeException("验证码错误");
		UserMsg smsUser = new UserMsg();
		smsUser.setUsername("用户"+validated.getPhone());
		smsUser.setPhone(validated.getPhone());
		smsUser.setIsadmin(0);
		smsUser.setIsdelete(0);
		UserMsg userMsg = userSerivce.save(smsUser);
		String token = JwtUtils.generateToken(smsUser);
		redisutils.set(Constant.JWT_TOKEN+userMsg.getUid(),token,Constant.MAX_EXPIRED);
		CookieUtil.addcookie(ImmutableMap.of("Authorization",token),request,response);
		return ResultUtil.resultOK();
	}
	
	
	
	@RequestMapping(value = "/logout",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResultUtil<?> logout(HttpServletRequest request,HttpServletResponse response) {
		String token = request.getHeader("Authorization");
		if(token==null)token = CookieUtil.getcookie(request,"Authorization");
		if(token==null)return ResultUtil.resultCodes(ResponseEnum.LOGOUTERR);
		CookieUtil.addcookie(ImmutableMap.of("Authorization","del"),request,response);
		redisutils.delvalues(Constant.JWT_TOKEN,token);
		return ResultUtil.resultOK();
	}
	
	private void validate(String validated,HttpServletRequest request) {
		String image_token = CookieUtil.getcookie(request,Constants.session_key);
		if(!redisutils.hasKey(image_token))throw new RuntimeException("验证码不存在");
		if (!Objects.equals(redisutils.get(image_token),validated))throw new RuntimeException("验证码错误");
	}
	
	//@RequiresPermissions("user")
	@RequiresRoles(logical=Logical.OR,value={"user","admin"})
	@RequestMapping(value = "/userinfo",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResultUtil<?> getuserinfo(){
		return ResultUtil.resultOK(SecurityUtils.getSubject().getPrincipal());
	}
	
	@RequiresRoles("admin")
	@RequestMapping(value = "/getuser/{uid:\\d+}",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResultUtil<?> getUserId(@PathVariable("uid") Integer uid){
		return ResultUtil.resultOK(userSerivce.findById(uid));
	}
	
	@RequiresRoles("admin")
	@RequestMapping(value = "/username/{name}",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResultUtil<?> getUsername(@PathVariable("name") String name){
		return ResultUtil.resultOK(userSerivce.findByName(name));
	}
}

3.统一异常处理中心

@ControllerAdvice
public abstract class BaseController implements ResponseBodyAdvice<Object> {
	
	@ExceptionHandler(RuntimeException.class)
	public ResultUtil<?> runtime(RuntimeException exception) {
		return ResultUtil.resultErr(exception.getMessage());
	}
	
	@ExceptionHandler(AuthenticationException.class)
	public ResultUtil<?> shiroException(AuthenticationException e) {
		if(e instanceof UnknownAccountException){
			 return ResultUtil.resultErr("用户不存在");
		}else if(e instanceof IncorrectCredentialsException){
			 return ResultUtil.resultErr("密码错误");
		}else if(e instanceof ExcessiveAttemptsException){
			 return ResultUtil.resultErr("认证次数超过限制,请稍后重试");
		}
		return ResultUtil.resultErr();
	}

	@ExceptionHandler(BindException.class)
	public ResultUtil<?> bind(BindException exception) {
		System.out.println("BindException.class");
//		String message = exception.getAllErrors().stream().filter(x -> x instanceof FieldError)
//				.map(x -> ((FieldError) x).getDefaultMessage()).reduce((x, y) -> x + y).get();
		return ResultUtil.resultErr(exception.getFieldError().getDefaultMessage());
	}

	@ExceptionHandler(ValidationException.class)
	public ResultUtil<?> validation(ValidationException exception) {
		return ResultUtil.resultErr(exception.getMessage());
	}

	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(MethodArgumentNotValidException.class)
	public ResultUtil<?> exceptionHandler(MethodArgumentNotValidException exception) {
		BindingResult binding = exception.getBindingResult();
		return ResultUtil.resultErr(binding.getFieldError().getDefaultMessage());
	}

	@Override
	public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
		return true;
	}

	@Override
	public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType,
			Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest,
			ServerHttpResponse serverHttpResponse) {
		ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) serverHttpRequest;
		ServletServerHttpResponse serverResponse = (ServletServerHttpResponse) serverHttpResponse;
		if (serverRequest == null || serverResponse == null || serverRequest.getServletRequest() == null
				|| serverResponse.getServletResponse() == null) {
			return o;
		}
		HttpServletRequest request = serverRequest.getServletRequest();
		HttpServletResponse response = serverResponse.getServletResponse();
		String originHeader = "Access-Control-Allow-Origin";
		if (!response.containsHeader(originHeader)) {
			String origin = request.getHeader("Origin");
			if (origin == null) {
				String referer = request.getHeader("Referer");
				if (referer != null)
					origin = referer.substring(0, referer.indexOf("/", 7));
			}
			response.setHeader("Access-Control-Allow-Origin", origin);
		}
		String allowHeaders = "Access-Control-Allow-Headers";
		if (!response.containsHeader(allowHeaders))
			response.setHeader(allowHeaders, request.getHeader(allowHeaders));
		String allowMethods = "Access-Control-Allow-Methods";
		if (!response.containsHeader(allowMethods))
			response.setHeader(allowMethods, "GET,POST,OPTIONS,HEAD");
		String exposeHeaders = "access-control-expose-headers";
		if (!response.containsHeader(exposeHeaders))
			response.setHeader(exposeHeaders, "x-auth-token");
		return o;
	}
}

最后贴上用到的maven依赖包

        <!-- shiro -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.8.0</version>
		</dependency>
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.9.0</version>
		</dependency>
		<!-- jsonwebtoken -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt</artifactId>
			<version>0.9.0</version>
		</dependency>

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

		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.4.0</version>
		</dependency>

		<dependency>
			<groupId>com.squareup.okhttp3</groupId>
			<artifactId>okhttp</artifactId>
			<version>4.9.0</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-web</artifactId>
			<version>1.1.4.RELEASE</version>
		</dependency>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值